From 9eb0c209084b849109b92ac9e0b8717ff4332e26 Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Mon, 18 May 2026 15:30:38 +0530 Subject: [PATCH 01/24] feat: setup consumer server --- apps/consumer/package.json | 13 +++++++++++++ package-lock.json | 8 ++++++++ 2 files changed, 21 insertions(+) create mode 100644 apps/consumer/package.json diff --git a/apps/consumer/package.json b/apps/consumer/package.json new file mode 100644 index 00000000..d05f8cee --- /dev/null +++ b/apps/consumer/package.json @@ -0,0 +1,13 @@ +{ + "name": "consumer", + "version": "1.0.0", + "description": "", + "main": "src/app.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs" +} diff --git a/package-lock.json b/package-lock.json index 5219135a..6afc350d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,10 @@ "lint-staged": "^17.0.5" } }, + "apps/consumer": { + "version": "1.0.0", + "license": "ISC" + }, "apps/dashboard-api": { "version": "0.10.0", "license": "AGPL-3.0-only", @@ -6583,6 +6587,10 @@ "node": "^14.18.0 || >=16.10.0" } }, + "node_modules/consumer": { + "resolved": "apps/consumer", + "link": true + }, "node_modules/content-disposition": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", From 045117e32229a2efae493506ed48cd1b211c014b Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Mon, 18 May 2026 21:45:43 +0530 Subject: [PATCH 02/24] feat: configure Express server with CORS, CSRF, rate limiting, and graceful shutdown --- apps/consumer/package.json | 4 +- apps/consumer/src/app.js | 174 +++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 apps/consumer/src/app.js diff --git a/apps/consumer/package.json b/apps/consumer/package.json index d05f8cee..e37987e3 100644 --- a/apps/consumer/package.json +++ b/apps/consumer/package.json @@ -4,7 +4,9 @@ "description": "", "main": "src/app.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "dev": "node src/app.js", + "start": "node src/app.js", + "test": "jest --testPathPatterns=src/" }, "keywords": [], "author": "", diff --git a/apps/consumer/src/app.js b/apps/consumer/src/app.js new file mode 100644 index 00000000..94f92489 --- /dev/null +++ b/apps/consumer/src/app.js @@ -0,0 +1,174 @@ +const dotenv = require('dotenv'); +const path = require('path'); +dotenv.config({ path: path.join(__dirname, '../../../.env') }); + +const { validateEnv } = require('@urbackend/common'); + +if (process.env.NODE_ENV !== 'test') { + validateEnv(); +} + +const express = require('express') +const mongoose = require('mongoose') +const cors = require('cors') +const cookieParser = require('cookie-parser'); +const csurf = require('csurf'); +const rateLimit = require('express-rate-limit'); + + +const app = express(); +app.set('trust proxy', 1); + +const dashboardLimiter = rateLimit({ + windowMs: 15 * 60 * 1000, + max: 1000, + message: { error: "Dashboard usage limit exceeded. Slow down!" }, + skip: (req) => process.env.NODE_ENV === 'development', +}); + +const whitelist = (function() { + // Default allowed origins + const allowed = [process.env.FRONTEND_URL]; + + // Support comma-separated list of origins in .env + if (process.env.ALLOWED_ORIGINS) { + const extraOrigins = process.env.ALLOWED_ORIGINS.split(',').map(o => o.trim()); + allowed.push(...extraOrigins); + } + + if (process.env.NODE_ENV === 'development') { + allowed.push('http://localhost:5173'); + allowed.push('http://localhost:3000'); + } + + // Filter out duplicates and empty values + const uniqueAllowed = [...new Set(allowed.filter(Boolean))]; + + return { + get: () => uniqueAllowed + }; +})() + +app.use(cors({ + origin: whitelist.get(), + credentials: true, +})); + +app.use(express.json({ + verify: (req, res, buf) => { + req.rawBody = buf.toString(); + } +})); +app.use(express.urlencoded({ extended: true })); + +app.use(cookieParser()); + +const csrfProtection = csurf({ + cookie: { + httpOnly: true, + secure: process.env.NODE_ENV === 'production', + sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax' + } +}); + +app.use((req, res, next) => { + // Exclude Razorpay webhook from CSRF protection since it's an external POST request + if (req.path === '/api/billing/webhook') { + return next(); + } + csrfProtection(req, res, next); +}); + + +if (process.env.NODE_ENV !== 'test') { + // do test specific stuff +} + +app.get('/api/server-ip', async (req, res) => { + const ip = await getPublicIp(); + res.json({ ip }); +}); + +app.get('/', (req, res) => { + res.status(200).json({ status: "success", message: "urBackend API is running 🚀" }) +}); + +app.use((err, req, res, next) => { + // CSRF Error Handling + if (err.code === 'EBADCSRFTOKEN') { + return res.status(403).json({ + success: false, + error: "Invalid CSRF token", + message: "The form has expired or the CSRF token is invalid. Please refresh the page and try again." + }); + } + + if (err instanceof SyntaxError && err.status === 400 && 'body' in err) { + return res.status(400).json({ + success: false, + error: "Invalid JSON format", + message: "Check your request body syntax. Stray characters outside the JSON object are not allowed." + }); + } + + const statusCode = err.statusCode || 500; + const message = err.message || "Something went wrong!"; + + // Only log actual server errors (500), not expected operational errors (4xx) + if (statusCode >= 500) { + console.error("🔥 Server Error:", err.stack); + } + + res.status(statusCode).json({ + success: false, + error: statusCode >= 500 ? "Internal Server Error" : message, + message: message + }); +}); + +app.use((req, res) => { + const id = res.get("X-Kiroo-Replay-ID"); + res.json({error: "Not Found", replayId: id}) +}) +if (process.env.NODE_ENV !== 'test') { + + const PORT = process.env.PORT || 1234; + + const { connectDB } = require('@urbackend/common'); + + // Start DB & Server + connectDB(); + + const server = app.listen(PORT, () => { + console.log(`Server running on port ${PORT}`); + }); + + // SHUTDOWN + const gracefulShutdown = async () => { + console.log('🛑 SIGTERM/SIGINT received. Shutting down gracefully...'); + + server.close(async () => { + console.log('✅ HTTP server closed.'); + try { + await mongoose.connection.close(false); + console.log('✅ MongoDB connection closed.'); + process.exit(0); + } catch (err) { + console.error('❌ Error closing MongoDB connection:', err); + process.exit(1); + } + }); + + // Force close after 10s + setTimeout(() => { + console.error('Force shutting down...'); + process.exit(1); + }, 10000); + }; + + process.on('SIGTERM', gracefulShutdown); + process.on('SIGINT', gracefulShutdown); +} + +// Export for Testing +module.exports = app; \ No newline at end of file From 20d9e7dee0834c78f9542de0594ef37b6c2ebe3d Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Mon, 18 May 2026 22:02:29 +0530 Subject: [PATCH 03/24] refractor: reuse existing auth middleware --- .../src/middlewares/authMiddleware.js | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 apps/consumer/src/middlewares/authMiddleware.js diff --git a/apps/consumer/src/middlewares/authMiddleware.js b/apps/consumer/src/middlewares/authMiddleware.js new file mode 100644 index 00000000..424740bd --- /dev/null +++ b/apps/consumer/src/middlewares/authMiddleware.js @@ -0,0 +1,39 @@ +const jwt = require('jsonwebtoken'); + +module.exports = function (req, res, next) { + // Check for token in cookies (Primary for Web) + let token = req.cookies && req.cookies.accessToken; + + // Fallback to Authorization header (For CLI/API) + if (!token) { + const authHeader = req.header('Authorization'); + if (authHeader) { + const parts = authHeader.trim().split(/\s+/); + if (parts.length === 2 && parts[0].toLowerCase() === 'bearer') { + token = parts[1]; + } + } + } + + // Check if any token was provided + if (!token) { + return res.status(401).json({ error: 'Access Denied: No Token Provided' }); + } + + try { + // Verify the token using the secret key + const verified = jwt.verify(token, process.env.JWT_SECRET); + + + // Attach decoded token data to request object + req.user = verified; + + // Proceed to the next middleware or route handler + next(); + } catch (err) { + console.log("err---------------2") + console.error(err); + + res.status(400).json({ error: 'Invalid Token' }); + } +}; From 282ac4461b1c29d56e9db8fde0cb945d11d12e4e Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Mon, 18 May 2026 23:00:25 +0530 Subject: [PATCH 04/24] feat: implement handler in project controller --- .../src/controllers/project.controller.js | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 apps/consumer/src/controllers/project.controller.js diff --git a/apps/consumer/src/controllers/project.controller.js b/apps/consumer/src/controllers/project.controller.js new file mode 100644 index 00000000..d4ee8ac6 --- /dev/null +++ b/apps/consumer/src/controllers/project.controller.js @@ -0,0 +1,26 @@ +const { AppError } = require('@urbackend/common'); +const { Developer } = require('@urbackend/common'); + +module.exports.dbExportHandler = async (req, res, next) => { + try { + const { projectId } = req.params; + const { _id: userId } = req.user; + + const developer = await Developer.findById(userId).select('email').lean(); + if (!developer) { + return next(new AppError(404, "Authenticated developer not found.")); + } + const { email } = developer; + + console.log(`[Consumer API] Received export request for project ${projectId} from user ${userId} (${email})`); + + // just acknowledging the request, for now + return res.status(202).json({ + message: `Export request for project ${projectId} received by consumer. Processing will begin shortly.`, + }); + + } catch (err) { + console.error(`[Consumer API] Error handling export request for project ${req.params.projectId}:`, err); + return next(new AppError(500, err.message || "Failed to initiate database export.")); + } +}; From 13bd9e58ec22f2b5dfab01ea939df2ef8bb35318 Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Mon, 18 May 2026 23:02:45 +0530 Subject: [PATCH 05/24] feat: create project route and add db export endpoint --- apps/consumer/src/routes/project.routes.js | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 apps/consumer/src/routes/project.routes.js diff --git a/apps/consumer/src/routes/project.routes.js b/apps/consumer/src/routes/project.routes.js new file mode 100644 index 00000000..1c6287e2 --- /dev/null +++ b/apps/consumer/src/routes/project.routes.js @@ -0,0 +1,9 @@ +const express = require('express'); +const router = express.Router(); +const projectController = require('../controllers/project.controller'); +const authMiddleware = require('../middlewares/authMiddleware'); + +// POST /api/projects/:projectId/export +router.post('/:projectId/export', authMiddleware, projectController.dbExportHandler); + +module.exports = router; From 4e9cbc27c8602ad79b65fd1462c7cfd8c7a9abf2 Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Mon, 18 May 2026 23:05:35 +0530 Subject: [PATCH 06/24] feat: add project route to express app --- apps/consumer/src/app.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/consumer/src/app.js b/apps/consumer/src/app.js index 94f92489..fe0969e9 100644 --- a/apps/consumer/src/app.js +++ b/apps/consumer/src/app.js @@ -16,6 +16,7 @@ const csurf = require('csurf'); const rateLimit = require('express-rate-limit'); +const projectRoutes = require('./routes/project.routes'); const app = express(); app.set('trust proxy', 1); @@ -93,6 +94,9 @@ app.get('/', (req, res) => { res.status(200).json({ status: "success", message: "urBackend API is running 🚀" }) }); +// Mount project routes +app.use('/api/projects', projectRoutes); + app.use((err, req, res, next) => { // CSRF Error Handling if (err.code === 'EBADCSRFTOKEN') { From 30bf4c4145b4e8d59972c357272cb13ec14690c0 Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Mon, 18 May 2026 23:20:57 +0530 Subject: [PATCH 07/24] feat: add BullMQ queue for db export jobs --- packages/common/src/queues/exportQueue.js | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 packages/common/src/queues/exportQueue.js diff --git a/packages/common/src/queues/exportQueue.js b/packages/common/src/queues/exportQueue.js new file mode 100644 index 00000000..20b489dc --- /dev/null +++ b/packages/common/src/queues/exportQueue.js @@ -0,0 +1,6 @@ +const { Queue } = require('bullmq'); +const connection = require('../config/redis'); + +const exportQueue = new Queue('export-queue', { connection }); + +module.exports = { exportQueue }; \ No newline at end of file From c2e37a486a277cc03c516ac14f08c968eaf5720b Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Tue, 19 May 2026 08:17:29 +0530 Subject: [PATCH 08/24] refactor: move db export job creation to dashboard API convert consumer server into dedicated BullMQ worker service --- apps/consumer/src/app.js | 178 ------------------ .../src/middlewares/authMiddleware.js | 39 ---- .../src/controllers/dbExport.controller.js} | 0 .../src/routes/dbExport.routes.js} | 2 +- 4 files changed, 1 insertion(+), 218 deletions(-) delete mode 100644 apps/consumer/src/middlewares/authMiddleware.js rename apps/{consumer/src/controllers/project.controller.js => dashboard-api/src/controllers/dbExport.controller.js} (100%) rename apps/{consumer/src/routes/project.routes.js => dashboard-api/src/routes/dbExport.routes.js} (79%) diff --git a/apps/consumer/src/app.js b/apps/consumer/src/app.js index fe0969e9..e69de29b 100644 --- a/apps/consumer/src/app.js +++ b/apps/consumer/src/app.js @@ -1,178 +0,0 @@ -const dotenv = require('dotenv'); -const path = require('path'); -dotenv.config({ path: path.join(__dirname, '../../../.env') }); - -const { validateEnv } = require('@urbackend/common'); - -if (process.env.NODE_ENV !== 'test') { - validateEnv(); -} - -const express = require('express') -const mongoose = require('mongoose') -const cors = require('cors') -const cookieParser = require('cookie-parser'); -const csurf = require('csurf'); -const rateLimit = require('express-rate-limit'); - - -const projectRoutes = require('./routes/project.routes'); -const app = express(); -app.set('trust proxy', 1); - -const dashboardLimiter = rateLimit({ - windowMs: 15 * 60 * 1000, - max: 1000, - message: { error: "Dashboard usage limit exceeded. Slow down!" }, - skip: (req) => process.env.NODE_ENV === 'development', -}); - -const whitelist = (function() { - // Default allowed origins - const allowed = [process.env.FRONTEND_URL]; - - // Support comma-separated list of origins in .env - if (process.env.ALLOWED_ORIGINS) { - const extraOrigins = process.env.ALLOWED_ORIGINS.split(',').map(o => o.trim()); - allowed.push(...extraOrigins); - } - - if (process.env.NODE_ENV === 'development') { - allowed.push('http://localhost:5173'); - allowed.push('http://localhost:3000'); - } - - // Filter out duplicates and empty values - const uniqueAllowed = [...new Set(allowed.filter(Boolean))]; - - return { - get: () => uniqueAllowed - }; -})() - -app.use(cors({ - origin: whitelist.get(), - credentials: true, -})); - -app.use(express.json({ - verify: (req, res, buf) => { - req.rawBody = buf.toString(); - } -})); -app.use(express.urlencoded({ extended: true })); - -app.use(cookieParser()); - -const csrfProtection = csurf({ - cookie: { - httpOnly: true, - secure: process.env.NODE_ENV === 'production', - sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax' - } -}); - -app.use((req, res, next) => { - // Exclude Razorpay webhook from CSRF protection since it's an external POST request - if (req.path === '/api/billing/webhook') { - return next(); - } - csrfProtection(req, res, next); -}); - - -if (process.env.NODE_ENV !== 'test') { - // do test specific stuff -} - -app.get('/api/server-ip', async (req, res) => { - const ip = await getPublicIp(); - res.json({ ip }); -}); - -app.get('/', (req, res) => { - res.status(200).json({ status: "success", message: "urBackend API is running 🚀" }) -}); - -// Mount project routes -app.use('/api/projects', projectRoutes); - -app.use((err, req, res, next) => { - // CSRF Error Handling - if (err.code === 'EBADCSRFTOKEN') { - return res.status(403).json({ - success: false, - error: "Invalid CSRF token", - message: "The form has expired or the CSRF token is invalid. Please refresh the page and try again." - }); - } - - if (err instanceof SyntaxError && err.status === 400 && 'body' in err) { - return res.status(400).json({ - success: false, - error: "Invalid JSON format", - message: "Check your request body syntax. Stray characters outside the JSON object are not allowed." - }); - } - - const statusCode = err.statusCode || 500; - const message = err.message || "Something went wrong!"; - - // Only log actual server errors (500), not expected operational errors (4xx) - if (statusCode >= 500) { - console.error("🔥 Server Error:", err.stack); - } - - res.status(statusCode).json({ - success: false, - error: statusCode >= 500 ? "Internal Server Error" : message, - message: message - }); -}); - -app.use((req, res) => { - const id = res.get("X-Kiroo-Replay-ID"); - res.json({error: "Not Found", replayId: id}) -}) -if (process.env.NODE_ENV !== 'test') { - - const PORT = process.env.PORT || 1234; - - const { connectDB } = require('@urbackend/common'); - - // Start DB & Server - connectDB(); - - const server = app.listen(PORT, () => { - console.log(`Server running on port ${PORT}`); - }); - - // SHUTDOWN - const gracefulShutdown = async () => { - console.log('🛑 SIGTERM/SIGINT received. Shutting down gracefully...'); - - server.close(async () => { - console.log('✅ HTTP server closed.'); - try { - await mongoose.connection.close(false); - console.log('✅ MongoDB connection closed.'); - process.exit(0); - } catch (err) { - console.error('❌ Error closing MongoDB connection:', err); - process.exit(1); - } - }); - - // Force close after 10s - setTimeout(() => { - console.error('Force shutting down...'); - process.exit(1); - }, 10000); - }; - - process.on('SIGTERM', gracefulShutdown); - process.on('SIGINT', gracefulShutdown); -} - -// Export for Testing -module.exports = app; \ No newline at end of file diff --git a/apps/consumer/src/middlewares/authMiddleware.js b/apps/consumer/src/middlewares/authMiddleware.js deleted file mode 100644 index 424740bd..00000000 --- a/apps/consumer/src/middlewares/authMiddleware.js +++ /dev/null @@ -1,39 +0,0 @@ -const jwt = require('jsonwebtoken'); - -module.exports = function (req, res, next) { - // Check for token in cookies (Primary for Web) - let token = req.cookies && req.cookies.accessToken; - - // Fallback to Authorization header (For CLI/API) - if (!token) { - const authHeader = req.header('Authorization'); - if (authHeader) { - const parts = authHeader.trim().split(/\s+/); - if (parts.length === 2 && parts[0].toLowerCase() === 'bearer') { - token = parts[1]; - } - } - } - - // Check if any token was provided - if (!token) { - return res.status(401).json({ error: 'Access Denied: No Token Provided' }); - } - - try { - // Verify the token using the secret key - const verified = jwt.verify(token, process.env.JWT_SECRET); - - - // Attach decoded token data to request object - req.user = verified; - - // Proceed to the next middleware or route handler - next(); - } catch (err) { - console.log("err---------------2") - console.error(err); - - res.status(400).json({ error: 'Invalid Token' }); - } -}; diff --git a/apps/consumer/src/controllers/project.controller.js b/apps/dashboard-api/src/controllers/dbExport.controller.js similarity index 100% rename from apps/consumer/src/controllers/project.controller.js rename to apps/dashboard-api/src/controllers/dbExport.controller.js diff --git a/apps/consumer/src/routes/project.routes.js b/apps/dashboard-api/src/routes/dbExport.routes.js similarity index 79% rename from apps/consumer/src/routes/project.routes.js rename to apps/dashboard-api/src/routes/dbExport.routes.js index 1c6287e2..990ccc7d 100644 --- a/apps/consumer/src/routes/project.routes.js +++ b/apps/dashboard-api/src/routes/dbExport.routes.js @@ -1,6 +1,6 @@ const express = require('express'); const router = express.Router(); -const projectController = require('../controllers/project.controller'); +const projectController = require('../controllers/dbExport.controller'); const authMiddleware = require('../middlewares/authMiddleware'); // POST /api/projects/:projectId/export From 5ef25f88d05195cde48862a736d55ad86b10f9da Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Tue, 19 May 2026 09:07:28 +0530 Subject: [PATCH 09/24] refactor: move export endpoint to projects router and remove dbExport router --- apps/dashboard-api/src/app.js | 2 +- apps/dashboard-api/src/routes/dbExport.routes.js | 9 --------- apps/dashboard-api/src/routes/projects.js | 4 ++++ 3 files changed, 5 insertions(+), 10 deletions(-) delete mode 100644 apps/dashboard-api/src/routes/dbExport.routes.js diff --git a/apps/dashboard-api/src/app.js b/apps/dashboard-api/src/app.js index 185a6c04..e9fb9f18 100644 --- a/apps/dashboard-api/src/app.js +++ b/apps/dashboard-api/src/app.js @@ -116,7 +116,7 @@ app.use('/api/analytics', dashboardLimiter, analyticsRoute); app.use('/api/billing', billingRoute); app.use('/api/events', dashboardLimiter, eventsRoute); app.use('/api/admin/metrics', dashboardLimiter, adminMetricsRoute); - +app.use('/api/') diff --git a/apps/dashboard-api/src/routes/dbExport.routes.js b/apps/dashboard-api/src/routes/dbExport.routes.js deleted file mode 100644 index 990ccc7d..00000000 --- a/apps/dashboard-api/src/routes/dbExport.routes.js +++ /dev/null @@ -1,9 +0,0 @@ -const express = require('express'); -const router = express.Router(); -const projectController = require('../controllers/dbExport.controller'); -const authMiddleware = require('../middlewares/authMiddleware'); - -// POST /api/projects/:projectId/export -router.post('/:projectId/export', authMiddleware, projectController.dbExportHandler); - -module.exports = router; diff --git a/apps/dashboard-api/src/routes/projects.js b/apps/dashboard-api/src/routes/projects.js index e01e5b4a..67beec9d 100644 --- a/apps/dashboard-api/src/routes/projects.js +++ b/apps/dashboard-api/src/routes/projects.js @@ -50,6 +50,7 @@ const { const { createAdminUser, resetPassword, getUserDetails, updateAdminUser, listUserSessions, revokeUserSession } = require('../controllers/userAuth.controller'); +const exportController = require('../controllers/dbExport.controller'); // POST REQ FOR CREATE PROJECT router.post('/', authMiddleware, verifyEmail, planEnforcement.checkProjectLimit, createProject); @@ -152,4 +153,7 @@ router.put('/:projectId/admin/users/:userId', authMiddleware, loadProjectForAdmi router.get('/:projectId/admin/users/:userId/sessions', authMiddleware, loadProjectForAdmin, checkAuthEnabled, listUserSessions); router.delete('/:projectId/admin/users/:userId/sessions/:tokenId', authMiddleware, loadProjectForAdmin, checkAuthEnabled, revokeUserSession); +// POST req for DB EXPORT +router.post('/:projectId/export', authMiddleware, exportController.dbExportHandler); + module.exports = router; From 0c6f88af7ef5b687d25c340a78f9ab07db7253f1 Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Tue, 19 May 2026 14:55:58 +0530 Subject: [PATCH 10/24] feat: implement project ownership verifcation and queuing logic in export handler --- apps/dashboard-api/src/app.js | 1 - .../src/controllers/dbExport.controller.js | 25 ++++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/apps/dashboard-api/src/app.js b/apps/dashboard-api/src/app.js index e9fb9f18..2e1b582e 100644 --- a/apps/dashboard-api/src/app.js +++ b/apps/dashboard-api/src/app.js @@ -116,7 +116,6 @@ app.use('/api/analytics', dashboardLimiter, analyticsRoute); app.use('/api/billing', billingRoute); app.use('/api/events', dashboardLimiter, eventsRoute); app.use('/api/admin/metrics', dashboardLimiter, adminMetricsRoute); -app.use('/api/') diff --git a/apps/dashboard-api/src/controllers/dbExport.controller.js b/apps/dashboard-api/src/controllers/dbExport.controller.js index d4ee8ac6..996b403e 100644 --- a/apps/dashboard-api/src/controllers/dbExport.controller.js +++ b/apps/dashboard-api/src/controllers/dbExport.controller.js @@ -1,26 +1,39 @@ const { AppError } = require('@urbackend/common'); const { Developer } = require('@urbackend/common'); +const { Project } = require('@urbackend/common'); +const { exportQueue } = require('@urbackend/common'); module.exports.dbExportHandler = async (req, res, next) => { try { const { projectId } = req.params; const { _id: userId } = req.user; - const developer = await Developer.findById(userId).select('email').lean(); + + const project = await Project.findById(projectId).select('owner').lean(); + if (!project) { + return next(new AppError(404, "Project not found.")); + } + if (project.owner.toString() !== userId.toString()) { + return next(new AppError(403, "Access denied. You are not the owner of this project.")); + } + + + const developer = await Developer.findById(userId).select('email plan').lean(); if (!developer) { return next(new AppError(404, "Authenticated developer not found.")); } - const { email } = developer; + const { email, plan = 'free' } = developer; + + console.log(`[Dashboard API] Received export request for project ${projectId} from user ${userId} (${email})`); - console.log(`[Consumer API] Received export request for project ${projectId} from user ${userId} (${email})`); + await exportQueue.add('export-database', { projectId, userId, email }); - // just acknowledging the request, for now return res.status(202).json({ - message: `Export request for project ${projectId} received by consumer. Processing will begin shortly.`, + message: `Database export request received. You will receive an email with a download link shortly.`, }); } catch (err) { - console.error(`[Consumer API] Error handling export request for project ${req.params.projectId}:`, err); + console.error(`[Dashboard API] Error handling export request for project ${req.params.projectId}:`, err); return next(new AppError(500, err.message || "Failed to initiate database export.")); } }; From 5fd7eb1bc07d538c28f003154759e8af8f68ed9d Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Tue, 19 May 2026 18:15:53 +0530 Subject: [PATCH 11/24] feat: implement plan based rate limiting --- .../src/controllers/dbExport.controller.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/apps/dashboard-api/src/controllers/dbExport.controller.js b/apps/dashboard-api/src/controllers/dbExport.controller.js index 996b403e..23d2c11d 100644 --- a/apps/dashboard-api/src/controllers/dbExport.controller.js +++ b/apps/dashboard-api/src/controllers/dbExport.controller.js @@ -2,6 +2,7 @@ const { AppError } = require('@urbackend/common'); const { Developer } = require('@urbackend/common'); const { Project } = require('@urbackend/common'); const { exportQueue } = require('@urbackend/common'); +const { redis } = require('@urbackend/common'); module.exports.dbExportHandler = async (req, res, next) => { try { @@ -26,10 +27,25 @@ module.exports.dbExportHandler = async (req, res, next) => { console.log(`[Dashboard API] Received export request for project ${projectId} from user ${userId} (${email})`); + + const maxExports = plan === 'pro' ? 5 : 1; + const today = new Date().toISOString().split('T')[0]; + const key = `project:${projectId}:export_limit:${today}`; + + const currentCount = await redis.get(key); + if (currentCount && Number(currentCount) >= maxExports) { + return next(new AppError(429, `Daily export limit reached (${maxExports}/${maxExports}). Please try again tomorrow.`)); + } + + const newCount = await redis.incr(key); + if (newCount === 1) { + await redis.expire(key, 86400); // Set expiry to 24 hours + } + await exportQueue.add('export-database', { projectId, userId, email }); return res.status(202).json({ - message: `Database export request received. You will receive an email with a download link shortly.`, + message: `Database export request received. You will receive an email with a download link shortly. Usage today: ${newCount}/${maxExports}.`, }); } catch (err) { From d47dd37cefb33236e140e265e921b7a919d6dec9 Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Tue, 19 May 2026 19:14:43 +0530 Subject: [PATCH 12/24] feat: cache project lookup in Redis before MongoDB fallback --- apps/dashboard-api/package.json | 2 ++ .../src/controllers/dbExport.controller.js | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/dashboard-api/package.json b/apps/dashboard-api/package.json index 1996169d..508a9ff2 100644 --- a/apps/dashboard-api/package.json +++ b/apps/dashboard-api/package.json @@ -14,6 +14,8 @@ "transform": {} }, "dependencies": { + "@bull-board/api": "^7.1.5", + "@bull-board/express": "^7.1.5", "@kiroo/sdk": "^0.1.2", "@supabase/supabase-js": "^2.84.0", "@urbackend/common": "*", diff --git a/apps/dashboard-api/src/controllers/dbExport.controller.js b/apps/dashboard-api/src/controllers/dbExport.controller.js index 23d2c11d..7db26a1c 100644 --- a/apps/dashboard-api/src/controllers/dbExport.controller.js +++ b/apps/dashboard-api/src/controllers/dbExport.controller.js @@ -3,17 +3,22 @@ const { Developer } = require('@urbackend/common'); const { Project } = require('@urbackend/common'); const { exportQueue } = require('@urbackend/common'); const { redis } = require('@urbackend/common'); +const { getProjectById, setProjectById } = require('@urbackend/common'); module.exports.dbExportHandler = async (req, res, next) => { try { const { projectId } = req.params; const { _id: userId } = req.user; - - const project = await Project.findById(projectId).select('owner').lean(); + let project = await getProjectById(projectId); if (!project) { - return next(new AppError(404, "Project not found.")); + project = await Project.findById(projectId).lean(); + if (!project) { + return next(new AppError(404, "Project not found.")); + } + await setProjectById(projectId, project); } + if (project.owner.toString() !== userId.toString()) { return next(new AppError(403, "Access denied. You are not the owner of this project.")); } From c9c86c9759a7cbbd1c1d9214d6238d93b87a8a13 Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Wed, 20 May 2026 09:07:19 +0530 Subject: [PATCH 13/24] feat: implement the DB export worker logic --- apps/consumer/src/exportWorker.js | 94 +++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 apps/consumer/src/exportWorker.js diff --git a/apps/consumer/src/exportWorker.js b/apps/consumer/src/exportWorker.js new file mode 100644 index 00000000..00fa7574 --- /dev/null +++ b/apps/consumer/src/exportWorker.js @@ -0,0 +1,94 @@ +const { Worker } = require('bullmq'); +const fs = require('fs'); +const path = require('path'); +const os = require('os'); +const { + redis, + exportQueue, + emailQueue, + Project, + getConnection, + getCompiledModel, + getStorage, + getBucket +} = require('@urbackend/common'); + +const initExportWorker = () => { + const worker = new Worker(exportQueue.name, async (job) => { + const { projectId, userId, email } = job.data; + console.log(`[ExportWorker] Starting export for project ${projectId} requested by ${email}`); + + const project = await Project.findById(projectId).select('+resources.storage.config.encrypted +resources.storage.config.iv +resources.storage.config.tag resources.storage.isExternal storageUsed storageLimit'); + if (!project) throw new Error('Project not found'); + + const connection = await getConnection(projectId); + + // stream to a local temp file first to prevent memory bloat on large db export + const tempFilePath = path.join(os.tmpdir(), `export_${projectId}_${Date.now()}.json`); + const writeStream = fs.createWriteStream(tempFilePath); + + try { + writeStream.write('{\n'); + + for (let i = 0; i < project.collections.length; i++) { + const col = project.collections[i]; + const Model = getCompiledModel(connection, col, projectId, project.resources.db.isExternal); + + writeStream.write(` "${col.name}": [\n`); + + // use a mongoose cursor to stream documents one by one + const cursor = Model.find().lean().cursor(); + let first = true; + + for await (const doc of cursor) { + if (!first) writeStream.write(',\n'); + writeStream.write(` ${JSON.stringify(doc)}`); + first = false; + } + + writeStream.write('\n ]'); + if (i < project.collections.length - 1) writeStream.write(',\n'); + } + + writeStream.write('\n}\n'); + writeStream.end(); + + await new Promise((resolve, reject) => { + writeStream.on('finish', resolve); + writeStream.on('error', reject); + }); + + console.log(`[ExportWorker] Data written to temp file. Uploading to storage...`); + + // upload to supabase / storage + const supabase = await getStorage(project); + const bucket = getBucket(project); + const storagePath = `${projectId}/exports/db_export_${Date.now()}.json`; + + const fileBuffer = fs.readFileSync(tempFilePath); + const { error: uploadError } = await supabase.storage + .from(bucket) + .upload(storagePath, fileBuffer, { contentType: 'application/json', upsert: true }); + + if (uploadError) throw uploadError; + + // create a signed URL valid for 24 hrs (86400 seconds) + const { data: signedData, error: signedError } = await supabase.storage + .from(bucket) + .createSignedUrl(storagePath, 86400); + + if (signedError) throw signedError; + + // queue the email to be sent to the user + await emailQueue.add('send-export-email', { email, downloadUrl: signedData.signedUrl, projectName: project.name }); + console.log(`[ExportWorker] Export completed! Email queued for ${email}`); + + } finally { + if (fs.existsSync(tempFilePath)) fs.unlinkSync(tempFilePath); + } + }, { connection: redis, concurrency: 2 }); + + return worker; +}; + +module.exports = { initExportWorker }; \ No newline at end of file From 12cc3f031e79a8ea2e45e626267beadf04b84ff8 Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Wed, 20 May 2026 14:11:52 +0530 Subject: [PATCH 14/24] feat: add export email job handling to email worker --- packages/common/src/queues/emailQueue.js | 61 ++++++++++++++++++------ 1 file changed, 46 insertions(+), 15 deletions(-) diff --git a/packages/common/src/queues/emailQueue.js b/packages/common/src/queues/emailQueue.js index 30c5295f..11127dc0 100644 --- a/packages/common/src/queues/emailQueue.js +++ b/packages/common/src/queues/emailQueue.js @@ -7,21 +7,52 @@ const emailQueue = new Queue('email-queue', { connection }); // Initialize Worker with Rate Limiting const worker = new Worker('email-queue', async (job) => { - const { email, version, title, content, changelogUrl } = job.data; - try { - console.log(`[Queue] Processing Release email for: ${email}`); - await sendReleaseEmail(email, { version, title, content, changelogUrl }); - } catch (error) { - console.error(`[Queue] Failed to send email to ${email}:`, error); - throw error; - } -}, { - connection, - limiter: { - max: 1, - duration: 900000, // 1 job per 15 minutes (96 per 24 hours) - safe for 100 limit - } -}); + + if (job.name === 'release-email') { + const { email, version, title, content, changelogUrl } = job.data; + try { + console.log(`[Queue] Processing Release email for: ${email}`); + await sendReleaseEmail(email, { version, title, content, changelogUrl }); + } catch (error) { + console.error(`[Queue] Failed to send email to ${email}:`, error); + throw error; + } + } + + if (job.name === 'send-export-email') { + const { email, downloadUrl, projectName } = job.data; + + console.log(`[EmailWorker] Sending simple export email to ${email} for ${projectName}`); + + const subject = `Export Ready: ${projectName}`; + + const textBody = `Hello, + + Your requested database export for the project "${projectName}" is ready. + + You can download your JSON export using the following secure link (valid for 24 hours): + ${downloadUrl} + + Thanks, + urBackend Team`; + + await emailTransporter.sendMail({ + from: '"urBackend" ', + to: email, + subject: subject, + text: textBody + }); + + console.log(`[EmailWorker] Export email successfully sent to ${email}`); + } + + }, { + connection, + limiter: { + max: 1, + duration: 900000, // 1 job per 15 minutes (96 per 24 hours) - safe for 100 limit + } + }); worker.on('completed', (job) => { console.log(`[Queue] Job ${job.id} completed successfully`); From 99c722abc271a81578951dbb8016c97a13491fff Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Wed, 20 May 2026 15:42:00 +0530 Subject: [PATCH 15/24] feat: implement DB export worker completion and failure handling and initialize worker --- apps/consumer/package.json | 4 ++-- apps/consumer/src/app.js | 0 apps/consumer/src/exportWorker.js | 37 ++++++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 3 deletions(-) delete mode 100644 apps/consumer/src/app.js diff --git a/apps/consumer/package.json b/apps/consumer/package.json index e37987e3..c540b4d8 100644 --- a/apps/consumer/package.json +++ b/apps/consumer/package.json @@ -4,8 +4,8 @@ "description": "", "main": "src/app.js", "scripts": { - "dev": "node src/app.js", - "start": "node src/app.js", + "dev": "node src/exportWorker.js", + "start": "node src/exportWorker.js", "test": "jest --testPathPatterns=src/" }, "keywords": [], diff --git a/apps/consumer/src/app.js b/apps/consumer/src/app.js deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/consumer/src/exportWorker.js b/apps/consumer/src/exportWorker.js index 00fa7574..fef5c38b 100644 --- a/apps/consumer/src/exportWorker.js +++ b/apps/consumer/src/exportWorker.js @@ -1,4 +1,8 @@ +const dotenv = require('dotenv'); +dotenv.config({ path: require('path').join(__dirname, '../../../.env') }); + const { Worker } = require('bullmq'); +const mongoose = require('mongoose') const fs = require('fs'); const path = require('path'); const os = require('os'); @@ -13,12 +17,18 @@ const { getBucket } = require('@urbackend/common'); +const { validateEnv } = require('@urbackend/common'); + +if (process.env.NODE_ENV !== 'test') { + validateEnv(); +} + const initExportWorker = () => { const worker = new Worker(exportQueue.name, async (job) => { const { projectId, userId, email } = job.data; console.log(`[ExportWorker] Starting export for project ${projectId} requested by ${email}`); - const project = await Project.findById(projectId).select('+resources.storage.config.encrypted +resources.storage.config.iv +resources.storage.config.tag resources.storage.isExternal storageUsed storageLimit'); + const project = await Project.findById(projectId); if (!project) throw new Error('Project not found'); const connection = await getConnection(projectId); @@ -88,7 +98,32 @@ const initExportWorker = () => { } }, { connection: redis, concurrency: 2 }); + worker.on('completed', (job) => { + console.log(`[ExportWorker] Job ${job.id} for project ${job.data.projectId} completed.`); + }); + + worker.on('failed', (job, err) => { + console.error(`[ExportWorker] Job ${job?.id} for project ${job?.data?.projectId} failed:`, err.message); + }); + return worker; }; +if (require.main === module) { + + const { connectDB } = require('@urbackend/common'); + + (async () => { + try { + await connectDB(); + + initExportWorker(); + + console.log('[CONSUMER] Export worker started and listening for jobs...'); + } catch (err) { + console.error('Failed to start worker:', err); + process.exit(1); + } + })(); +} module.exports = { initExportWorker }; \ No newline at end of file From a6f3555b91816ed217fd0bc21918eba62c122bb5 Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Wed, 20 May 2026 16:46:28 +0530 Subject: [PATCH 16/24] feat: add sendExportReadyEmail function to emailService.js --- packages/common/src/utils/emailService.js | 36 +++++++++++++++++++- packages/common/src/utils/storage.manager.js | 1 + 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/common/src/utils/emailService.js b/packages/common/src/utils/emailService.js index a37e7b57..8e9074a1 100644 --- a/packages/common/src/utils/emailService.js +++ b/packages/common/src/utils/emailService.js @@ -299,4 +299,38 @@ async function sendProRequestConfirmationEmail(email) { } } -module.exports = { sendOtp, sendReleaseEmail, sendAuthOtpEmail, sendProRequestConfirmationEmail }; +async function sendExportReadyEmail({ to, downloadUrl, projectName }) { + try { + const subject = `Export Ready: ${projectName}`; + const textBody = `Hello, + +Your requested database export for the project "${projectName}" is ready. + +You can download your JSON export using the following secure link (valid for 24 hours): +${downloadUrl} + +Thanks, +urBackend Team`; + + console.log("we are he re") + + const { data, error } = await resend.emails.send({ + from: '"urBackend" ', + to: to, + subject: subject, + text: textBody, + replyTo: 'urbackend@apps.bitbros.in', + }); + + if (error) { + console.error("[Resend Error - Export Ready]", error); + throw new Error(error.message || "Failed to send export ready email"); + } + return { data }; + } catch (error) { + console.error("[Email Service Error - Export Ready]", error); + throw error; + } +} + +module.exports = { sendOtp, sendReleaseEmail, sendAuthOtpEmail, sendProRequestConfirmationEmail, sendExportReadyEmail }; diff --git a/packages/common/src/utils/storage.manager.js b/packages/common/src/utils/storage.manager.js index df4da987..aa2a2635 100644 --- a/packages/common/src/utils/storage.manager.js +++ b/packages/common/src/utils/storage.manager.js @@ -143,6 +143,7 @@ async function getStorage(project) { client = createS3Adapter(config); } else { throw new Error("Unknown storage provider: " + provider); + console.error("[getStorage] Unknown storage provider: ", provider); } } catch (err) { console.error("Storage config error:", err); From 9cea1509d57e211b1144110251dca180ba871d00 Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Wed, 20 May 2026 16:48:41 +0530 Subject: [PATCH 17/24] fix: modify emailQueue.js to use sendExportReadyEmail fn --- packages/common/src/index.js | 2 ++ packages/common/src/queues/emailQueue.js | 21 ++------------------- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/packages/common/src/index.js b/packages/common/src/index.js index b1cd27b7..c3f4054f 100644 --- a/packages/common/src/index.js +++ b/packages/common/src/index.js @@ -32,6 +32,7 @@ const MailLog = require("./models/MailLog"); const { authEmailQueue, initAuthEmailWorker } = require("./queues/authEmailQueue"); const { publicEmailQueue, initPublicEmailWorker } = require("./queues/publicEmailQueue"); const { emailQueue } = require("./queues/emailQueue"); +const { exportQueue } = require("./queues/exportQueue"); const { webhookQueue, enqueueWebhookDelivery, @@ -130,6 +131,7 @@ module.exports = { WebhookDelivery, ProRequest, authEmailQueue, + exportQueue, emailQueue, webhookQueue, enqueueWebhookDelivery, diff --git a/packages/common/src/queues/emailQueue.js b/packages/common/src/queues/emailQueue.js index 11127dc0..4eeafe87 100644 --- a/packages/common/src/queues/emailQueue.js +++ b/packages/common/src/queues/emailQueue.js @@ -1,6 +1,6 @@ const { Queue, Worker } = require('bullmq'); const connection = require('../config/redis'); -const { sendReleaseEmail } = require('../utils/emailService'); +const { sendReleaseEmail, sendExportReadyEmail } = require('../utils/emailService'); // Create the email queue const emailQueue = new Queue('email-queue', { connection }); @@ -24,24 +24,7 @@ const worker = new Worker('email-queue', async (job) => { console.log(`[EmailWorker] Sending simple export email to ${email} for ${projectName}`); - const subject = `Export Ready: ${projectName}`; - - const textBody = `Hello, - - Your requested database export for the project "${projectName}" is ready. - - You can download your JSON export using the following secure link (valid for 24 hours): - ${downloadUrl} - - Thanks, - urBackend Team`; - - await emailTransporter.sendMail({ - from: '"urBackend" ', - to: email, - subject: subject, - text: textBody - }); + await sendExportReadyEmail({ to:email, downloadUrl, projectName}); console.log(`[EmailWorker] Export email successfully sent to ${email}`); } From dce298aacfcf464de11ae341122a094f32bdffe4 Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Wed, 20 May 2026 17:03:57 +0530 Subject: [PATCH 18/24] fix (package.json): modify dev script to also run consumer server --- package-lock.json | 62 +++++++++++++++++++++++ package.json | 2 +- packages/common/src/utils/emailService.js | 2 - 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6afc350d..13c0a022 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,8 @@ "version": "0.10.0", "license": "AGPL-3.0-only", "dependencies": { + "@bull-board/api": "^7.1.5", + "@bull-board/express": "^7.1.5", "@kiroo/sdk": "^0.1.2", "@supabase/supabase-js": "^2.84.0", "@urbackend/common": "*", @@ -1575,6 +1577,39 @@ "node": ">=18" } }, + "node_modules/@bull-board/api": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/@bull-board/api/-/api-7.1.5.tgz", + "integrity": "sha512-EW0sbTtGIysu9vipdVpPQeToPqOpPgVZTt+pn1Ut3gbSS/GLWbEgIfFtMmSQDUoSL9WH00RzjgUY5K+43nWh0A==", + "license": "MIT", + "dependencies": { + "redis-info": "^3.1.0" + }, + "peerDependencies": { + "@bull-board/ui": "7.1.5" + } + }, + "node_modules/@bull-board/express": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/@bull-board/express/-/express-7.1.5.tgz", + "integrity": "sha512-kp4SzhVjZlykryiQwcOhJjDhiLbBnZoAMoSgEstzqQ0raLw+jERRC6ryJ0MIQO+SO+Jv9EjjxrXCR8O2YSP/eg==", + "license": "MIT", + "dependencies": { + "@bull-board/api": "7.1.5", + "@bull-board/ui": "7.1.5", + "ejs": "^5.0.2", + "express": "^5.2.1" + } + }, + "node_modules/@bull-board/ui": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/@bull-board/ui/-/ui-7.1.5.tgz", + "integrity": "sha512-2IkatKwNRx/1M9/lAZIptcxS1FPNq6icpp2M46Upwd4olVxs/ujF9Kvs+Ff9ExtIO/OgYfwx7mG2IprGZ+nQCg==", + "license": "MIT", + "dependencies": { + "@bull-board/api": "7.1.5" + } + }, "node_modules/@dnd-kit/accessibility": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz", @@ -7064,6 +7099,18 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "license": "MIT" }, + "node_modules/ejs": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-5.0.2.tgz", + "integrity": "sha512-IpbUaI/CAW86l3f+T8zN0iggSc0LmMZLcIW5eRVStLVNCoTXkE0YlncbbH50fp8Cl6zHIky0sW2uUbhBqGw0Jw==", + "license": "Apache-2.0", + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.12.18" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.349", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.349.tgz", @@ -10058,6 +10105,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, "node_modules/lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", @@ -12639,6 +12692,15 @@ "node": ">=4" } }, + "node_modules/redis-info": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redis-info/-/redis-info-3.1.0.tgz", + "integrity": "sha512-ER4L9Sh/vm63DkIE0bkSjxluQlioBiBgf5w1UuldaW/3vPcecdljVDisZhmnCMvsxHNiARTTDDHGg9cGwTfrKg==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.11" + } + }, "node_modules/redis-parser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", diff --git a/package.json b/package.json index be2009b8..17c00b25 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "sdks/*" ], "scripts": { - "dev": "concurrently -c \"cyan,magenta,yellow\" -n \"DASHBOARD,PUBLIC,WEB\" \"npm run dev --workspace=dashboard-api\" \"npm run dev --workspace=public-api\" \"npm run dev --workspace=web-dashboard\"", + "dev": "concurrently -c \"cyan,magenta,yellow,green\" -n \"DASHBOARD,PUBLIC,WEB,CONSUMER\" \"npm run dev --workspace=dashboard-api\" \"npm run dev --workspace=public-api\" \"npm run dev --workspace=web-dashboard\" \"npm run dev --workspace=consumer\"", "build": "npm run build --workspaces --if-present", "prepare": "husky || node -e \"\"" }, diff --git a/packages/common/src/utils/emailService.js b/packages/common/src/utils/emailService.js index 8e9074a1..964ab73e 100644 --- a/packages/common/src/utils/emailService.js +++ b/packages/common/src/utils/emailService.js @@ -312,8 +312,6 @@ ${downloadUrl} Thanks, urBackend Team`; - console.log("we are he re") - const { data, error } = await resend.emails.send({ from: '"urBackend" ', to: to, From aa5547a5b7c3935e9a7bc29414b4c0a952724b0b Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Thu, 21 May 2026 10:29:50 +0530 Subject: [PATCH 19/24] refactor: add dedicated consumer entrypoint and graceful shutdown --- apps/consumer/index.js | 35 +++++++++++++++++++ apps/consumer/package.json | 4 +-- .../export.worker.js} | 28 +-------------- 3 files changed, 38 insertions(+), 29 deletions(-) create mode 100644 apps/consumer/index.js rename apps/consumer/src/{exportWorker.js => workers/export.worker.js} (85%) diff --git a/apps/consumer/index.js b/apps/consumer/index.js new file mode 100644 index 00000000..31432f71 --- /dev/null +++ b/apps/consumer/index.js @@ -0,0 +1,35 @@ +const dotenv = require('dotenv'); +dotenv.config({ path: require('path').join(__dirname, '../../.env') }); + +const { validateEnv } = require('@urbackend/common'); + +if (process.env.NODE_ENV !== 'test') { + validateEnv(); +} + +const { initExportWorker } = require('./src/workers/export.worker'); + +const { connectDB } = require('@urbackend/common'); + + (async () => { + try { + await connectDB(); + + const worker = initExportWorker(); + + console.log('[CONSUMER] Export worker started and listening for jobs...'); + + const shutdown = async () => { + console.log('Shutting down worker...'); + await worker.close(); + process.exit(0); + }; + + process.on('SIGINT', shutdown); + process.on('SIGTERM', shutdown); + + } catch (err) { + console.error('Failed to start worker:', err); + process.exit(1); + } + })(); \ No newline at end of file diff --git a/apps/consumer/package.json b/apps/consumer/package.json index c540b4d8..88ce13da 100644 --- a/apps/consumer/package.json +++ b/apps/consumer/package.json @@ -4,8 +4,8 @@ "description": "", "main": "src/app.js", "scripts": { - "dev": "node src/exportWorker.js", - "start": "node src/exportWorker.js", + "dev": "node index.js", + "start": "node index.js", "test": "jest --testPathPatterns=src/" }, "keywords": [], diff --git a/apps/consumer/src/exportWorker.js b/apps/consumer/src/workers/export.worker.js similarity index 85% rename from apps/consumer/src/exportWorker.js rename to apps/consumer/src/workers/export.worker.js index fef5c38b..d3760ff0 100644 --- a/apps/consumer/src/exportWorker.js +++ b/apps/consumer/src/workers/export.worker.js @@ -1,11 +1,8 @@ -const dotenv = require('dotenv'); -dotenv.config({ path: require('path').join(__dirname, '../../../.env') }); - const { Worker } = require('bullmq'); -const mongoose = require('mongoose') const fs = require('fs'); const path = require('path'); const os = require('os'); + const { redis, exportQueue, @@ -17,12 +14,6 @@ const { getBucket } = require('@urbackend/common'); -const { validateEnv } = require('@urbackend/common'); - -if (process.env.NODE_ENV !== 'test') { - validateEnv(); -} - const initExportWorker = () => { const worker = new Worker(exportQueue.name, async (job) => { const { projectId, userId, email } = job.data; @@ -109,21 +100,4 @@ const initExportWorker = () => { return worker; }; -if (require.main === module) { - - const { connectDB } = require('@urbackend/common'); - - (async () => { - try { - await connectDB(); - - initExportWorker(); - - console.log('[CONSUMER] Export worker started and listening for jobs...'); - } catch (err) { - console.error('Failed to start worker:', err); - process.exit(1); - } - })(); -} module.exports = { initExportWorker }; \ No newline at end of file From 18ab734a8ca9fbec1f414e991f650aa101cd5c3e Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Thu, 21 May 2026 10:43:37 +0530 Subject: [PATCH 20/24] chore: add Dockerfile --- apps/consumer/Dockerfile | 20 ++++++++++++++++++++ apps/consumer/package.json | 4 ++-- apps/consumer/{ => src}/index.js | 4 ++-- 3 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 apps/consumer/Dockerfile rename apps/consumer/{ => src}/index.js (85%) diff --git a/apps/consumer/Dockerfile b/apps/consumer/Dockerfile new file mode 100644 index 00000000..6df06336 --- /dev/null +++ b/apps/consumer/Dockerfile @@ -0,0 +1,20 @@ +FROM node:22-alpine + +WORKDIR /app + +# Copy root package files +COPY package.json package-lock.json ./ + +# Copy workspace package.json files +COPY packages/common/package.json ./packages/common/ +COPY apps/consumer/package.json ./apps/consumer/ + +RUN npm ci + +# Copy actual source code +COPY packages/common ./packages/common +COPY apps/consumer ./apps/consumer + +WORKDIR /app/apps/consumer + +CMD ["npm", "run", "start"] \ No newline at end of file diff --git a/apps/consumer/package.json b/apps/consumer/package.json index 88ce13da..61a0ad77 100644 --- a/apps/consumer/package.json +++ b/apps/consumer/package.json @@ -4,8 +4,8 @@ "description": "", "main": "src/app.js", "scripts": { - "dev": "node index.js", - "start": "node index.js", + "dev": "node src/index.js", + "start": "node src/index.js", "test": "jest --testPathPatterns=src/" }, "keywords": [], diff --git a/apps/consumer/index.js b/apps/consumer/src/index.js similarity index 85% rename from apps/consumer/index.js rename to apps/consumer/src/index.js index 31432f71..c43ab2c8 100644 --- a/apps/consumer/index.js +++ b/apps/consumer/src/index.js @@ -1,5 +1,5 @@ const dotenv = require('dotenv'); -dotenv.config({ path: require('path').join(__dirname, '../../.env') }); +dotenv.config({ path: require('path').join(__dirname, '../../../.env') }); const { validateEnv } = require('@urbackend/common'); @@ -7,7 +7,7 @@ if (process.env.NODE_ENV !== 'test') { validateEnv(); } -const { initExportWorker } = require('./src/workers/export.worker'); +const { initExportWorker } = require('./workers/export.worker'); const { connectDB } = require('@urbackend/common'); From d7176497305aac53d084ff0c0994f33558f70b1a Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Sun, 24 May 2026 12:31:43 +0530 Subject: [PATCH 21/24] feat(storage): Implement function to return unified S3Client for all storage providers --- packages/common/src/utils/storage.manager.js | 116 ++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/packages/common/src/utils/storage.manager.js b/packages/common/src/utils/storage.manager.js index aa2a2635..35e26367 100644 --- a/packages/common/src/utils/storage.manager.js +++ b/packages/common/src/utils/storage.manager.js @@ -267,4 +267,118 @@ async function verifyUploadedFile(project, filePath) { return head.ContentLength; } -module.exports = { getStorage, getPresignedUploadUrl, verifyUploadedFile }; +async function getS3CompatibleStorage(project) { + if (!project?._id) { + throw new Error("Project document is required"); + } + + // INTERNAL SUPABASE STORAGE + if (!project.resources?.storage?.isExternal) { + + if ( + !process.env.SUPABASE_S3_ENDPOINT || + !process.env.SUPABASE_S3_ACCESS_KEY_ID || + !process.env.SUPABASE_S3_SECRET_ACCESS_KEY || + !process.env.SUPABASE_BUCKET + ) { + throw new Error( + "Internal Supabase S3 configuration is incomplete" + ); + } + + const s3Client = new S3Client({ + region: "auto", + endpoint: process.env.SUPABASE_S3_ENDPOINT, + forcePathStyle: true, + credentials: { + accessKeyId: process.env.SUPABASE_S3_ACCESS_KEY_ID, + secretAccessKey: process.env.SUPABASE_S3_SECRET_ACCESS_KEY + } + }); + + return { + provider: "supabase_internal", + s3Client, + bucket: process.env.SUPABASE_BUCKET + }; + } + + // EXTERNAL STORAGE + let config; + + try { + const decrypted = decrypt(project.resources.storage.config); + config = JSON.parse(decrypted); + } catch (err) { + console.error("[getS3CompatibleStorage] Invalid config:", err); + throw new Error("Invalid storage configuration"); + } + + const provider = config.storageProvider || "supabase"; + + // EXTERNAL SUPABASE VIA S3 GATEWAY + if (provider === "supabase") { + + if ( + !config.s3Endpoint || + !config.s3AccessKeyId || + !config.s3SecretAccessKey || + !config.bucket + ) { + throw new Error( + "Supabase S3-compatible configuration is incomplete" + ); + } + + const s3Client = new S3Client({ + region: "auto", + endpoint: config.s3Endpoint, + forcePathStyle: true, + credentials: { + accessKeyId: config.s3AccessKeyId, + secretAccessKey: config.s3SecretAccessKey + } + }); + + return { + provider, + s3Client, + bucket: config.bucket + }; + } + + // AWS S3 / CLOUDFLARE R2 + if (provider === "s3" || provider === "cloudflare_r2") { + + if ( + !config.endpoint || + !config.accessKeyId || + !config.secretAccessKey || + !config.bucket + ) { + throw new Error( + "S3-compatible storage configuration is incomplete" + ); + } + + const s3Client = new S3Client({ + region: config.region || "auto", + endpoint: config.endpoint, + forcePathStyle: true, + credentials: { + accessKeyId: config.accessKeyId, + secretAccessKey: config.secretAccessKey + } + }); + + return { + provider, + s3Client, + bucket: config.bucket + }; + } + + throw new Error(`Unsupported storage provider: ${provider}`); +} + +module.exports = { getStorage, getPresignedUploadUrl, verifyUploadedFile, getS3CompatibleStorage }; From 9c14503042fb28fc76088b59e05cd4f35d8c25ed Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Mon, 25 May 2026 01:07:12 +0530 Subject: [PATCH 22/24] fix (storage): Remove bucket from getS3Storage return body, rename ambiguous env vars to standardized storage config names --- packages/common/src/index.js | 3 ++- packages/common/src/utils/storage.manager.js | 28 ++++++++------------ 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/packages/common/src/index.js b/packages/common/src/index.js index c3f4054f..62ff043b 100644 --- a/packages/common/src/index.js +++ b/packages/common/src/index.js @@ -108,7 +108,7 @@ const { } = require("./utils/project.helpers"); const QueryEngine = require("./utils/queryEngine"); const { registry, storageRegistry } = require("./utils/registry"); -const { getStorage, getPresignedUploadUrl, verifyUploadedFile } = require("./utils/storage.manager"); +const { getStorage, getPresignedUploadUrl, verifyUploadedFile, getS3CompatibleStorage } = require("./utils/storage.manager"); const validateEnv = require("./utils/validateEnv"); const { validateData, validateUpdateData } = require("./utils/validateData"); const sessionManager = require("./utils/session.manager"); @@ -224,4 +224,5 @@ module.exports = { getMonthKey, getEndOfMonthTtlSeconds, incrWithTtlAtomic, + getS3CompatibleStorage }; diff --git a/packages/common/src/utils/storage.manager.js b/packages/common/src/utils/storage.manager.js index 35e26367..3166b8da 100644 --- a/packages/common/src/utils/storage.manager.js +++ b/packages/common/src/utils/storage.manager.js @@ -276,10 +276,9 @@ async function getS3CompatibleStorage(project) { if (!project.resources?.storage?.isExternal) { if ( - !process.env.SUPABASE_S3_ENDPOINT || - !process.env.SUPABASE_S3_ACCESS_KEY_ID || - !process.env.SUPABASE_S3_SECRET_ACCESS_KEY || - !process.env.SUPABASE_BUCKET + !process.env.SUPABASE_URL || + !process.env.SUPABASE_PUBLIC_KEY || + !process.env.SUPABASE_SECRET_KEY ) { throw new Error( "Internal Supabase S3 configuration is incomplete" @@ -288,18 +287,17 @@ async function getS3CompatibleStorage(project) { const s3Client = new S3Client({ region: "auto", - endpoint: process.env.SUPABASE_S3_ENDPOINT, + endpoint: process.env.SUPABASE_URL, forcePathStyle: true, credentials: { - accessKeyId: process.env.SUPABASE_S3_ACCESS_KEY_ID, - secretAccessKey: process.env.SUPABASE_S3_SECRET_ACCESS_KEY + accessKeyId: process.env.SUPABASE_PUBLIC_KEY, + secretAccessKey: process.env.SUPABASE_SECRET_KEY } }); return { provider: "supabase_internal", - s3Client, - bucket: process.env.SUPABASE_BUCKET + s3Client }; } @@ -322,8 +320,7 @@ async function getS3CompatibleStorage(project) { if ( !config.s3Endpoint || !config.s3AccessKeyId || - !config.s3SecretAccessKey || - !config.bucket + !config.s3SecretAccessKey ) { throw new Error( "Supabase S3-compatible configuration is incomplete" @@ -342,8 +339,7 @@ async function getS3CompatibleStorage(project) { return { provider, - s3Client, - bucket: config.bucket + s3Client }; } @@ -353,8 +349,7 @@ async function getS3CompatibleStorage(project) { if ( !config.endpoint || !config.accessKeyId || - !config.secretAccessKey || - !config.bucket + !config.secretAccessKey ) { throw new Error( "S3-compatible storage configuration is incomplete" @@ -373,8 +368,7 @@ async function getS3CompatibleStorage(project) { return { provider, - s3Client, - bucket: config.bucket + s3Client }; } From 414fe0a6db8d9366a64ef6975496b93f7198def7 Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Tue, 26 May 2026 20:53:13 +0530 Subject: [PATCH 23/24] feat: update export worker to use getS3CompatibleStorage function, stream using PassThrough --- apps/consumer/src/workers/export.worker.js | 86 +- package-lock.json | 1200 ++++++-------------- package.json | 1 + 3 files changed, 394 insertions(+), 893 deletions(-) diff --git a/apps/consumer/src/workers/export.worker.js b/apps/consumer/src/workers/export.worker.js index d3760ff0..cc9a633d 100644 --- a/apps/consumer/src/workers/export.worker.js +++ b/apps/consumer/src/workers/export.worker.js @@ -1,7 +1,8 @@ const { Worker } = require('bullmq'); -const fs = require('fs'); -const path = require('path'); -const os = require('os'); +const { PassThrough } = require('stream'); +const { Upload } = require('@aws-sdk/lib-storage'); +const { GetObjectCommand } = require('@aws-sdk/client-s3'); +const { getSignedUrl } = require('@aws-sdk/s3-request-presigner'); const { redis, @@ -9,9 +10,9 @@ const { emailQueue, Project, getConnection, - getCompiledModel, - getStorage, - getBucket + getCompiledModel, + getS3CompatibleStorage, + getBucket } = require('@urbackend/common'); const initExportWorker = () => { @@ -24,68 +25,67 @@ const initExportWorker = () => { const connection = await getConnection(projectId); - // stream to a local temp file first to prevent memory bloat on large db export - const tempFilePath = path.join(os.tmpdir(), `export_${projectId}_${Date.now()}.json`); - const writeStream = fs.createWriteStream(tempFilePath); + console.log(`[ExportWorker] Preparing streaming upload to storage...`); + + const { s3Client } = await getS3CompatibleStorage(project); + const bucket = await getBucket(project); + const storagePath = `${projectId}/exports/db_export_${Date.now()}.json`; + + const passThrough = new PassThrough(); + + const upload = new Upload({ + client: s3Client, + params: { + Bucket: bucket, + Key: storagePath, + Body: passThrough, + ContentType: 'application/json' + } + }); + + // Start the upload promise in parallel + const uploadPromise = upload.done(); try { - writeStream.write('{\n'); + passThrough.write('{\n'); for (let i = 0; i < project.collections.length; i++) { const col = project.collections[i]; const Model = getCompiledModel(connection, col, projectId, project.resources.db.isExternal); - writeStream.write(` "${col.name}": [\n`); + passThrough.write(` "${col.name}": [\n`); // use a mongoose cursor to stream documents one by one const cursor = Model.find().lean().cursor(); let first = true; for await (const doc of cursor) { - if (!first) writeStream.write(',\n'); - writeStream.write(` ${JSON.stringify(doc)}`); + if (!first) passThrough.write(',\n'); + passThrough.write(` ${JSON.stringify(doc)}`); first = false; } - writeStream.write('\n ]'); - if (i < project.collections.length - 1) writeStream.write(',\n'); + passThrough.write('\n ]'); + if (i < project.collections.length - 1) passThrough.write(',\n'); } - writeStream.write('\n}\n'); - writeStream.end(); - - await new Promise((resolve, reject) => { - writeStream.on('finish', resolve); - writeStream.on('error', reject); - }); - - console.log(`[ExportWorker] Data written to temp file. Uploading to storage...`); - - // upload to supabase / storage - const supabase = await getStorage(project); - const bucket = getBucket(project); - const storagePath = `${projectId}/exports/db_export_${Date.now()}.json`; - - const fileBuffer = fs.readFileSync(tempFilePath); - const { error: uploadError } = await supabase.storage - .from(bucket) - .upload(storagePath, fileBuffer, { contentType: 'application/json', upsert: true }); + passThrough.write('\n}\n'); + passThrough.end(); - if (uploadError) throw uploadError; + console.log(`[ExportWorker] Database stream ended. Awaiting final storage upload chunks...`); + await uploadPromise; // create a signed URL valid for 24 hrs (86400 seconds) - const { data: signedData, error: signedError } = await supabase.storage - .from(bucket) - .createSignedUrl(storagePath, 86400); - - if (signedError) throw signedError; + const command = new GetObjectCommand({ Bucket: bucket, Key: storagePath }); + const signedUrl = await getSignedUrl(s3Client, command, { expiresIn: 86400 }); // queue the email to be sent to the user - await emailQueue.add('send-export-email', { email, downloadUrl: signedData.signedUrl, projectName: project.name }); + await emailQueue.add('send-export-email', { email, downloadUrl: signedUrl, projectName: project.name }); console.log(`[ExportWorker] Export completed! Email queued for ${email}`); - } finally { - if (fs.existsSync(tempFilePath)) fs.unlinkSync(tempFilePath); + } catch (error) { + passThrough.destroy(error); + throw error; } }, { connection: redis, concurrency: 2 }); diff --git a/package-lock.json b/package-lock.json index 13c0a022..277a525f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "sdks/*" ], "dependencies": { + "@aws-sdk/lib-storage": "^3.1053.0", "path": "^0.12.7" }, "devDependencies": { @@ -341,65 +342,28 @@ } }, "node_modules/@aws-sdk/client-s3": { - "version": "3.1041.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1041.0.tgz", - "integrity": "sha512-sQV14bIqslnBHuSlLMD+fc3pH+ajop6vnrFlJ4wM4JDqcYwVik4O+9srnZUrkesFw5y+CN0GfOQ06CAgtC4mjQ==", + "version": "3.1053.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1053.0.tgz", + "integrity": "sha512-/oGxoB6p1Nqs935Blt+v1o+anSCEf2n3RjIrcLz84i4cn2Gr+Z7JpDdUkG5+74r5ctqEPG7k/phTGbJ9fNKnHg==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha1-browser": "5.2.0", "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.8", - "@aws-sdk/credential-provider-node": "^3.972.39", - "@aws-sdk/middleware-bucket-endpoint": "^3.972.10", - "@aws-sdk/middleware-expect-continue": "^3.972.10", - "@aws-sdk/middleware-flexible-checksums": "^3.974.16", - "@aws-sdk/middleware-host-header": "^3.972.10", - "@aws-sdk/middleware-location-constraint": "^3.972.10", - "@aws-sdk/middleware-logger": "^3.972.10", - "@aws-sdk/middleware-recursion-detection": "^3.972.11", - "@aws-sdk/middleware-sdk-s3": "^3.972.37", - "@aws-sdk/middleware-ssec": "^3.972.10", - "@aws-sdk/middleware-user-agent": "^3.972.38", - "@aws-sdk/region-config-resolver": "^3.972.13", - "@aws-sdk/signature-v4-multi-region": "^3.996.25", - "@aws-sdk/types": "^3.973.8", - "@aws-sdk/util-endpoints": "^3.996.8", - "@aws-sdk/util-user-agent-browser": "^3.972.10", - "@aws-sdk/util-user-agent-node": "^3.973.24", - "@smithy/config-resolver": "^4.4.17", - "@smithy/core": "^3.23.17", - "@smithy/eventstream-serde-browser": "^4.2.14", - "@smithy/eventstream-serde-config-resolver": "^4.3.14", - "@smithy/eventstream-serde-node": "^4.2.14", - "@smithy/fetch-http-handler": "^5.3.17", - "@smithy/hash-blob-browser": "^4.2.15", - "@smithy/hash-node": "^4.2.14", - "@smithy/hash-stream-node": "^4.2.14", - "@smithy/invalid-dependency": "^4.2.14", - "@smithy/md5-js": "^4.2.14", - "@smithy/middleware-content-length": "^4.2.14", - "@smithy/middleware-endpoint": "^4.4.32", - "@smithy/middleware-retry": "^4.5.7", - "@smithy/middleware-serde": "^4.2.20", - "@smithy/middleware-stack": "^4.2.14", - "@smithy/node-config-provider": "^4.3.14", - "@smithy/node-http-handler": "^4.6.1", - "@smithy/protocol-http": "^5.3.14", - "@smithy/smithy-client": "^4.12.13", - "@smithy/types": "^4.14.1", - "@smithy/url-parser": "^4.2.14", - "@smithy/util-base64": "^4.3.2", - "@smithy/util-body-length-browser": "^4.2.2", - "@smithy/util-body-length-node": "^4.2.3", - "@smithy/util-defaults-mode-browser": "^4.3.49", - "@smithy/util-defaults-mode-node": "^4.2.54", - "@smithy/util-endpoints": "^3.4.2", - "@smithy/util-middleware": "^4.2.14", - "@smithy/util-retry": "^4.3.6", - "@smithy/util-stream": "^4.5.25", - "@smithy/util-utf8": "^4.2.2", - "@smithy/util-waiter": "^4.3.0", + "@aws-sdk/core": "^3.974.13", + "@aws-sdk/credential-provider-node": "^3.972.44", + "@aws-sdk/middleware-bucket-endpoint": "^3.972.15", + "@aws-sdk/middleware-expect-continue": "^3.972.13", + "@aws-sdk/middleware-flexible-checksums": "^3.974.21", + "@aws-sdk/middleware-location-constraint": "^3.972.11", + "@aws-sdk/middleware-sdk-s3": "^3.972.42", + "@aws-sdk/middleware-ssec": "^3.972.11", + "@aws-sdk/signature-v4-multi-region": "^3.996.28", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/fetch-http-handler": "^5.4.3", + "@smithy/node-http-handler": "^4.7.3", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -407,24 +371,18 @@ } }, "node_modules/@aws-sdk/core": { - "version": "3.974.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.8.tgz", - "integrity": "sha512-njR2qoG6ZuB0kvAS2FyICsFZJ6gmCcf2X/7JcD14sUvGDm26wiZ5BrA6LOiUxKFEF+IVe7kdroxyE00YlkiYsw==", + "version": "3.974.13", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.13.tgz", + "integrity": "sha512-+Y5/4tHki0uYgyx8eun146DegRVQBpdKGK5RbV0FTKJPpaKTchvqVxrrRFK6Wk0JksO4iAZKw3eqxGEIwtO98w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.8", - "@aws-sdk/xml-builder": "^3.972.22", - "@smithy/core": "^3.23.17", - "@smithy/node-config-provider": "^4.3.14", - "@smithy/property-provider": "^4.2.14", - "@smithy/protocol-http": "^5.3.14", - "@smithy/signature-v4": "^5.3.14", - "@smithy/smithy-client": "^4.12.13", - "@smithy/types": "^4.14.1", - "@smithy/util-base64": "^4.3.2", - "@smithy/util-middleware": "^4.2.14", - "@smithy/util-retry": "^4.3.6", - "@smithy/util-utf8": "^4.2.2", + "@aws-sdk/types": "^3.973.9", + "@aws-sdk/xml-builder": "^3.972.25", + "@aws/lambda-invoke-store": "^0.2.2", + "@smithy/core": "^3.24.3", + "@smithy/signature-v4": "^5.4.2", + "@smithy/types": "^4.14.2", + "bowser": "^2.11.0", "tslib": "^2.6.2" }, "engines": { @@ -432,12 +390,12 @@ } }, "node_modules/@aws-sdk/crc64-nvme": { - "version": "3.972.7", - "resolved": "https://registry.npmjs.org/@aws-sdk/crc64-nvme/-/crc64-nvme-3.972.7.tgz", - "integrity": "sha512-QUagVVBbC8gODCF6e1aV0mE2TXWB9Opz4k8EJFdNrujUVQm5R4AjJa1mpOqzwOuROBzqJU9zawzig7M96L8Ejg==", + "version": "3.972.9", + "resolved": "https://registry.npmjs.org/@aws-sdk/crc64-nvme/-/crc64-nvme-3.972.9.tgz", + "integrity": "sha512-P+QGozmXn2mZZI7sDgk+aUm+RTI61MPSFB+Ir2vjEjEbEsE4e7hYtzrDvAUxZy9ko81h53e11+F/GYlvwDkaOQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.14.1", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -445,15 +403,15 @@ } }, "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.34", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.34.tgz", - "integrity": "sha512-XT0jtf8Fw9JE6ppsQeoNnZRiG+jqRixMT1v1ZR17G60UvVdsQmTG8nbEyHuEPfMxDXEhfdARaM/XiEhca4lGHQ==", + "version": "3.972.39", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.39.tgz", + "integrity": "sha512-29wX9zpAvEt1vcj0psha+y6ygBHy2V/S72mp6e7q0KARLWXq+pwE/lR6qGkwknQvruh52lXvlqZIga8Hdxkucw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.8", - "@aws-sdk/types": "^3.973.8", - "@smithy/property-provider": "^4.2.14", - "@smithy/types": "^4.14.1", + "@aws-sdk/core": "^3.974.13", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -461,20 +419,17 @@ } }, "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.36", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.36.tgz", - "integrity": "sha512-DPoGWfy7J7RKxvbf5kOKIGQkD2ek3dbKgzKIGrnLuvZBz5myU+Im/H6pmc14QcnFbqHMqxvtWSgRDSJW3qXLQg==", + "version": "3.972.41", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.41.tgz", + "integrity": "sha512-IA3CQTjtJkb6u1H4mE4936c8OPBMa9Jggtwe8U2Mqw/vvb/tZ5Ebd0mcZcX0uKWQhOyYo/+qNIwkV5Xh+FeJJA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.8", - "@aws-sdk/types": "^3.973.8", - "@smithy/fetch-http-handler": "^5.3.17", - "@smithy/node-http-handler": "^4.6.1", - "@smithy/property-provider": "^4.2.14", - "@smithy/protocol-http": "^5.3.14", - "@smithy/smithy-client": "^4.12.13", - "@smithy/types": "^4.14.1", - "@smithy/util-stream": "^4.5.25", + "@aws-sdk/core": "^3.974.13", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/fetch-http-handler": "^5.4.3", + "@smithy/node-http-handler": "^4.7.3", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -482,24 +437,23 @@ } }, "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.972.38", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.38.tgz", - "integrity": "sha512-oDzUBu2MGJFgoar05sPMCwSrhw44ASyccrHzj66vO69OZqi7I6hZZxXfuPLC8OCzW7C+sU+bI73XHij41yekgQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.8", - "@aws-sdk/credential-provider-env": "^3.972.34", - "@aws-sdk/credential-provider-http": "^3.972.36", - "@aws-sdk/credential-provider-login": "^3.972.38", - "@aws-sdk/credential-provider-process": "^3.972.34", - "@aws-sdk/credential-provider-sso": "^3.972.38", - "@aws-sdk/credential-provider-web-identity": "^3.972.38", - "@aws-sdk/nested-clients": "^3.997.6", - "@aws-sdk/types": "^3.973.8", - "@smithy/credential-provider-imds": "^4.2.14", - "@smithy/property-provider": "^4.2.14", - "@smithy/shared-ini-file-loader": "^4.4.9", - "@smithy/types": "^4.14.1", + "version": "3.972.43", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.43.tgz", + "integrity": "sha512-4mzII+3mZEVXXE1xzrLQrCJL7/r62A63bA6SVzZoNL5rqCJghpf+xgGltVrIBBs0n+mOZBKrQl2tRREtvZ5l6A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.13", + "@aws-sdk/credential-provider-env": "^3.972.39", + "@aws-sdk/credential-provider-http": "^3.972.41", + "@aws-sdk/credential-provider-login": "^3.972.43", + "@aws-sdk/credential-provider-process": "^3.972.39", + "@aws-sdk/credential-provider-sso": "^3.972.43", + "@aws-sdk/credential-provider-web-identity": "^3.972.43", + "@aws-sdk/nested-clients": "^3.997.11", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/credential-provider-imds": "^4.3.2", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -507,18 +461,16 @@ } }, "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.38", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.38.tgz", - "integrity": "sha512-g1NosS8qe4OF++G2UFCM5ovSkgipC7YYor5KCWatG0UoMSO5YFj9C8muePlyVmOBV/WTI16Jo3/s1NUo/o1Bww==", + "version": "3.972.43", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.43.tgz", + "integrity": "sha512-HG7kQCwXtbv3oBV61Ins0oNX8KKyvrMqqRkb6ZiAfQHbMuHaiNaEb2KnpKLPkNpqImSBK82UkVE/kaY6IfWikA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.8", - "@aws-sdk/nested-clients": "^3.997.6", - "@aws-sdk/types": "^3.973.8", - "@smithy/property-provider": "^4.2.14", - "@smithy/protocol-http": "^5.3.14", - "@smithy/shared-ini-file-loader": "^4.4.9", - "@smithy/types": "^4.14.1", + "@aws-sdk/core": "^3.974.13", + "@aws-sdk/nested-clients": "^3.997.11", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -526,22 +478,21 @@ } }, "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.39", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.39.tgz", - "integrity": "sha512-HEswDQyxUtadoZ/bJsPPENHg7R0Lzym5LuMksJeHvqhCOpP+rtkDLKI4/ZChH4w3cf5kG8n6bZuI8PzajoiqMg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.34", - "@aws-sdk/credential-provider-http": "^3.972.36", - "@aws-sdk/credential-provider-ini": "^3.972.38", - "@aws-sdk/credential-provider-process": "^3.972.34", - "@aws-sdk/credential-provider-sso": "^3.972.38", - "@aws-sdk/credential-provider-web-identity": "^3.972.38", - "@aws-sdk/types": "^3.973.8", - "@smithy/credential-provider-imds": "^4.2.14", - "@smithy/property-provider": "^4.2.14", - "@smithy/shared-ini-file-loader": "^4.4.9", - "@smithy/types": "^4.14.1", + "version": "3.972.44", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.44.tgz", + "integrity": "sha512-sDaBIT0yrNNIPfvlsiTCmANm07zKju+ipWODjEXgZlsjMeIJR3LVp7RDyAOzUoAsTbDfYKDWp+i5WrFiQP6rmQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.39", + "@aws-sdk/credential-provider-http": "^3.972.41", + "@aws-sdk/credential-provider-ini": "^3.972.43", + "@aws-sdk/credential-provider-process": "^3.972.39", + "@aws-sdk/credential-provider-sso": "^3.972.43", + "@aws-sdk/credential-provider-web-identity": "^3.972.43", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/credential-provider-imds": "^4.3.2", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -549,16 +500,15 @@ } }, "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.34", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.34.tgz", - "integrity": "sha512-T3IFs4EVmVi1dVN5RciFnklCANSzvrQd/VuHY9ThHSQmYkTogjcGkoJEr+oNUPQZnso52183088NqysMPji1/Q==", + "version": "3.972.39", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.39.tgz", + "integrity": "sha512-2k/amBifLd75eXNwgvPw/2lKYSQ3NhvHQgkVKVjfUq13/eJ3JRtHmznuFenn74OK3sSfp4SMy1YB2w+UVXoKqA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.8", - "@aws-sdk/types": "^3.973.8", - "@smithy/property-provider": "^4.2.14", - "@smithy/shared-ini-file-loader": "^4.4.9", - "@smithy/types": "^4.14.1", + "@aws-sdk/core": "^3.974.13", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -566,18 +516,17 @@ } }, "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.972.38", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.38.tgz", - "integrity": "sha512-5ZxG+t0+3Q3QPh8KEjX6syskhgNf7I0MN7oGioTf6Lm1NTjfP7sIcYGNsthXC2qR8vcD3edNZwCr2ovfSSWuRA==", + "version": "3.972.43", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.43.tgz", + "integrity": "sha512-LPc3+Y4vhH1T4x6CMqwCM6hk5+SRf/Lwmgm8INm95wxTtIRHcMwQUVkDzWu4Iw/RSncxYM2BC01OrYbxOPZvyg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.8", - "@aws-sdk/nested-clients": "^3.997.6", - "@aws-sdk/token-providers": "3.1041.0", - "@aws-sdk/types": "^3.973.8", - "@smithy/property-provider": "^4.2.14", - "@smithy/shared-ini-file-loader": "^4.4.9", - "@smithy/types": "^4.14.1", + "@aws-sdk/core": "^3.974.13", + "@aws-sdk/nested-clients": "^3.997.11", + "@aws-sdk/token-providers": "3.1052.0", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -585,134 +534,101 @@ } }, "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.38", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.38.tgz", - "integrity": "sha512-lYHFF30DGI20jZcYX8cm6Ns0V7f1dDN6g/MBDLTyD/5iw+bXs3yBr2iAiHDkx4RFU5JgsnZvCHYKiRVPRdmOgw==", + "version": "3.972.43", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.43.tgz", + "integrity": "sha512-wQtL34lUD/09VXjwAUo2T+I3aEXRDxMB3DKmTJL/Zj0Gi6sLDTrVhae1XVt01yzkquOWajI/sZW72JGDZ1ciTw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.8", - "@aws-sdk/nested-clients": "^3.997.6", - "@aws-sdk/types": "^3.973.8", - "@smithy/property-provider": "^4.2.14", - "@smithy/shared-ini-file-loader": "^4.4.9", - "@smithy/types": "^4.14.1", + "@aws-sdk/core": "^3.974.13", + "@aws-sdk/nested-clients": "^3.997.11", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/middleware-bucket-endpoint": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.10.tgz", - "integrity": "sha512-Vbc2frZH7wXlMNd+ZZSXUEs/l1Sv8Jj4zUnIfwrYF5lwaLdXHZ9xx4U3rjUcaye3HRhFVc+E5DbBxpRAbB16BA==", + "node_modules/@aws-sdk/lib-storage": { + "version": "3.1053.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-storage/-/lib-storage-3.1053.0.tgz", + "integrity": "sha512-Y5fyrJ2Qln3lmU0I335no+zdyytpM7svvYOYadZiV2bXGDXEO26A8B+4iGW264GvBO4jnl/iPHVZ/hJIqXekAA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.8", - "@aws-sdk/util-arn-parser": "^3.972.3", - "@smithy/node-config-provider": "^4.3.14", - "@smithy/protocol-http": "^5.3.14", - "@smithy/types": "^4.14.1", - "@smithy/util-config-provider": "^4.2.2", + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "buffer": "5.6.0", + "events": "3.3.0", + "stream-browserify": "3.0.0", "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-expect-continue": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.10.tgz", - "integrity": "sha512-2Yn0f1Qiq/DjxYR3wfI3LokXnjOhFM7Ssn4LTdFDIxRMCE6I32MAsVnhPX1cUZsuVA9tiZtwwhlSLAtFGxAZlQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.8", - "@smithy/protocol-http": "^5.3.14", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-flexible-checksums": { - "version": "3.974.16", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.16.tgz", - "integrity": "sha512-6ru8doI0/XzszqLIPXf0E/V7HhAw1Pu94010XCKYtBUfD0LxF0BuOzrUf8OQGR6j2o6wgKTHUniOmndQycHwCA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/crc32": "5.2.0", - "@aws-crypto/crc32c": "5.2.0", - "@aws-crypto/util": "5.2.0", - "@aws-sdk/core": "^3.974.8", - "@aws-sdk/crc64-nvme": "^3.972.7", - "@aws-sdk/types": "^3.973.8", - "@smithy/is-array-buffer": "^4.2.2", - "@smithy/node-config-provider": "^4.3.14", - "@smithy/protocol-http": "^5.3.14", - "@smithy/types": "^4.14.1", - "@smithy/util-middleware": "^4.2.14", - "@smithy/util-stream": "^4.5.25", - "@smithy/util-utf8": "^4.2.2", - "tslib": "^2.6.2" }, - "engines": { - "node": ">=20.0.0" + "peerDependencies": { + "@aws-sdk/client-s3": "^3.1053.0" } }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.10.tgz", - "integrity": "sha512-IJSsIMeVQ8MMCPbuh1AbltkFhLBLXn7aejzfX5YKT/VLDHn++Dcz8886tXckE+wQssyPUhaXrJhdakO2VilRhg==", + "node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.972.15", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.972.15.tgz", + "integrity": "sha512-O2HDANa+MrvbxpaRVQDiH3T13uAa9AkMjKyZmDygwauAmmvqZ5B0iRmKW+fuVGW6NPXuyXurFgIx69lSvmAWGA==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.8", - "@smithy/protocol-http": "^5.3.14", - "@smithy/types": "^4.14.1", + "@aws-sdk/core": "^3.974.13", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/middleware-location-constraint": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.10.tgz", - "integrity": "sha512-rI3NZvJcEvjoD0+0PI0iUAwlPw2IlSlhyvgBK/3WkKJQE/YiKFedd9dMN2lVacdNxPNhxL/jzQaKQdrGtQagjQ==", + "node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.972.13", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.972.13.tgz", + "integrity": "sha512-sHiqIFg8o2ipT7t40B89Vj0ubSUtY6OSt/+Ee/OXhHch5K4+81zP2+QX8Lkc/nJ2QSmCySxOke7TEbmX69fe2g==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.8", - "@smithy/types": "^4.14.1", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.10.tgz", - "integrity": "sha512-OOuGvvz1Dm20SjZo5oEBePFqxt5nf8AwkNDSyUHvD9/bfNASmstcYxFAHUowy4n6Io7mWUZ04JURZwSBvyQanQ==", + "node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.974.21", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.974.21.tgz", + "integrity": "sha512-alAu9heyiBK/OmRNXVxq8mmPTgeW2AQ6EYjRsI38kPZa1MZvt2Jh+BlGq7/GG9OVXOaEgD7DlGj/Lzfy5OmuEg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.8", - "@smithy/types": "^4.14.1", + "@aws-crypto/crc32": "5.2.0", + "@aws-crypto/crc32c": "5.2.0", + "@aws-crypto/util": "5.2.0", + "@aws-sdk/core": "^3.974.13", + "@aws-sdk/crc64-nvme": "^3.972.9", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/middleware-recursion-detection": { + "node_modules/@aws-sdk/middleware-location-constraint": { "version": "3.972.11", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.11.tgz", - "integrity": "sha512-+zz6f79Kj9V5qFK2P+D8Ehjnw4AhphAlCAsPjUqEcInA9umtSSKMrHbSagEeOIsDNuvVrH98bjRHcyQukTrhaQ==", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.972.11.tgz", + "integrity": "sha512-hkfspNUP4criAH6ton6BGKgnm5dZx+7bUOy1YqlTfejDeUPAM23D81q/IX+hdlS3KUsfwGz5ADTqZWKBEUpf4A==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "^3.973.8", - "@aws/lambda-invoke-store": "^0.2.2", - "@smithy/protocol-http": "^5.3.14", - "@smithy/types": "^4.14.1", + "@aws-sdk/types": "^3.973.9", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -720,24 +636,17 @@ } }, "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.972.37", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.37.tgz", - "integrity": "sha512-Km7M+i8DrLArVzrid1gfxeGhYHBd3uxvE77g0s5a52zPSVosxzQBnJ0gwWb6NIp/DOk8gsBMhi7V+cpJG0ndTA==", + "version": "3.972.42", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.42.tgz", + "integrity": "sha512-/xNqNGXv9LaxZd25L9VV4pnSOw9OdDNO4rAHamM+h3KQBSITljIH9vk3dveGga1I2j36lQd0rdG3gjNEXvtNew==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.8", - "@aws-sdk/types": "^3.973.8", - "@aws-sdk/util-arn-parser": "^3.972.3", - "@smithy/core": "^3.23.17", - "@smithy/node-config-provider": "^4.3.14", - "@smithy/protocol-http": "^5.3.14", - "@smithy/signature-v4": "^5.3.14", - "@smithy/smithy-client": "^4.12.13", - "@smithy/types": "^4.14.1", - "@smithy/util-config-provider": "^4.2.2", - "@smithy/util-middleware": "^4.2.14", - "@smithy/util-stream": "^4.5.25", - "@smithy/util-utf8": "^4.2.2", + "@aws-sdk/core": "^3.974.13", + "@aws-sdk/signature-v4-multi-region": "^3.996.28", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/signature-v4": "^5.4.2", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -745,32 +654,13 @@ } }, "node_modules/@aws-sdk/middleware-ssec": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.10.tgz", - "integrity": "sha512-Gli9A0u8EVVb+5bFDGS/QbSVg28w/wpEidg1ggVcSj65BDTdGR6punsOcVjqdiu1i42WHWo51MCvARPIIz9juw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.8", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.972.38", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.38.tgz", - "integrity": "sha512-iz+B29TXcAZsJpwB+AwG/TTGA5l/VnmMZ2UxtiySOZjI6gCdmviXPwdgzcmuazMy16rXoPY4mYCGe7zdNKfx5A==", + "version": "3.972.11", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.972.11.tgz", + "integrity": "sha512-7PQvGNhtveKlvVqNahqWx5yrwxP7ecwAoB1dYBf8eKwfo2tzzCbNnW+q2nO3N066ktQaB4iBQbDRWtizm+amoQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.8", - "@aws-sdk/types": "^3.973.8", - "@aws-sdk/util-endpoints": "^3.996.8", - "@smithy/core": "^3.23.17", - "@smithy/protocol-http": "^5.3.14", - "@smithy/types": "^4.14.1", - "@smithy/util-retry": "^4.3.6", + "@aws-sdk/types": "^3.973.9", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -778,65 +668,20 @@ } }, "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.6", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.6.tgz", - "integrity": "sha512-WBDnqatJl+kGObpfmfSxqnXeYTu3Me8wx8WCtvoxX3pfWrrTv8I4WTMSSs7PZqcRcVh8WeUKMgGFjMG+52SR1w==", + "version": "3.997.11", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.11.tgz", + "integrity": "sha512-nWXXJ1r/r8N2Gw1pWolRgED38/A9A8DHR2ETWIv220zh4PZHcybbR4hUVWWktmNXTRHzDJwRluapHn0rZxuoqA==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.8", - "@aws-sdk/middleware-host-header": "^3.972.10", - "@aws-sdk/middleware-logger": "^3.972.10", - "@aws-sdk/middleware-recursion-detection": "^3.972.11", - "@aws-sdk/middleware-user-agent": "^3.972.38", - "@aws-sdk/region-config-resolver": "^3.972.13", - "@aws-sdk/signature-v4-multi-region": "^3.996.25", - "@aws-sdk/types": "^3.973.8", - "@aws-sdk/util-endpoints": "^3.996.8", - "@aws-sdk/util-user-agent-browser": "^3.972.10", - "@aws-sdk/util-user-agent-node": "^3.973.24", - "@smithy/config-resolver": "^4.4.17", - "@smithy/core": "^3.23.17", - "@smithy/fetch-http-handler": "^5.3.17", - "@smithy/hash-node": "^4.2.14", - "@smithy/invalid-dependency": "^4.2.14", - "@smithy/middleware-content-length": "^4.2.14", - "@smithy/middleware-endpoint": "^4.4.32", - "@smithy/middleware-retry": "^4.5.7", - "@smithy/middleware-serde": "^4.2.20", - "@smithy/middleware-stack": "^4.2.14", - "@smithy/node-config-provider": "^4.3.14", - "@smithy/node-http-handler": "^4.6.1", - "@smithy/protocol-http": "^5.3.14", - "@smithy/smithy-client": "^4.12.13", - "@smithy/types": "^4.14.1", - "@smithy/url-parser": "^4.2.14", - "@smithy/util-base64": "^4.3.2", - "@smithy/util-body-length-browser": "^4.2.2", - "@smithy/util-body-length-node": "^4.2.3", - "@smithy/util-defaults-mode-browser": "^4.3.49", - "@smithy/util-defaults-mode-node": "^4.2.54", - "@smithy/util-endpoints": "^3.4.2", - "@smithy/util-middleware": "^4.2.14", - "@smithy/util-retry": "^4.3.6", - "@smithy/util-utf8": "^4.2.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.972.13", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.13.tgz", - "integrity": "sha512-CvJ2ZIjK/jVD/lbOpowBVElJyC1YxLTIJ13yM0AEo0t2v7swOzGjSA6lJGH+DwZXQhcjUjoYwc8bVYCX5MDr1A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.8", - "@smithy/config-resolver": "^4.4.17", - "@smithy/node-config-provider": "^4.3.14", - "@smithy/types": "^4.14.1", + "@aws-sdk/core": "^3.974.13", + "@aws-sdk/signature-v4-multi-region": "^3.996.28", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/fetch-http-handler": "^5.4.3", + "@smithy/node-http-handler": "^4.7.3", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -863,16 +708,15 @@ } }, "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.25", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.25.tgz", - "integrity": "sha512-+CMIt3e1VzlklAECmG+DtP1sV8iKq25FuA0OKpnJ4KA0kxUtd7CgClY7/RU6VzJBQwbN4EJ9Ue6plvqx1qGadw==", + "version": "3.996.28", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.28.tgz", + "integrity": "sha512-qs9z5LqXO/CZC2Lg9SGKpoLU8Rhi+m2pFKZqfO9pytX1clc0katqtsDNupJxFy0xT9wsZSPzM2v1y+/H/zfp5Q==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/middleware-sdk-s3": "^3.972.37", - "@aws-sdk/types": "^3.973.8", - "@smithy/protocol-http": "^5.3.14", - "@smithy/signature-v4": "^5.3.14", - "@smithy/types": "^4.14.1", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/signature-v4": "^5.4.2", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -880,17 +724,16 @@ } }, "node_modules/@aws-sdk/token-providers": { - "version": "3.1041.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1041.0.tgz", - "integrity": "sha512-Th7kPI6YPtvJUcdznooXJMy+9rQWjmEF81LxaJssngBzuysK4a/x+l8kjm1zb7nYsUPbndnBdUnwng/3PLvtGw==", + "version": "3.1052.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1052.0.tgz", + "integrity": "sha512-QqZNB3so7UIDxZtroc85TQaLVxdZRFm0eWM1CSR2N+b06as9TOrilvrlTZuj3guYlxMs6yLOgGxnklJ5qMYtTw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "^3.974.8", - "@aws-sdk/nested-clients": "^3.997.6", - "@aws-sdk/types": "^3.973.8", - "@smithy/property-provider": "^4.2.14", - "@smithy/shared-ini-file-loader": "^4.4.9", - "@smithy/types": "^4.14.1", + "@aws-sdk/core": "^3.974.13", + "@aws-sdk/nested-clients": "^3.997.11", + "@aws-sdk/types": "^3.973.9", + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -898,40 +741,12 @@ } }, "node_modules/@aws-sdk/types": { - "version": "3.973.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.8.tgz", - "integrity": "sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/util-arn-parser": { - "version": "3.972.3", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.972.3.tgz", - "integrity": "sha512-HzSD8PMFrvgi2Kserxuff5VitNq2sgf3w9qxmskKDiDTThWfVteJxuCS9JXiPIPtmCrp+7N9asfIaVhBFORllA==", + "version": "3.973.9", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.9.tgz", + "integrity": "sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg==", "license": "Apache-2.0", "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.996.8", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.8.tgz", - "integrity": "sha512-oOZHcRDihk5iEe5V25NVWg45b3qEA8OpHWVdU/XQh8Zj4heVPAJqWvMphQnU7LkufmUo10EpvFPZuQMiFLJK3g==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.8", - "@smithy/types": "^4.14.1", - "@smithy/url-parser": "^4.2.14", - "@smithy/util-endpoints": "^3.4.2", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -965,52 +780,15 @@ "node": ">=20.0.0" } }, - "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.972.10", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.10.tgz", - "integrity": "sha512-FAzqXvfEssGdSIz8ejatan0bOdx1qefBWKF/gWmVBXIP1HkS7v/wjjaqrAGGKvyihrXTXW00/2/1nTJtxpXz7g==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.973.8", - "@smithy/types": "^4.14.1", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.973.24", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.24.tgz", - "integrity": "sha512-ZWwlkjcIp7cEL8ZfTpTAPNkwx25p7xol0xlKoWVVf22+nsjwmLcHYtTPjIV1cSpmB/b6DaK4cb1fSkvCXHgRdw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/middleware-user-agent": "^3.972.38", - "@aws-sdk/types": "^3.973.8", - "@smithy/node-config-provider": "^4.3.14", - "@smithy/types": "^4.14.1", - "@smithy/util-config-provider": "^4.2.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.22", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.22.tgz", - "integrity": "sha512-PMYKKtJd70IsSG0yHrdAbxBr+ZWBKLvzFZfD3/urxgf6hXVMzuU5M+3MJ5G67RpOmLBu1fAUN65SbWuKUCOlAA==", + "version": "3.972.25", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.25.tgz", + "integrity": "sha512-GH+Kjz4nPKWKHnsiQpnhP1MJdTGIcK4rAka6tzakgjjUkVgNsmPeEbbRAf09SzS1hjGu6duGHCBsxYke0BhHjQ==", "license": "Apache-2.0", "dependencies": { "@nodable/entities": "2.1.0", - "@smithy/types": "^4.14.1", - "fast-xml-parser": "5.7.2", + "@smithy/types": "^4.14.2", + "fast-xml-parser": "5.7.3", "tslib": "^2.6.2" }, "engines": { @@ -3489,242 +3267,62 @@ "dev": true, "license": "MIT" }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "15.3.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.3.2.tgz", - "integrity": "sha512-mrn35Jl2pCpns+mE3HaZa1yPN5EYCRgiMI+135COjr2hr8Cls9DXqIZ57vZe2cz7y2XVSq92tcs6kGQcT1J8Rw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.1" - } - }, - "node_modules/@smithy/chunked-blob-reader": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.2.2.tgz", - "integrity": "sha512-St+kVicSyayWQca+I1rGitaOEH6uKgE8IUWoYnnEX26SWdWQcL6LvMSD19Lg+vYHKdT9B2Zuu7rd3i6Wnyb/iw==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/chunked-blob-reader-native": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-4.2.3.tgz", - "integrity": "sha512-jA5k5Udn7Y5717L86h4EIv06wIr3xn8GM1qHRi/Nf31annXcXHJjBKvgztnbn2TxH3xWrPBfgwHsOwZf0UmQWw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-base64": "^4.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/config-resolver": { - "version": "4.4.17", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.17.tgz", - "integrity": "sha512-TzDZcAnhTyAHbXVxWZo7/tEcrIeFq20IBk8So3OLOetWpR8EwY/yEqBMBFaJMeyEiREDq4NfEl+qO3OAUD+vbQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.3.14", - "@smithy/types": "^4.14.1", - "@smithy/util-config-provider": "^4.2.2", - "@smithy/util-endpoints": "^3.4.2", - "@smithy/util-middleware": "^4.2.14", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/core": { - "version": "3.23.17", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.17.tgz", - "integrity": "sha512-x7BlLbUFL8NWCGjMF9C+1N5cVCxcPa7g6Tv9B4A2luWx3be3oU8hQ96wIwxe/s7OhIzvoJH73HAUSg5JXVlEtQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.3.14", - "@smithy/types": "^4.14.1", - "@smithy/url-parser": "^4.2.14", - "@smithy/util-base64": "^4.3.2", - "@smithy/util-body-length-browser": "^4.2.2", - "@smithy/util-middleware": "^4.2.14", - "@smithy/util-stream": "^4.5.25", - "@smithy/util-utf8": "^4.2.2", - "@smithy/uuid": "^1.1.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.14.tgz", - "integrity": "sha512-Au28zBN48ZAoXdooGUHemuVBrkE+Ie6RPmGNIAJsFqj33Vhb6xAgRifUydZ2aY+M+KaMAETAlKk5NC5h1G7wpg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.3.14", - "@smithy/property-provider": "^4.2.14", - "@smithy/types": "^4.14.1", - "@smithy/url-parser": "^4.2.14", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-codec": { - "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.14.tgz", - "integrity": "sha512-erZq0nOIpzfeZdCyzZjdJb4nVSKLUmSkaQUVkRGQTXs30gyUGeKnrYEg+Xe1W5gE3aReS7IgsvANwVPxSzY6Pw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^4.14.1", - "@smithy/util-hex-encoding": "^4.2.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-browser": { - "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.14.tgz", - "integrity": "sha512-8IelTCtTctWRbb+0Dcy+C0aICh1qa0qWXqgjcXDmMuCvPJRnv26hiDZoAau2ILOniki65mCPKqOQs/BaWvO4CQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/eventstream-serde-universal": "^4.2.14", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-config-resolver": { - "version": "4.3.14", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.14.tgz", - "integrity": "sha512-sqHiHpYRYo3FJlaIxD1J8PhbcmJAm7IuM16mVnwSkCToD7g00IBZzKuiLNMGmftULmEUX6/UAz8/NN5uMP8bVA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-node": { - "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.14.tgz", - "integrity": "sha512-Ht/8BuGlKfFTy0H3+8eEu0vdpwGztCnaLLXtpXNdQqiR7Hj4vFScU3T436vRAjATglOIPjJXronY+1WxxNLSiw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/eventstream-serde-universal": "^4.2.14", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-universal": { - "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.14.tgz", - "integrity": "sha512-lWyt4T2XQZUZgK3tQ3Wn0w3XBvZsK/vjTuJl6bXbnGZBHH0ZUSONTYiK9TgjTTzU54xQr3DRFwpjmhp0oLm3gg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/eventstream-codec": "^4.2.14", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "5.3.17", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.17.tgz", - "integrity": "sha512-bXOvQzaSm6MnmLaWA1elgfQcAtN4UP3vXqV97bHuoOrHQOJiLT3ds6o9eo5bqd0TJfRFpzdGnDQdW3FACiAVdw==", - "license": "Apache-2.0", + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@smithy/protocol-http": "^5.3.14", - "@smithy/querystring-builder": "^4.2.14", - "@smithy/types": "^4.14.1", - "@smithy/util-base64": "^4.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "type-detect": "4.0.8" } }, - "node_modules/@smithy/hash-blob-browser": { - "version": "4.2.15", - "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.15.tgz", - "integrity": "sha512-0PJ4Al3fg2nM4qKrAIxyNcApgqHAXcBkN8FeizOz69z0rb26uZ6lMESYtxegaTlXB5Hj84JfwMPavMrwDMjucA==", - "license": "Apache-2.0", + "node_modules/@sinonjs/fake-timers": { + "version": "15.3.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.3.2.tgz", + "integrity": "sha512-mrn35Jl2pCpns+mE3HaZa1yPN5EYCRgiMI+135COjr2hr8Cls9DXqIZ57vZe2cz7y2XVSq92tcs6kGQcT1J8Rw==", + "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@smithy/chunked-blob-reader": "^5.2.2", - "@smithy/chunked-blob-reader-native": "^4.2.3", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" + "@sinonjs/commons": "^3.0.1" } }, - "node_modules/@smithy/hash-node": { - "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.14.tgz", - "integrity": "sha512-8ZBDY2DD4wr+GGjTpPtiglEsqr0lUP+KHqgZcWczFf6qeZ/YRjMIOoQWVQlmwu7EtxKTd8YXD8lblmYcpBIA1g==", + "node_modules/@smithy/core": { + "version": "3.24.4", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.24.4.tgz", + "integrity": "sha512-3UNRKEyQyAgVgM0LGlerCLm+ChZWZ1GPfde+jBEW6bm6bSBGU1p0EbblaUV3unbhwvidjLA5Zs3sOs7mnZwvAw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.14.1", - "@smithy/util-buffer-from": "^4.2.2", - "@smithy/util-utf8": "^4.2.2", + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@smithy/hash-stream-node": { - "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.14.tgz", - "integrity": "sha512-tw4GANWkZPb6+BdD4Fgucqzey2+r73Z/GRo9zklsCdwrnxxumUV83ZIaBDdudV4Ylazw3EPTiJZhpX42105ruQ==", + "node_modules/@smithy/credential-provider-imds": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.3.4.tgz", + "integrity": "sha512-vKW0MEFRU4Y3MkVZUkpJm+g9qyPGLCXhc0YLggUdSdBB4g7IaSSsCE75P9rBXyWHrXY1UYSQUl8/DwsTR7QciA==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.14.1", - "@smithy/util-utf8": "^4.2.2", + "@smithy/core": "^3.24.4", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, - "node_modules/@smithy/invalid-dependency": { - "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.14.tgz", - "integrity": "sha512-c21qJiTSb25xvvOp+H2TNZzPCngrvl5vIPqPB8zQ/DmJF4QWXO19x1dWfMJZ6wZuuWUPPm0gV8C0cU3+ifcWuw==", + "node_modules/@smithy/fetch-http-handler": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.4.4.tgz", + "integrity": "sha512-qM7AUKI4G6d7lNgaZD3lA1tWSolh5r6gcixfTZAPstVURfjIbvreVTPz+994M0yC3HbX4YYhDRgr31Xy3XwWOQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.14.1", + "@smithy/core": "^3.24.4", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -3743,34 +3341,6 @@ "node": ">=18.0.0" } }, - "node_modules/@smithy/md5-js": { - "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.14.tgz", - "integrity": "sha512-V2v0vx+h0iUSNG1Alt+GNBMSLGCrl9iVsdd+Ap67HPM9PN479x12V8LkuMoKImNZxn3MXeuyUjls+/7ZACZghA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.14.1", - "@smithy/util-utf8": "^4.2.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/middleware-content-length": { - "version": "4.2.14", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.14.tgz", - "integrity": "sha512-xhHq7fX4/3lv5NHxLUk3OeEvl0xZ+Ek3qIbWaCL4f9JwgDZEclPBElljaZCAItdGPQl/kSM4LPMOpy1MYgprpw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^5.3.14", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@smithy/middleware-endpoint": { "version": "4.4.32", "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.32.tgz", @@ -3790,27 +3360,6 @@ "node": ">=18.0.0" } }, - "node_modules/@smithy/middleware-retry": { - "version": "4.5.7", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.5.7.tgz", - "integrity": "sha512-bRt6ZImqVSeTk39Nm81K20ObIiAZ3WefY7G6+iz/0tZjs4dgRRjvRX2sgsH+zi6iDCRR/aQvQofLKxxz4rPBZg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.23.17", - "@smithy/node-config-provider": "^4.3.14", - "@smithy/protocol-http": "^5.3.14", - "@smithy/service-error-classification": "^4.3.1", - "@smithy/smithy-client": "^4.12.13", - "@smithy/types": "^4.14.1", - "@smithy/util-middleware": "^4.2.14", - "@smithy/util-retry": "^4.3.6", - "@smithy/uuid": "^1.1.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@smithy/middleware-serde": { "version": "4.2.20", "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.20.tgz", @@ -3855,14 +3404,13 @@ } }, "node_modules/@smithy/node-http-handler": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.6.1.tgz", - "integrity": "sha512-iB+orM4x3xrr57X3YaXazfKnntl0LHlZB1kcXSGzMV1Tt0+YwEjGlbjk/44qEGtBzXAz6yFDzkYTKSV6Pj2HUg==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.7.4.tgz", + "integrity": "sha512-HIeF+1vrDGzPkkv39Hj2vlHSXHY3p958jd/8ZnePIY6+ZOsQX8coyEUKO5yQu4r0bQIVsbpotVIrXXwyycMStQ==", "license": "Apache-2.0", "dependencies": { - "@smithy/protocol-http": "^5.3.14", - "@smithy/querystring-builder": "^4.2.14", - "@smithy/types": "^4.14.1", + "@smithy/core": "^3.24.4", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -3922,18 +3470,6 @@ "node": ">=18.0.0" } }, - "node_modules/@smithy/service-error-classification": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.3.1.tgz", - "integrity": "sha512-aUQuDGh760ts/8MU+APjIZhlLPKhIIfqyzZaJikLEIMrdxFvxuLYD0WxWzaYWpmLbQlXDe9p7EWM3HsBe0K6Gw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.14.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@smithy/shared-ini-file-loader": { "version": "4.4.9", "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.9.tgz", @@ -3948,18 +3484,13 @@ } }, "node_modules/@smithy/signature-v4": { - "version": "5.3.14", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.14.tgz", - "integrity": "sha512-1D9Y/nmlVjCeSivCbhZ7hgEpmHyY1h0GvpSZt3l0xcD9JjmjVC1CHOozS6+Gh+/ldMH8JuJ6cujObQqfayAVFA==", + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.4.4.tgz", + "integrity": "sha512-e5UtkMvsatzBfbeBZjEOt0k0Z3BEsjTFL/n6fdO5vtBLe67tdy0dX7xw2DU7uZ3acwoHyeCqpU2Fzb7pxwHb6Q==", "license": "Apache-2.0", "dependencies": { - "@smithy/is-array-buffer": "^4.2.2", - "@smithy/protocol-http": "^5.3.14", - "@smithy/types": "^4.14.1", - "@smithy/util-hex-encoding": "^4.2.2", - "@smithy/util-middleware": "^4.2.14", - "@smithy/util-uri-escape": "^4.2.2", - "@smithy/util-utf8": "^4.2.2", + "@smithy/core": "^3.24.4", + "@smithy/types": "^4.14.2", "tslib": "^2.6.2" }, "engines": { @@ -3985,9 +3516,9 @@ } }, "node_modules/@smithy/types": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.1.tgz", - "integrity": "sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg==", + "version": "4.14.2", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.2.tgz", + "integrity": "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -4024,30 +3555,6 @@ "node": ">=18.0.0" } }, - "node_modules/@smithy/util-body-length-browser": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.2.tgz", - "integrity": "sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-body-length-node": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.3.tgz", - "integrity": "sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@smithy/util-buffer-from": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.2.tgz", @@ -4061,65 +3568,6 @@ "node": ">=18.0.0" } }, - "node_modules/@smithy/util-config-provider": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.2.tgz", - "integrity": "sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.3.49", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.49.tgz", - "integrity": "sha512-a5bNrdiONYB/qE2BuKegvUMd/+ZDwdg4vsNuuSzYE8qs2EYAdK9CynL+Rzn29PbPiUqoz/cbpRbcLzD5lEevHw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/property-provider": "^4.2.14", - "@smithy/smithy-client": "^4.12.13", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.2.54", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.54.tgz", - "integrity": "sha512-g1cvrJvOnzeJgEdf7AE4luI7gp6L8weE0y9a9wQUSGtjb8QRHDbCJYuE4Sy0SD9N8RrnNPFsPltAz/OSoBR9Zw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/config-resolver": "^4.4.17", - "@smithy/credential-provider-imds": "^4.2.14", - "@smithy/node-config-provider": "^4.3.14", - "@smithy/property-provider": "^4.2.14", - "@smithy/smithy-client": "^4.12.13", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-endpoints": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.4.2.tgz", - "integrity": "sha512-a55Tr+3OKld4TTtnT+RhKOQHyPxm3j/xL4OR83WBUhLJaKDS9dnJ7arRMOp3t31dcLhApwG9bgvrRXBHlLdIkg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^4.3.14", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@smithy/util-hex-encoding": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.2.tgz", @@ -4145,20 +3593,6 @@ "node": ">=18.0.0" } }, - "node_modules/@smithy/util-retry": { - "version": "4.3.8", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.3.8.tgz", - "integrity": "sha512-LUIxbTBi+OpvXpg91poGA6BdyoleMDLnfXjVDqyi2RvZmTveY5loE/FgYUBCR5LU2BThW2SoZRh8dTIIy38IPw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/service-error-classification": "^4.3.1", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@smithy/util-stream": { "version": "4.5.25", "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.25.tgz", @@ -4203,31 +3637,6 @@ "node": ">=18.0.0" } }, - "node_modules/@smithy/util-waiter": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.3.0.tgz", - "integrity": "sha512-JyjYmLAfS+pdxF92o4yLgEoy0zhayKTw73FU1aofLWwLcJw7iSqIY2exGmMTrl/lmZugP5p/zxdFSippJDfKWA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/uuid": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.2.tgz", - "integrity": "sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@stablelib/base64": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", @@ -5923,6 +5332,26 @@ "node": "18 || 20 || >=22" } }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/baseline-browser-mapping": { "version": "2.10.25", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.25.tgz", @@ -6082,6 +5511,16 @@ "node": ">=16.20.1" } }, + "node_modules/buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -7616,6 +7055,15 @@ "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "license": "MIT" }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -7837,9 +7285,9 @@ "license": "Unlicense" }, "node_modules/fast-xml-builder": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.5.tgz", - "integrity": "sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", + "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", "funding": [ { "type": "github", @@ -7848,13 +7296,14 @@ ], "license": "MIT", "dependencies": { - "path-expression-matcher": "^1.1.3" + "path-expression-matcher": "^1.5.0", + "xml-naming": "^0.1.0" } }, "node_modules/fast-xml-parser": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.2.tgz", - "integrity": "sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.3.tgz", + "integrity": "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg==", "funding": [ { "type": "github", @@ -7864,7 +7313,7 @@ "license": "MIT", "dependencies": { "@nodable/entities": "^2.1.0", - "fast-xml-builder": "^1.1.5", + "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, @@ -8565,6 +8014,26 @@ "url": "https://opencollective.com/express" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", @@ -13446,6 +12915,22 @@ "dev": true, "license": "MIT" }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-browserify/node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -13593,9 +13078,9 @@ } }, "node_modules/strnum": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.3.tgz", - "integrity": "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.3.0.tgz", + "integrity": "sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==", "funding": [ { "type": "github", @@ -14806,6 +14291,21 @@ } } }, + "node_modules/xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 17c00b25..d5113fa6 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "lint-staged": "^17.0.5" }, "dependencies": { + "@aws-sdk/lib-storage": "^3.1053.0", "path": "^0.12.7" }, "overrides": { From a18a81ba5a4bd2586633233ab303053f5d7c5f7e Mon Sep 17 00:00:00 2001 From: Renganath Chokkalingam Date: Wed, 27 May 2026 07:43:43 +0530 Subject: [PATCH 24/24] fix: CodeQL format string warning in export logger --- apps/dashboard-api/src/controllers/dbExport.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dashboard-api/src/controllers/dbExport.controller.js b/apps/dashboard-api/src/controllers/dbExport.controller.js index 7db26a1c..3cbc7b9d 100644 --- a/apps/dashboard-api/src/controllers/dbExport.controller.js +++ b/apps/dashboard-api/src/controllers/dbExport.controller.js @@ -54,7 +54,7 @@ module.exports.dbExportHandler = async (req, res, next) => { }); } catch (err) { - console.error(`[Dashboard API] Error handling export request for project ${req.params.projectId}:`, err); + console.error("[Dashboard API] Error handling export request for project - ", req.params.projectId, ": ", err); return next(new AppError(500, err.message || "Failed to initiate database export.")); } };