-
Notifications
You must be signed in to change notification settings - Fork 0
feat: implement token refresh scheduler and enhance Google OAuth hand… #48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -23,10 +23,24 @@ googleAuth.get('/callback', async(req: Request, res: Response)=>{ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { tokens } = await oauth2.getToken(code); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // DEBUG: Log tokens received from Google | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('\n🔐 Google OAuth Callback - Tokens received:'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(' access_token:', tokens.access_token ? '✅ Present' : '❌ Missing'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(' refresh_token:', tokens.refresh_token ? '✅ Present' : '❌ Missing'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(' expiry_date:', tokens.expiry_date); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(' token_type:', tokens.token_type); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(' scope:', tokens.scope); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!tokens.refresh_token) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.warn('⚠️ WARNING: No refresh_token received! User may have already authorized this app.'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.warn(' To force new refresh_token, user needs to revoke access at: https://myaccount.google.com/permissions'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+26
to
+37
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove or sanitize debug logging in production. The debug logging exposes detailed OAuth token information to console logs. In production environments, this could leak sensitive data to log aggregation systems. Consider:
🔎 Suggested approach with environment-based logging+ const isDebug = process.env.NODE_ENV === 'development';
+
- // DEBUG: Log tokens received from Google
- console.log('\n🔐 Google OAuth Callback - Tokens received:');
- console.log(' access_token:', tokens.access_token ? '✅ Present' : '❌ Missing');
- console.log(' refresh_token:', tokens.refresh_token ? '✅ Present' : '❌ Missing');
- console.log(' expiry_date:', tokens.expiry_date);
- console.log(' token_type:', tokens.token_type);
- console.log(' scope:', tokens.scope);
+ if (isDebug) {
+ console.log('\n🔐 Google OAuth Callback - Tokens received:');
+ console.log(' access_token:', tokens.access_token ? '✅ Present' : '❌ Missing');
+ console.log(' refresh_token:', tokens.refresh_token ? '✅ Present' : '❌ Missing');
+ console.log(' expiry_date:', tokens.expiry_date);
+ }
if (!tokens.refresh_token) {
- console.warn('⚠️ WARNING: No refresh_token received! User may have already authorized this app.');
- console.warn(' To force new refresh_token, user needs to revoke access at: https://myaccount.google.com/permissions');
+ if (isDebug) {
+ console.warn('⚠️ WARNING: No refresh_token received!');
+ }
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Save tokens to database if userId (state) is provided | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (state && typeof state === 'string') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(' Saving tokens for userId:', state); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await Oauth.saveCredentials(state, tokens as OAuthTokens) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(' ✅ Tokens saved to database'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Redirect to success page | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -38,5 +52,42 @@ googleAuth.get('/callback', async(req: Request, res: Response)=>{ | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| `http://localhost:3000/workflow?google=error&msg=${encodeURIComponent(err?.message ?? 'Token exchange failed')}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Debug endpoint to check stored credentials | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| googleAuth.get('/debug/credentials', async(req: Request, res: Response)=>{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { prismaClient } = await import('@repo/db/client'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const credentials = await prismaClient.credential.findMany({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| where: { type: 'google_oauth' }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| select: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userId: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| config: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const debugInfo = credentials.map(cred => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const config = cred.config as any; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: cred.id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userId: cred.userId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hasAccessToken: !!config?.access_token, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| hasRefreshToken: !!config?.refresh_token, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| refreshTokenLength: config?.refresh_token?.length || 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expiryDate: config?.expiry_date, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expiresIn: config?.expiry_date ? Math.round((config.expiry_date - Date.now()) / 1000 / 60) + ' minutes' : 'N/A', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isInvalid: config?.invalid || false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scope: config?.scope | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('\n📋 Stored Credentials Debug:'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.table(debugInfo); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.json({ credentials: debugInfo }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (err) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(500).json({ error: err instanceof Error ? err.message : 'Unknown error' }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+56
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CRITICAL: Debug endpoint exposes credentials without authentication. The 🔎 Required fix: Add authentication and restrict access-// Debug endpoint to check stored credentials
-googleAuth.get('/debug/credentials', async(req: Request, res: Response)=>{
+// Debug endpoint to check stored credentials (protected)
+googleAuth.get('/debug/credentials', userMiddleware, async(req: AuthRequest, res: Response)=>{
try {
+ // Only allow in development or for admin users
+ if (process.env.NODE_ENV === 'production') {
+ return res.status(403).json({ error: 'Debug endpoints disabled in production' });
+ }
+
+ if (!req.user) {
+ return res.status(401).json({ error: 'Authentication required' });
+ }
+
const { prismaClient } = await import('@repo/db/client');
const credentials = await prismaClient.credential.findMany({
- where: { type: 'google_oauth' },
+ where: {
+ type: 'google_oauth',
+ userId: req.user.id // Only show user's own credentials
+ },
select: {
id: true,
userId: true,
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -10,6 +10,8 @@ import { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TriggerSchema, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WorkflowSchema, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NodeSchema, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NodeUpdateSchema, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TriggerUpdateSchema, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } from "@repo/common/zod"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { GoogleSheetsNodeExecutor } from "@repo/nodes"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const router: Router = Router(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -336,6 +338,7 @@ router.get('/empty/workflow', userMiddleware, async(req:AuthRequest, res: Respon | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| router.get("/workflow/:workflowId", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userMiddleware, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async (req: AuthRequest, res: Response) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -437,7 +440,7 @@ router.post('/create/node', userMiddleware, async(req: AuthRequest, res: Respons | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const data = req.body; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(data," from http-backeden" ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // console.log(data," from http-backeden" ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const dataSafe = NodeSchema.safeParse(data) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(!dataSafe.success) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -469,6 +472,79 @@ router.post('/create/node', userMiddleware, async(req: AuthRequest, res: Respons | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ------------------------- UPDATE NODES AND TRIGGES --------------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| router.put('/update/node', userMiddleware, async(req: AuthRequest, res: Response)=>{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(!req.user){ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(statusCodes.BAD_REQUEST).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "User is not logged in ", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const data = req.body; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const dataSafe = NodeUpdateSchema.safeParse(data) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(!dataSafe.success) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(statusCodes.BAD_REQUEST).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Invalid input" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const updateNode = await prismaClient.node.update({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| where: {id: dataSafe.data.NodeId}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data:{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| config: dataSafe.data.Config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(updateNode) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(statusCodes.CREATED).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Node updated", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data: updateNode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }catch(e){ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("This is the error from Node updating", e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(statusCodes.INTERNAL_SERVER_ERROR).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Internal server Error from Node Updation.", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+477
to
+512
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use HTTP 200 instead of 201 for update operations. The endpoint returns 🔎 Proposed fix if(updateNode)
- return res.status(statusCodes.CREATED).json({
+ return res.status(statusCodes.OK).json({
message: "Node updated",
data: updateNode
})📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| router.put('/update/trigger', userMiddleware, async(req: AuthRequest, res: Response)=>{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(!req.user){ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(statusCodes.BAD_REQUEST).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "User is not logged in ", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const data = req.body; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const dataSafe = TriggerUpdateSchema.safeParse(data) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(!dataSafe.success) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(statusCodes.BAD_REQUEST).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Invalid input" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const updatedTrigger = await prismaClient.trigger.update({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| where:{id: dataSafe.data.TriggerId}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data:{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| config: dataSafe.data.Config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if(updatedTrigger) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(statusCodes.CREATED).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Trigger updated", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data: updatedTrigger | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }catch(e){ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log("This is the error from Trigger updating", e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return res.status(statusCodes.INTERNAL_SERVER_ERROR).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| message: "Internal server Error from Trigger Updation", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+514
to
+547
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use HTTP 200 instead of 201 for update operations. Similar to the node update endpoint, this trigger update endpoint returns 🔎 Proposed fix if(updatedTrigger)
- return res.status(statusCodes.CREATED).json({
+ return res.status(statusCodes.OK).json({
message: "Trigger updated",
data: updatedTrigger
})📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ----------------------- GET WORKFLOW DATA(NODES, TRIGGER)--------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,68 @@ | ||||||||||
| import { tokenRefreshService } from "../services/token-refresh.service.js"; | ||||||||||
|
|
||||||||||
| class TokenScheduler { | ||||||||||
| private intervalId: NodeJS.Timeout | null = null; | ||||||||||
| private intervalMinutes: number; | ||||||||||
|
|
||||||||||
| constructor(intervalMinutes: number = 60) { | ||||||||||
| this.intervalMinutes = intervalMinutes; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * Start the token refresh scheduler | ||||||||||
| */ | ||||||||||
| start(): void { | ||||||||||
| console.log(`\n🚀 Token Refresh Scheduler started`); | ||||||||||
| console.log(` Interval: Every ${this.intervalMinutes} minutes`); | ||||||||||
| console.log(` Next run: Immediately + every ${this.intervalMinutes} min\n`); | ||||||||||
|
|
||||||||||
| // Run immediately on start | ||||||||||
| this.runRefreshJob(); | ||||||||||
|
|
||||||||||
| // Then run at specified interval | ||||||||||
| const intervalMs = this.intervalMinutes * 60 * 1000; | ||||||||||
| this.intervalId = setInterval(() => { | ||||||||||
| this.runRefreshJob(); | ||||||||||
| }, intervalMs); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * Stop the scheduler | ||||||||||
| */ | ||||||||||
| stop(): void { | ||||||||||
| if (this.intervalId) { | ||||||||||
| clearInterval(this.intervalId); | ||||||||||
| this.intervalId = null; | ||||||||||
| console.log('🛑 Token Refresh Scheduler stopped'); | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * Run the refresh job | ||||||||||
| */ | ||||||||||
| private async runRefreshJob(): Promise<void> { | ||||||||||
| try { | ||||||||||
| const timestamp = new Date().toISOString(); | ||||||||||
| console.log(`\n⏱️ [${timestamp}] Running scheduled token refresh...`); | ||||||||||
|
|
||||||||||
| await tokenRefreshService.refreshAllExpiringTokens(); | ||||||||||
|
|
||||||||||
| } catch (error) { | ||||||||||
| console.error('❌ Scheduled token refresh failed:', error); | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * Manually trigger a refresh (useful for testing or on-demand refresh) | ||||||||||
| */ | ||||||||||
| async triggerManualRefresh(): Promise<void> { | ||||||||||
| console.log('\n🔧 Manual token refresh triggered...'); | ||||||||||
| await this.runRefreshJob(); | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // Default scheduler instance - runs every 30 minutes | ||||||||||
| export const tokenScheduler = new TokenScheduler(60); | ||||||||||
|
Comment on lines
+64
to
+65
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inconsistent comment: says 30 minutes, code uses 60. The comment states "runs every 30 minutes" but the constructor argument is 🔎 Proposed fix-// Default scheduler instance - runs every 30 minutes
+// Default scheduler instance - runs every 60 minutes
export const tokenScheduler = new TokenScheduler(60);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
|
|
||||||||||
| // Export class for custom configurations | ||||||||||
| export { TokenScheduler }; | ||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling and graceful shutdown for the token scheduler.
The scheduler starts without error handling, and there's no cleanup on server shutdown. If the scheduler fails to start, the server continues anyway, potentially leaving tokens unrefreshed. Additionally, without graceful shutdown, the scheduler may continue running after the server stops.
🔎 Recommended improvements
async function startServer() { await NodeRegistry.registerAll() - tokenScheduler.start(); + try { + tokenScheduler.start(); + console.log('✅ Token scheduler started'); + } catch (error) { + console.error('❌ Failed to start token scheduler:', error); + // Decide: should this be fatal? For now, log and continue + } + app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); }) + + // Graceful shutdown + process.on('SIGTERM', () => { + console.log('SIGTERM received, shutting down gracefully'); + tokenScheduler.stop(); + process.exit(0); + }); + + process.on('SIGINT', () => { + console.log('SIGINT received, shutting down gracefully'); + tokenScheduler.stop(); + process.exit(0); + }); }📝 Committable suggestion
🤖 Prompt for AI Agents