enh
This commit is contained in:
parent
639428caba
commit
1b042819af
18 changed files with 303 additions and 691 deletions
|
|
@ -1,13 +1,12 @@
|
||||||
import 'dotenv/config';
|
import 'dotenv/config';
|
||||||
import express, { NextFunction, Request, Response } from "express";
|
import { Hono } from 'hono';
|
||||||
import cors from "cors";
|
import { cors } from 'hono/cors';
|
||||||
// import bodyParser from "body-parser";
|
import { logger } from 'hono/logger';
|
||||||
import path from "path";
|
import { serve } from '@hono/node-server';
|
||||||
import fs from "fs";
|
import { trpcServer } from '@hono/trpc-server';
|
||||||
import { getStaffUserById, getUserDetailsByUserId, isUserSuspended } from '@/src/dbService';
|
import { getStaffUserById, isUserSuspended } from '@/src/dbService';
|
||||||
import mainRouter from '@/src/main-router';
|
import mainRouter from '@/src/main-router';
|
||||||
import initFunc from '@/src/lib/init';
|
import initFunc from '@/src/lib/init';
|
||||||
import { createExpressMiddleware } from '@trpc/server/adapters/express';
|
|
||||||
import { appRouter } from '@/src/trpc/router';
|
import { appRouter } from '@/src/trpc/router';
|
||||||
import { TRPCError } from '@trpc/server';
|
import { TRPCError } from '@trpc/server';
|
||||||
import { jwtVerify } from 'jose'
|
import { jwtVerify } from 'jose'
|
||||||
|
|
@ -21,57 +20,28 @@ seed()
|
||||||
initFunc()
|
initFunc()
|
||||||
startAutomatedJobs()
|
startAutomatedJobs()
|
||||||
|
|
||||||
const app = express();
|
const app = new Hono();
|
||||||
|
|
||||||
|
// CORS middleware
|
||||||
app.use(cors({
|
app.use(cors({
|
||||||
origin: 'http://localhost:5174'
|
origin: 'http://localhost:5174',
|
||||||
|
allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
|
||||||
|
allowHeaders: ['Origin', 'X-Requested-With', 'Content-Type', 'Accept', 'Authorization'],
|
||||||
|
credentials: true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
signedUrlCache.loadFromDisk();
|
signedUrlCache.loadFromDisk();
|
||||||
|
|
||||||
app.use(express.json());
|
// Logger middleware
|
||||||
app.use(express.urlencoded({ extended: true }));
|
app.use(logger());
|
||||||
|
|
||||||
// Middleware to log all request URLs
|
// tRPC middleware
|
||||||
app.use((req, res, next) => {
|
app.use('/api/trpc', trpcServer({
|
||||||
const timestamp = new Date().toISOString();
|
|
||||||
console.log(`[${timestamp}] ${req.method} ${req.url}`);
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
|
|
||||||
//cors middleware
|
|
||||||
export function corsMiddleware(req: Request, res: Response, next: NextFunction) {
|
|
||||||
// Allow requests from any origin (for production, replace * with your domain)
|
|
||||||
res.header('Access-Control-Allow-Origin', '*');
|
|
||||||
|
|
||||||
// Allow specific headers clients can send
|
|
||||||
res.header(
|
|
||||||
'Access-Control-Allow-Headers',
|
|
||||||
'Origin, X-Requested-With, Content-Type, Accept, Authorization'
|
|
||||||
);
|
|
||||||
|
|
||||||
// Allow specific HTTP methods
|
|
||||||
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH, DELETE, OPTIONS');
|
|
||||||
|
|
||||||
// Allow credentials if needed (optional)
|
|
||||||
// res.header('Access-Control-Allow-Credentials', 'true');
|
|
||||||
|
|
||||||
// Handle preflight (OPTIONS) requests quickly
|
|
||||||
if (req.method === 'OPTIONS') {
|
|
||||||
return res.sendStatus(204);
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
app.use('/api/trpc', createExpressMiddleware({
|
|
||||||
router: appRouter,
|
router: appRouter,
|
||||||
createContext: async ({ req, res }) => {
|
createContext: async ({ req }) => {
|
||||||
let user = null;
|
let user = null;
|
||||||
let staffUser = null;
|
let staffUser = null;
|
||||||
const authHeader = req.headers.authorization;
|
const authHeader = req.headers.get('authorization');
|
||||||
|
|
||||||
if (authHeader?.startsWith('Bearer ')) {
|
if (authHeader?.startsWith('Bearer ')) {
|
||||||
const token = authHeader.substring(7);
|
const token = authHeader.substring(7);
|
||||||
|
|
@ -85,7 +55,7 @@ app.use('/api/trpc', createExpressMiddleware({
|
||||||
const staff = await getStaffUserById(decoded.staffId);
|
const staff = await getStaffUserById(decoded.staffId);
|
||||||
|
|
||||||
if (staff) {
|
if (staff) {
|
||||||
user=staffUser
|
user = staffUser
|
||||||
staffUser = {
|
staffUser = {
|
||||||
id: staff.id,
|
id: staff.id,
|
||||||
name: staff.name,
|
name: staff.name,
|
||||||
|
|
@ -110,7 +80,7 @@ app.use('/api/trpc', createExpressMiddleware({
|
||||||
// Invalid token, both user and staffUser remain null
|
// Invalid token, both user and staffUser remain null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { req, res, user, staffUser };
|
return { req, user, staffUser };
|
||||||
},
|
},
|
||||||
onError({ error, path, type, ctx }) {
|
onError({ error, path, type, ctx }) {
|
||||||
console.error('🚨 tRPC Error :', {
|
console.error('🚨 tRPC Error :', {
|
||||||
|
|
@ -121,60 +91,53 @@ app.use('/api/trpc', createExpressMiddleware({
|
||||||
userId: ctx?.user?.userId,
|
userId: ctx?.user?.userId,
|
||||||
stack: error.stack,
|
stack: error.stack,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
app.use('/api', mainRouter)
|
// Mount main router
|
||||||
|
app.route('/api', mainRouter);
|
||||||
const fallbackUiDirCandidates = [
|
|
||||||
path.resolve(__dirname, '../fallback-ui/dist'),
|
|
||||||
path.resolve(__dirname, '../../fallback-ui/dist'),
|
|
||||||
path.resolve(process.cwd(), '../fallback-ui/dist'),
|
|
||||||
path.resolve(process.cwd(), './apps/fallback-ui/dist')
|
|
||||||
]
|
|
||||||
|
|
||||||
const fallbackUiDir =
|
|
||||||
fallbackUiDirCandidates.find((candidate) => fs.existsSync(candidate)) ??
|
|
||||||
fallbackUiDirCandidates[0]
|
|
||||||
|
|
||||||
|
|
||||||
const fallbackUiIndex = path.join(fallbackUiDir, 'index.html')
|
|
||||||
// const fallbackUiMountPath = '/admin-web'
|
|
||||||
const fallbackUiMountPath = '/';
|
|
||||||
|
|
||||||
if (fs.existsSync(fallbackUiIndex)) {
|
|
||||||
app.use(fallbackUiMountPath, express.static(fallbackUiDir))
|
|
||||||
app.use('/mf'+fallbackUiMountPath, express.static(fallbackUiDir))
|
|
||||||
const fallbackUiRegex = new RegExp(
|
|
||||||
`^${fallbackUiMountPath.replace(/\//g, '\\/')}(?:\\/.*)?$`
|
|
||||||
)
|
|
||||||
app.get([fallbackUiMountPath, fallbackUiRegex], (req, res) => {
|
|
||||||
res.sendFile(fallbackUiIndex)
|
|
||||||
})
|
|
||||||
app.get(/.*/, (req,res) => {
|
|
||||||
res.sendFile(fallbackUiIndex)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
console.warn(`Fallback UI build not found at ${fallbackUiIndex}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Serve /assets/public folder at /assets route
|
|
||||||
const assetsPublicDir = path.resolve(__dirname, './assets/public');
|
|
||||||
if (fs.existsSync(assetsPublicDir)) {
|
|
||||||
app.use('/assets', express.static(assetsPublicDir));
|
|
||||||
console.log('Serving /assets from', assetsPublicDir);
|
|
||||||
} else {
|
|
||||||
console.warn('Assets public folder not found at', assetsPublicDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Global error handler
|
// Global error handler
|
||||||
app.use((err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
|
app.onError((err, c) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
const status = err.statusCode || err.status || 500;
|
// Handle different error types
|
||||||
const message = err.message || 'Internal Server Error';
|
let status = 500;
|
||||||
res.status(status).json({ message });
|
let message = 'Internal Server Error';
|
||||||
|
|
||||||
|
if (err instanceof TRPCError) {
|
||||||
|
// Map TRPC error codes to HTTP status codes
|
||||||
|
const trpcStatusMap: Record<string, number> = {
|
||||||
|
'BAD_REQUEST': 400,
|
||||||
|
'UNAUTHORIZED': 401,
|
||||||
|
'FORBIDDEN': 403,
|
||||||
|
'NOT_FOUND': 404,
|
||||||
|
'TIMEOUT': 408,
|
||||||
|
'CONFLICT': 409,
|
||||||
|
'PRECONDITION_FAILED': 412,
|
||||||
|
'PAYLOAD_TOO_LARGE': 413,
|
||||||
|
'METHOD_NOT_SUPPORTED': 405,
|
||||||
|
'UNPROCESSABLE_CONTENT': 422,
|
||||||
|
'TOO_MANY_REQUESTS': 429,
|
||||||
|
'INTERNAL_SERVER_ERROR': 500,
|
||||||
|
};
|
||||||
|
status = trpcStatusMap[err.code] || 500;
|
||||||
|
message = err.message;
|
||||||
|
} else if ((err as any).statusCode) {
|
||||||
|
status = (err as any).statusCode;
|
||||||
|
message = err.message;
|
||||||
|
} else if ((err as any).status) {
|
||||||
|
status = (err as any).status;
|
||||||
|
message = err.message;
|
||||||
|
} else if (err.message) {
|
||||||
|
message = err.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.json({ message }, status as any);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.listen(4000, () => {
|
serve({
|
||||||
console.log("Server is running on http://localhost:4000/api/mobile/");
|
fetch: app.fetch,
|
||||||
|
port: 4000,
|
||||||
|
}, (info) => {
|
||||||
|
console.log(`Server is running on http://localhost:${info.port}/api/mobile/`);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -20,23 +20,22 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.888.0",
|
"@aws-sdk/client-s3": "^3.888.0",
|
||||||
"@aws-sdk/s3-request-presigner": "^3.888.0",
|
"@aws-sdk/s3-request-presigner": "^3.888.0",
|
||||||
|
"@hono/node-server": "^1.19.11",
|
||||||
|
"@hono/trpc-server": "^0.4.2",
|
||||||
"@trpc/server": "^11.6.0",
|
"@trpc/server": "^11.6.0",
|
||||||
"@turf/turf": "^7.2.0",
|
"@turf/turf": "^7.2.0",
|
||||||
"@types/bcryptjs": "^2.4.6",
|
"@types/bcryptjs": "^2.4.6",
|
||||||
"@types/cors": "^2.8.19",
|
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.11.0",
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
"cors": "^2.8.5",
|
|
||||||
"dayjs": "^1.11.18",
|
"dayjs": "^1.11.18",
|
||||||
"dotenv": "^17.2.1",
|
"dotenv": "^17.2.1",
|
||||||
"expo-server-sdk": "^4.0.0",
|
"expo-server-sdk": "^4.0.0",
|
||||||
"express": "^5.1.0",
|
|
||||||
"fuse.js": "^7.1.0",
|
"fuse.js": "^7.1.0",
|
||||||
|
"hono": "^4.12.9",
|
||||||
"jose": "^6.2.2",
|
"jose": "^6.2.2",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^5.0.3",
|
|
||||||
"@types/node": "^24.5.2",
|
"@types/node": "^24.5.2",
|
||||||
"rimraf": "^6.1.2",
|
"rimraf": "^6.1.2",
|
||||||
"ts-node-dev": "^2.0.0",
|
"ts-node-dev": "^2.0.0",
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { Router } from "express";
|
import { Hono } from 'hono';
|
||||||
import { authenticateStaff } from "@/src/middleware/staff-auth";
|
import { authenticateStaff } from "@/src/middleware/staff-auth";
|
||||||
|
|
||||||
const router = Router();
|
const router = new Hono();
|
||||||
|
|
||||||
// Apply staff authentication to all admin routes
|
// Apply staff authentication to all admin routes
|
||||||
router.use(authenticateStaff);
|
router.use('*', authenticateStaff);
|
||||||
|
|
||||||
const avRouter = router;
|
const avRouter = router;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Request, Response } from "express";
|
import { Context } from 'hono';
|
||||||
import {
|
import {
|
||||||
checkProductExistsByName,
|
checkProductExistsByName,
|
||||||
checkUnitExists,
|
checkUnitExists,
|
||||||
|
|
@ -25,8 +25,9 @@ type CreateDeal = {
|
||||||
/**
|
/**
|
||||||
* Create a new product
|
* Create a new product
|
||||||
*/
|
*/
|
||||||
export const createProduct = async (req: Request, res: Response) => {
|
export const createProduct = async (c: Context) => {
|
||||||
const { name, shortDescription, longDescription, unitId, storeId, price, marketPrice, incrementStep, productQuantity, isSuspended, isFlashAvailable, flashPrice, deals, tagIds } = req.body;
|
const body = await c.req.parseBody({ all: true });
|
||||||
|
const { name, shortDescription, longDescription, unitId, storeId, price, marketPrice, incrementStep, productQuantity, isSuspended, isFlashAvailable, flashPrice, deals, tagIds } = body;
|
||||||
|
|
||||||
// Validate required fields
|
// Validate required fields
|
||||||
if (!name || !unitId || !storeId || !price) {
|
if (!name || !unitId || !storeId || !price) {
|
||||||
|
|
@ -34,100 +35,111 @@ export const createProduct = async (req: Request, res: Response) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for duplicate name
|
// Check for duplicate name
|
||||||
const existingProduct = await checkProductExistsByName(name.trim())
|
const existingProduct = await checkProductExistsByName((name as string).trim())
|
||||||
|
|
||||||
if (existingProduct) {
|
if (existingProduct) {
|
||||||
throw new ApiError("A product with this name already exists", 400);
|
throw new ApiError("A product with this name already exists", 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if unit exists
|
// Check if unit exists
|
||||||
const unitExists = await checkUnitExists(unitId)
|
const unitExists = await checkUnitExists(parseInt(unitId as string))
|
||||||
|
|
||||||
if (!unitExists) {
|
if (!unitExists) {
|
||||||
throw new ApiError("Invalid unit ID", 400);
|
throw new ApiError("Invalid unit ID", 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract images from req.files
|
// Extract images from body
|
||||||
const images = (req.files as Express.Multer.File[])?.filter(item => item.fieldname === 'images');
|
const images = body.images;
|
||||||
let uploadedImageUrls: string[] = [];
|
let uploadedImageUrls: string[] = [];
|
||||||
|
|
||||||
if (images && Array.isArray(images)) {
|
if (images) {
|
||||||
const imageUploadPromises = images.map((file, index) => {
|
const imageFiles = Array.isArray(images) ? images : [images];
|
||||||
|
const imageUploadPromises = imageFiles.map((file, index) => {
|
||||||
|
if (file instanceof File) {
|
||||||
const key = `product-images/${Date.now()}-${index}`;
|
const key = `product-images/${Date.now()}-${index}`;
|
||||||
return imageUploadS3(file.buffer, file.mimetype, key);
|
return imageUploadS3(Buffer.from(file.stream() as any), file.type, key);
|
||||||
});
|
}
|
||||||
|
return null;
|
||||||
|
}).filter(Boolean);
|
||||||
|
|
||||||
uploadedImageUrls = await Promise.all(imageUploadPromises);
|
uploadedImageUrls = await Promise.all(imageUploadPromises as Promise<string>[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create product
|
// Create product
|
||||||
const productData: any = {
|
const productData: any = {
|
||||||
name,
|
name: name as string,
|
||||||
shortDescription,
|
shortDescription: shortDescription as string | undefined,
|
||||||
longDescription,
|
longDescription: longDescription as string | undefined,
|
||||||
unitId,
|
unitId: parseInt(unitId as string),
|
||||||
storeId,
|
storeId: parseInt(storeId as string),
|
||||||
price,
|
price: parseFloat(price as string),
|
||||||
marketPrice,
|
marketPrice: marketPrice ? parseFloat(marketPrice as string) : null,
|
||||||
incrementStep: incrementStep || 1,
|
incrementStep: incrementStep ? parseInt(incrementStep as string) : 1,
|
||||||
productQuantity: productQuantity || 1,
|
productQuantity: productQuantity ? parseInt(productQuantity as string) : 1,
|
||||||
isSuspended: isSuspended || false,
|
isSuspended: isSuspended === 'true',
|
||||||
isFlashAvailable: isFlashAvailable || false,
|
isFlashAvailable: isFlashAvailable === 'true',
|
||||||
images: uploadedImageUrls,
|
images: uploadedImageUrls,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (flashPrice) {
|
if (flashPrice) {
|
||||||
productData.flashPrice = parseFloat(flashPrice);
|
productData.flashPrice = parseFloat(flashPrice as string);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newProduct = await createProductRecord(productData)
|
const newProduct = await createProductRecord(productData)
|
||||||
|
|
||||||
// Handle deals if provided
|
// Handle deals if provided
|
||||||
let createdDeals: AdminSpecialDeal[] = []
|
let createdDeals: AdminSpecialDeal[] = []
|
||||||
if (deals && Array.isArray(deals)) {
|
if (deals) {
|
||||||
createdDeals = await createSpecialDealsForProduct(newProduct.id, deals)
|
const parsedDeals = typeof deals === 'string' ? JSON.parse(deals) : deals;
|
||||||
|
if (Array.isArray(parsedDeals)) {
|
||||||
|
createdDeals = await createSpecialDealsForProduct(newProduct.id, parsedDeals)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle tag assignments if provided
|
// Handle tag assignments if provided
|
||||||
if (tagIds && Array.isArray(tagIds)) {
|
if (tagIds) {
|
||||||
await replaceProductTags(newProduct.id, tagIds)
|
const parsedTagIds = typeof tagIds === 'string' ? JSON.parse(tagIds) : tagIds;
|
||||||
|
if (Array.isArray(parsedTagIds)) {
|
||||||
|
await replaceProductTags(newProduct.id, parsedTagIds)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reinitialize stores to reflect changes
|
// Reinitialize stores to reflect changes
|
||||||
scheduleStoreInitialization()
|
scheduleStoreInitialization()
|
||||||
|
|
||||||
// Send response first
|
// Send response first
|
||||||
res.status(201).json({
|
return c.json({
|
||||||
product: newProduct,
|
product: newProduct,
|
||||||
deals: createdDeals,
|
deals: createdDeals,
|
||||||
message: "Product created successfully",
|
message: "Product created successfully",
|
||||||
});
|
}, 201);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update a product
|
* Update a product
|
||||||
*/
|
*/
|
||||||
export const updateProduct = async (req: Request, res: Response) => {
|
export const updateProduct = async (c: Context) => {
|
||||||
const id = req.params.id as string
|
const id = c.req.param('id')
|
||||||
const { name, shortDescription, longDescription, unitId, storeId, price, marketPrice, incrementStep, productQuantity, isSuspended, isFlashAvailable, flashPrice, deals:dealsRaw, imagesToDelete:imagesToDeleteRaw, tagIds } = req.body;
|
const body = await c.req.parseBody({ all: true });
|
||||||
|
const { name, shortDescription, longDescription, unitId, storeId, price, marketPrice, incrementStep, productQuantity, isSuspended, isFlashAvailable, flashPrice, deals:dealsRaw, imagesToDelete:imagesToDeleteRaw, tagIds } = body;
|
||||||
|
|
||||||
|
|
||||||
const deals = dealsRaw ? JSON.parse(dealsRaw) : null;
|
const deals = dealsRaw ? (typeof dealsRaw === 'string' ? JSON.parse(dealsRaw) : dealsRaw) : null;
|
||||||
const imagesToDelete = imagesToDeleteRaw ? JSON.parse(imagesToDeleteRaw) : [];
|
const imagesToDelete = imagesToDeleteRaw ? (typeof imagesToDeleteRaw === 'string' ? JSON.parse(imagesToDeleteRaw) : imagesToDeleteRaw) : [];
|
||||||
|
|
||||||
if (!name || !unitId || !storeId || !price) {
|
if (!name || !unitId || !storeId || !price) {
|
||||||
throw new ApiError("Name, unitId, storeId, and price are required", 400);
|
throw new ApiError("Name, unitId, storeId, and price are required", 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if unit exists
|
// Check if unit exists
|
||||||
const unitExists = await checkUnitExists(unitId)
|
const unitExists = await checkUnitExists(parseInt(unitId as string))
|
||||||
|
|
||||||
if (!unitExists) {
|
if (!unitExists) {
|
||||||
throw new ApiError("Invalid unit ID", 400);
|
throw new ApiError("Invalid unit ID", 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current product to handle image updates
|
// Get current product to handle image updates
|
||||||
const currentImages = await getProductImagesById(parseInt(id))
|
const currentImages = await getProductImagesById(parseInt(id as string))
|
||||||
|
|
||||||
if (!currentImages) {
|
if (!currentImages) {
|
||||||
throw new ApiError("Product not found", 404);
|
throw new ApiError("Product not found", 404);
|
||||||
|
|
@ -154,45 +166,49 @@ export const updateProduct = async (req: Request, res: Response) => {
|
||||||
updatedImages = updatedImages.filter(img => !imagesToRemoveFromDb.includes(img));
|
updatedImages = updatedImages.filter(img => !imagesToRemoveFromDb.includes(img));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract new images from req.files
|
// Extract new images from body
|
||||||
const images = (req.files as Express.Multer.File[])?.filter(item => item.fieldname === 'images');
|
const images = body.images;
|
||||||
let uploadedImageUrls: string[] = [];
|
let uploadedImageUrls: string[] = [];
|
||||||
|
|
||||||
if (images && Array.isArray(images)) {
|
if (images) {
|
||||||
const imageUploadPromises = images.map((file, index) => {
|
const imageFiles = Array.isArray(images) ? images : [images];
|
||||||
|
const imageUploadPromises = imageFiles.map((file, index) => {
|
||||||
|
if (file instanceof File) {
|
||||||
const key = `product-images/${Date.now()}-${index}`;
|
const key = `product-images/${Date.now()}-${index}`;
|
||||||
return imageUploadS3(file.buffer, file.mimetype, key);
|
return imageUploadS3(Buffer.from(file.stream() as any), file.type, key);
|
||||||
});
|
}
|
||||||
|
return null;
|
||||||
|
}).filter(Boolean);
|
||||||
|
|
||||||
uploadedImageUrls = await Promise.all(imageUploadPromises);
|
uploadedImageUrls = await Promise.all(imageUploadPromises as Promise<string>[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combine remaining current images with new uploaded images
|
// Combine remaining current images with new uploaded images
|
||||||
const finalImages = [...updatedImages, ...uploadedImageUrls];
|
const finalImages = [...updatedImages, ...uploadedImageUrls];
|
||||||
|
|
||||||
const updateData: any = {
|
const updateData: any = {
|
||||||
name,
|
name: name as string,
|
||||||
shortDescription,
|
shortDescription: shortDescription as string | undefined,
|
||||||
longDescription,
|
longDescription: longDescription as string | undefined,
|
||||||
unitId,
|
unitId: parseInt(unitId as string),
|
||||||
storeId,
|
storeId: parseInt(storeId as string),
|
||||||
price,
|
price: parseFloat(price as string),
|
||||||
marketPrice,
|
marketPrice: marketPrice ? parseFloat(marketPrice as string) : null,
|
||||||
incrementStep: incrementStep || 1,
|
incrementStep: incrementStep ? parseInt(incrementStep as string) : 1,
|
||||||
productQuantity: productQuantity || 1,
|
productQuantity: productQuantity ? parseInt(productQuantity as string) : 1,
|
||||||
isSuspended: isSuspended || false,
|
isSuspended: isSuspended === 'true',
|
||||||
images: finalImages.length > 0 ? finalImages : undefined,
|
images: finalImages.length > 0 ? finalImages : undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isFlashAvailable !== undefined) {
|
if (isFlashAvailable !== undefined) {
|
||||||
updateData.isFlashAvailable = isFlashAvailable;
|
updateData.isFlashAvailable = isFlashAvailable === 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flashPrice !== undefined) {
|
if (flashPrice !== undefined) {
|
||||||
updateData.flashPrice = flashPrice ? parseFloat(flashPrice) : null;
|
updateData.flashPrice = flashPrice ? parseFloat(flashPrice as string) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedProduct = await updateProductRecord(parseInt(id), updateData)
|
const updatedProduct = await updateProductRecord(parseInt(id as string), updateData)
|
||||||
|
|
||||||
if (!updatedProduct) {
|
if (!updatedProduct) {
|
||||||
throw new ApiError("Product not found", 404);
|
throw new ApiError("Product not found", 404);
|
||||||
|
|
@ -200,22 +216,21 @@ export const updateProduct = async (req: Request, res: Response) => {
|
||||||
|
|
||||||
// Handle deals if provided
|
// Handle deals if provided
|
||||||
if (deals && Array.isArray(deals)) {
|
if (deals && Array.isArray(deals)) {
|
||||||
await updateProductDeals(parseInt(id), deals)
|
await updateProductDeals(parseInt(id as string), deals)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle tag assignments if provided
|
// Handle tag assignments if provided
|
||||||
// if (tagIds && Array.isArray(tagIds)) {
|
if (tagIds) {
|
||||||
if (tagIds && Boolean(tagIds)) {
|
const parsedTagIds = typeof tagIds === 'string' ? [parseInt(tagIds)] : (Array.isArray(tagIds) ? tagIds.map((t: any) => parseInt(t)) : [parseInt(tagIds as any)])
|
||||||
const tagIdsArray = Array.isArray(tagIds) ? tagIds : [+tagIds]
|
await replaceProductTags(parseInt(id as string), parsedTagIds)
|
||||||
await replaceProductTags(parseInt(id), tagIdsArray)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reinitialize stores to reflect changes
|
// Reinitialize stores to reflect changes
|
||||||
scheduleStoreInitialization()
|
scheduleStoreInitialization()
|
||||||
|
|
||||||
// Send response first
|
// Send response first
|
||||||
res.status(200).json({
|
return c.json({
|
||||||
product: updatedProduct,
|
product: updatedProduct,
|
||||||
message: "Product updated successfully",
|
message: "Product updated successfully",
|
||||||
});
|
}, 200);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Request, Response } from "express";
|
import { Context } from 'hono';
|
||||||
import { scaffoldAssetUrl } from "@/src/lib/s3-client"
|
import { scaffoldAssetUrl } from "@/src/lib/s3-client"
|
||||||
import { getNextDeliveryDate } from "@/src/trpc/apis/common-apis/common"
|
import { getNextDeliveryDate } from "@/src/trpc/apis/common-apis/common"
|
||||||
import {
|
import {
|
||||||
|
|
@ -9,19 +9,19 @@ import {
|
||||||
/**
|
/**
|
||||||
* Get all products summary for dropdown
|
* Get all products summary for dropdown
|
||||||
*/
|
*/
|
||||||
export const getAllProductsSummary = async (req: Request, res: Response) => {
|
export const getAllProductsSummary = async (c: Context) => {
|
||||||
try {
|
try {
|
||||||
const { tagId } = req.query;
|
const tagId = c.req.query('tagId');
|
||||||
const tagIdNum = tagId ? parseInt(tagId as string) : undefined;
|
const tagIdNum = tagId ? parseInt(tagId) : undefined;
|
||||||
|
|
||||||
// If tagId is provided but no products found, return empty array
|
// If tagId is provided but no products found, return empty array
|
||||||
if (tagIdNum) {
|
if (tagIdNum) {
|
||||||
const products = await getAllProductsWithUnits(tagIdNum);
|
const products = await getAllProductsWithUnits(tagIdNum);
|
||||||
if (products.length === 0) {
|
if (products.length === 0) {
|
||||||
return res.status(200).json({
|
return c.json({
|
||||||
products: [],
|
products: [],
|
||||||
count: 0,
|
count: 0,
|
||||||
});
|
}, 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,13 +46,13 @@ export const getAllProductsSummary = async (req: Request, res: Response) => {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
return res.status(200).json({
|
return c.json({
|
||||||
products: formattedProducts,
|
products: formattedProducts,
|
||||||
count: formattedProducts.length,
|
count: formattedProducts.length,
|
||||||
});
|
}, 200);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Get products summary error:", error);
|
console.error("Get products summary error:", error);
|
||||||
return res.status(500).json({ error: "Failed to fetch products summary" });
|
return c.json({ error: "Failed to fetch products summary" }, 500);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Router } from "express";
|
import { Hono } from 'hono';
|
||||||
import { getAllProductsSummary } from "@/src/apis/common-apis/apis/common-product.controller"
|
import { getAllProductsSummary } from "@/src/apis/common-apis/apis/common-product.controller"
|
||||||
|
|
||||||
const router = Router();
|
const router = new Hono();
|
||||||
|
|
||||||
router.get("/summary", getAllProductsSummary);
|
router.get("/summary", getAllProductsSummary);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { Router } from "express";
|
import { Hono } from 'hono';
|
||||||
import commonProductsRouter from "@/src/apis/common-apis/apis/common-product.router"
|
import commonProductsRouter from "@/src/apis/common-apis/apis/common-product.router"
|
||||||
|
|
||||||
const router = Router();
|
const router = new Hono();
|
||||||
|
|
||||||
router.use('/products', commonProductsRouter)
|
router.route('/products', commonProductsRouter)
|
||||||
|
|
||||||
const commonRouter = router;
|
const commonRouter = router;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import express from 'express';
|
// catchAsync is no longer needed with Hono
|
||||||
const catchAsync =
|
// Hono handles async errors automatically
|
||||||
(fn: express.RequestHandler) =>
|
// This file is kept for backward compatibility but should be removed in the future
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) =>
|
|
||||||
Promise.resolve(fn(req, res, next)).catch(next);
|
import { Context } from 'hono';
|
||||||
|
|
||||||
|
const catchAsync = (fn: (c: Context) => Promise<Response>) => {
|
||||||
|
return fn;
|
||||||
|
};
|
||||||
|
|
||||||
export default catchAsync;
|
export default catchAsync;
|
||||||
|
|
@ -1,56 +1,36 @@
|
||||||
import { Router, Request, Response, NextFunction } from "express";
|
import { Hono } from 'hono';
|
||||||
import avRouter from "@/src/apis/admin-apis/apis/av-router"
|
import avRouter from "@/src/apis/admin-apis/apis/av-router"
|
||||||
import { ApiError } from "@/src/lib/api-error"
|
import { ApiError } from "@/src/lib/api-error"
|
||||||
import v1Router from "@/src/v1-router"
|
import v1Router from "@/src/v1-router"
|
||||||
import testController from "@/src/test-controller"
|
import testController from "@/src/test-controller"
|
||||||
import { authenticateUser } from "@/src/middleware/auth.middleware"
|
import { authenticateUser } from "@/src/middleware/auth.middleware"
|
||||||
|
|
||||||
|
const router = new Hono();
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
// Health check endpoints (no auth required)
|
// Health check endpoints (no auth required)
|
||||||
router.get('/health', (req: Request, res: Response) => {
|
router.get('/health', (c) => {
|
||||||
res.status(200).json({
|
return c.json({
|
||||||
status: 'OK',
|
status: 'OK',
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
uptime: process.uptime(),
|
uptime: process.uptime(),
|
||||||
message: 'Hello world'
|
message: 'Hello world'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
router.get('/seed', (req:Request, res: Response) => {
|
|
||||||
res.status(200).json({
|
router.get('/seed', (c) => {
|
||||||
|
return c.json({
|
||||||
status: 'OK',
|
status: 'OK',
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
uptime: process.uptime()
|
uptime: process.uptime()
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
// Apply authentication middleware to all subsequent routes
|
// Apply authentication middleware to all subsequent routes
|
||||||
router.use(authenticateUser);
|
router.use('*', authenticateUser);
|
||||||
|
|
||||||
router.use('/v1', v1Router);
|
router.route('/v1', v1Router);
|
||||||
// router.use('/av', avRouter);
|
// router.route('/av', avRouter);
|
||||||
router.use('/test', testController);
|
router.route('/test', testController);
|
||||||
|
|
||||||
// Global error handling middleware
|
|
||||||
router.use((err: Error, req: Request, res: Response, next: NextFunction) => {
|
|
||||||
console.error('Error:', err);
|
|
||||||
|
|
||||||
if (err instanceof ApiError) {
|
|
||||||
return res.status(err.statusCode).json({
|
|
||||||
error: err.message,
|
|
||||||
details: err.details,
|
|
||||||
statusCode: err.statusCode
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle unknown errors
|
|
||||||
return res.status(500).json({
|
|
||||||
error: 'Internal Server Error',
|
|
||||||
message: process.env.NODE_ENV === 'development' ? err.message : undefined,
|
|
||||||
statusCode: 500
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const mainRouter = router;
|
const mainRouter = router;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,31 @@
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Context, Next } from 'hono';
|
||||||
import { jwtVerify } from 'jose';
|
import { jwtVerify } from 'jose';
|
||||||
import { getStaffUserById, isUserSuspended } from '@/src/dbService';
|
import { getStaffUserById, isUserSuspended } from '@/src/dbService';
|
||||||
import { ApiError } from '@/src/lib/api-error';
|
import { ApiError } from '@/src/lib/api-error';
|
||||||
import { encodedJwtSecret } from '@/src/lib/env-exporter';
|
import { encodedJwtSecret } from '@/src/lib/env-exporter';
|
||||||
|
|
||||||
interface AuthenticatedRequest extends Request {
|
interface UserContext {
|
||||||
user?: {
|
|
||||||
userId: number;
|
userId: number;
|
||||||
name?: string;
|
name?: string;
|
||||||
email?: string;
|
email?: string;
|
||||||
mobile?: string;
|
mobile?: string;
|
||||||
};
|
|
||||||
staffUser?: {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const authenticateUser = async (req: AuthenticatedRequest, res: Response, next: NextFunction) => {
|
interface StaffContext {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const authenticateUser = async (c: Context, next: Next) => {
|
||||||
try {
|
try {
|
||||||
const authHeader = req.headers.authorization;
|
const authHeader = c.req.header('authorization');
|
||||||
|
|
||||||
if (!authHeader?.startsWith('Bearer ')) {
|
if (!authHeader?.startsWith('Bearer ')) {
|
||||||
throw new ApiError('Authorization token required', 401);
|
throw new ApiError('Authorization token required', 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = authHeader.substring(7);
|
const token = authHeader.substring(7);
|
||||||
console.log(req.headers)
|
console.log(c.req.header)
|
||||||
|
|
||||||
const { payload } = await jwtVerify(token, encodedJwtSecret);
|
const { payload } = await jwtVerify(token, encodedJwtSecret);
|
||||||
const decoded = payload as any;
|
const decoded = payload as any;
|
||||||
|
|
@ -51,13 +50,13 @@ export const authenticateUser = async (req: AuthenticatedRequest, res: Response,
|
||||||
throw new ApiError('Invalid staff token', 401);
|
throw new ApiError('Invalid staff token', 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
req.staffUser = {
|
c.set('staffUser', {
|
||||||
id: staff.id,
|
id: staff.id,
|
||||||
name: staff.name,
|
name: staff.name,
|
||||||
};
|
});
|
||||||
} else {
|
} else {
|
||||||
// This is a regular user token
|
// This is a regular user token
|
||||||
req.user = decoded;
|
c.set('user', decoded);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// Old implementation - direct DB queries:
|
// Old implementation - direct DB queries:
|
||||||
|
|
@ -82,8 +81,8 @@ export const authenticateUser = async (req: AuthenticatedRequest, res: Response,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
next();
|
await next();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,12 @@
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Context, Next } from 'hono';
|
||||||
import { jwtVerify, errors } from 'jose';
|
import { jwtVerify, errors } from 'jose';
|
||||||
import { ApiError } from '@/src/lib/api-error'
|
import { ApiError } from '@/src/lib/api-error'
|
||||||
import { encodedJwtSecret } from '@/src/lib/env-exporter';
|
import { encodedJwtSecret } from '@/src/lib/env-exporter';
|
||||||
|
|
||||||
// Extend the Request interface to include user property
|
export const verifyToken = async (c: Context, next: Next) => {
|
||||||
declare global {
|
|
||||||
namespace Express {
|
|
||||||
interface Request {
|
|
||||||
user?: any;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const verifyToken = async (req: Request, res: Response, next: NextFunction) => {
|
|
||||||
try {
|
try {
|
||||||
// Get token from Authorization header
|
// Get token from Authorization header
|
||||||
const authHeader = req.headers.authorization;
|
const authHeader = c.req.header('authorization');
|
||||||
|
|
||||||
|
|
||||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||||
|
|
@ -32,37 +23,38 @@ export const verifyToken = async (req: Request, res: Response, next: NextFunctio
|
||||||
const { payload } = await jwtVerify(token, encodedJwtSecret);
|
const { payload } = await jwtVerify(token, encodedJwtSecret);
|
||||||
|
|
||||||
|
|
||||||
// Add user info to request
|
// Add user info to context
|
||||||
req.user = payload;
|
c.set('user', payload);
|
||||||
|
|
||||||
next();
|
await next();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof errors.JOSEError) {
|
if (error instanceof errors.JOSEError) {
|
||||||
next(new ApiError('Invalid Auth Credentials', 401));
|
throw new ApiError('Invalid Auth Credentials', 401);
|
||||||
} else {
|
} else {
|
||||||
next(error);
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const requireRole = (roles: string[]) => {
|
export const requireRole = (roles: string[]) => {
|
||||||
return (req: Request, res: Response, next: NextFunction) => {
|
return async (c: Context, next: Next) => {
|
||||||
try {
|
try {
|
||||||
if (!req.user) {
|
const user = c.get('user');
|
||||||
|
if (!user) {
|
||||||
throw new ApiError('Authentication required', 401);
|
throw new ApiError('Authentication required', 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if user has any of the required roles
|
// Check if user has any of the required roles
|
||||||
const userRoles = req.user.roles || [];
|
const userRoles = user.roles || [];
|
||||||
const hasPermission = roles.some(role => userRoles.includes(role));
|
const hasPermission = roles.some(role => userRoles.includes(role));
|
||||||
|
|
||||||
if (!hasPermission) {
|
if (!hasPermission) {
|
||||||
throw new ApiError('Access denied. Insufficient permissions', 403);
|
throw new ApiError('Access denied. Insufficient permissions', 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
next();
|
await next();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,9 @@
|
||||||
import { Request, Response, NextFunction } from 'express';
|
import { Context, Next } from 'hono';
|
||||||
import { jwtVerify, errors } from 'jose';
|
import { jwtVerify } from 'jose';
|
||||||
import { getStaffUserById } from '@/src/dbService';
|
import { getStaffUserById } from '@/src/dbService';
|
||||||
import { ApiError } from '@/src/lib/api-error';
|
import { ApiError } from '@/src/lib/api-error';
|
||||||
import { encodedJwtSecret } from '@/src/lib/env-exporter';
|
import { encodedJwtSecret } from '@/src/lib/env-exporter';
|
||||||
|
|
||||||
// Extend Request interface to include staffUser
|
|
||||||
declare global {
|
|
||||||
namespace Express {
|
|
||||||
interface Request {
|
|
||||||
staffUser?: {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify JWT token and extract payload
|
* Verify JWT token and extract payload
|
||||||
*/
|
*/
|
||||||
|
|
@ -29,12 +17,12 @@ const verifyStaffToken = async (token: string) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Middleware to authenticate staff users and attach staffUser to request
|
* Middleware to authenticate staff users and attach staffUser to context
|
||||||
*/
|
*/
|
||||||
export const authenticateStaff = async (req: Request, res: Response, next: NextFunction) => {
|
export const authenticateStaff = async (c: Context, next: Next) => {
|
||||||
try {
|
try {
|
||||||
// Extract token from Authorization header
|
// Extract token from Authorization header
|
||||||
const authHeader = req.headers.authorization;
|
const authHeader = c.req.header('authorization');
|
||||||
|
|
||||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||||
throw new ApiError('Staff authentication required', 401);
|
throw new ApiError('Staff authentication required', 401);
|
||||||
|
|
@ -72,14 +60,14 @@ export const authenticateStaff = async (req: Request, res: Response, next: NextF
|
||||||
throw new ApiError('Staff user not found', 401);
|
throw new ApiError('Staff user not found', 401);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attach staff user to request
|
// Attach staff user to context
|
||||||
req.staffUser = {
|
c.set('staffUser', {
|
||||||
id: staff.id,
|
id: staff.id,
|
||||||
name: staff.name,
|
name: staff.name,
|
||||||
};
|
});
|
||||||
|
|
||||||
next();
|
await next();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { Router, Request, Response } from 'express';
|
import { Hono } from 'hono';
|
||||||
|
|
||||||
const router = Router();
|
const router = new Hono();
|
||||||
|
|
||||||
router.get('/', (req: Request, res: Response) => {
|
router.get('/', (c) => {
|
||||||
res.json({
|
return c.json({
|
||||||
status: 'ok',
|
status: 'ok',
|
||||||
message: 'Health check passed',
|
message: 'Health check passed',
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
|
|
|
||||||
|
|
@ -357,7 +357,8 @@ export const authRouter = router({
|
||||||
? await generateSignedUrlFromS3Url(userDetail.profileImage)
|
? await generateSignedUrlFromS3Url(userDetail.profileImage)
|
||||||
: null
|
: null
|
||||||
|
|
||||||
const token = ctx.req.headers.authorization?.replace('Bearer ', '') || ''
|
const authHeader = ctx.req.header('authorization');
|
||||||
|
const token = authHeader?.replace('Bearer ', '') || ''
|
||||||
|
|
||||||
const response: UserAuthResponse = {
|
const response: UserAuthResponse = {
|
||||||
token,
|
token,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
import { initTRPC, TRPCError } from '@trpc/server';
|
import { initTRPC, TRPCError } from '@trpc/server';
|
||||||
import { type CreateExpressContextOptions } from '@trpc/server/adapters/express';
|
import type { Context as HonoContext } from 'hono';
|
||||||
|
|
||||||
export interface Context {
|
export interface Context {
|
||||||
req: CreateExpressContextOptions['req'];
|
req: HonoContext['req'];
|
||||||
res: CreateExpressContextOptions['res'];
|
|
||||||
user?: any;
|
user?: any;
|
||||||
staffUser?: {
|
staffUser?: {
|
||||||
id: number;
|
id: number;
|
||||||
|
|
|
||||||
13
apps/backend/src/types/hono.d.ts
vendored
Normal file
13
apps/backend/src/types/hono.d.ts
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { Context as HonoContext } from 'hono';
|
||||||
|
|
||||||
|
declare module 'hono' {
|
||||||
|
interface ContextVariableMap {
|
||||||
|
user?: any;
|
||||||
|
staffUser?: {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {};
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import { Router } from "express";
|
import { Hono } from 'hono';
|
||||||
import avRouter from "@/src/apis/admin-apis/apis/av-router"
|
import avRouter from "@/src/apis/admin-apis/apis/av-router"
|
||||||
import commonRouter from "@/src/apis/common-apis/apis/common.router"
|
import commonRouter from "@/src/apis/common-apis/apis/common.router"
|
||||||
|
|
||||||
const router = Router();
|
const router = new Hono();
|
||||||
|
|
||||||
router.use('/av', avRouter);
|
|
||||||
router.use('/cm', commonRouter);
|
|
||||||
|
|
||||||
|
router.route('/av', avRouter);
|
||||||
|
router.route('/cm', commonRouter);
|
||||||
|
|
||||||
const v1Router = router;
|
const v1Router = router;
|
||||||
|
|
||||||
|
|
|
||||||
415
package-lock.json
generated
415
package-lock.json
generated
|
|
@ -127,23 +127,22 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.888.0",
|
"@aws-sdk/client-s3": "^3.888.0",
|
||||||
"@aws-sdk/s3-request-presigner": "^3.888.0",
|
"@aws-sdk/s3-request-presigner": "^3.888.0",
|
||||||
|
"@hono/node-server": "^1.19.11",
|
||||||
|
"@hono/trpc-server": "^0.4.2",
|
||||||
"@trpc/server": "^11.6.0",
|
"@trpc/server": "^11.6.0",
|
||||||
"@turf/turf": "^7.2.0",
|
"@turf/turf": "^7.2.0",
|
||||||
"@types/bcryptjs": "^2.4.6",
|
"@types/bcryptjs": "^2.4.6",
|
||||||
"@types/cors": "^2.8.19",
|
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.11.0",
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
"cors": "^2.8.5",
|
|
||||||
"dayjs": "^1.11.18",
|
"dayjs": "^1.11.18",
|
||||||
"dotenv": "^17.2.1",
|
"dotenv": "^17.2.1",
|
||||||
"expo-server-sdk": "^4.0.0",
|
"expo-server-sdk": "^4.0.0",
|
||||||
"express": "^5.1.0",
|
|
||||||
"fuse.js": "^7.1.0",
|
"fuse.js": "^7.1.0",
|
||||||
|
"hono": "^4.12.9",
|
||||||
"jose": "^6.2.2",
|
"jose": "^6.2.2",
|
||||||
"zod": "^4.1.12"
|
"zod": "^4.1.12"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/express": "^5.0.3",
|
|
||||||
"@types/node": "^24.5.2",
|
"@types/node": "^24.5.2",
|
||||||
"rimraf": "^6.1.2",
|
"rimraf": "^6.1.2",
|
||||||
"ts-node-dev": "^2.0.0",
|
"ts-node-dev": "^2.0.0",
|
||||||
|
|
@ -3720,6 +3719,31 @@
|
||||||
"excpretty": "build/cli.js"
|
"excpretty": "build/cli.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@hono/node-server": {
|
||||||
|
"version": "1.19.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz",
|
||||||
|
"integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.14.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"hono": "^4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hono/trpc-server": {
|
||||||
|
"version": "0.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@hono/trpc-server/-/trpc-server-0.4.2.tgz",
|
||||||
|
"integrity": "sha512-3TDrc42CZLgcTFkXQba+y7JlRWRiyw1AqhLqztWyNS2IFT+3bHld0lxKdGBttCtGKHYx0505dM67RMazjhdZqw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@trpc/server": "^10.10.0 || >11.0.0-rc",
|
||||||
|
"hono": ">=4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@humanfs/core": {
|
"node_modules/@humanfs/core": {
|
||||||
"version": "0.19.1",
|
"version": "0.19.1",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
|
@ -7600,35 +7624,11 @@
|
||||||
"version": "2.4.6",
|
"version": "2.4.6",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/body-parser": {
|
|
||||||
"version": "1.19.6",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/connect": "*",
|
|
||||||
"@types/node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/canvas-confetti": {
|
"node_modules/@types/canvas-confetti": {
|
||||||
"version": "1.9.0",
|
"version": "1.9.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/connect": {
|
|
||||||
"version": "3.4.38",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/cors": {
|
|
||||||
"version": "2.8.19",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/d3-voronoi": {
|
"node_modules/@types/d3-voronoi": {
|
||||||
"version": "1.1.12",
|
"version": "1.1.12",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
|
|
@ -7642,27 +7642,6 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/express": {
|
|
||||||
"version": "5.0.6",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/body-parser": "*",
|
|
||||||
"@types/express-serve-static-core": "^5.0.0",
|
|
||||||
"@types/serve-static": "^2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/express-serve-static-core": {
|
|
||||||
"version": "5.1.1",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/node": "*",
|
|
||||||
"@types/qs": "*",
|
|
||||||
"@types/range-parser": "*",
|
|
||||||
"@types/send": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/geojson": {
|
"node_modules/@types/geojson": {
|
||||||
"version": "7946.0.16",
|
"version": "7946.0.16",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
|
|
@ -7706,11 +7685,6 @@
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/http-errors": {
|
|
||||||
"version": "2.0.5",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@types/istanbul-lib-coverage": {
|
"node_modules/@types/istanbul-lib-coverage": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.6",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
|
|
@ -7781,16 +7755,6 @@
|
||||||
"pg-types": "^2.2.0"
|
"pg-types": "^2.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/qs": {
|
|
||||||
"version": "6.15.0",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@types/range-parser": {
|
|
||||||
"version": "1.2.7",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@types/react": {
|
"node_modules/@types/react": {
|
||||||
"version": "19.0.14",
|
"version": "19.0.14",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -7821,23 +7785,6 @@
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/send": {
|
|
||||||
"version": "1.2.1",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/serve-static": {
|
|
||||||
"version": "2.2.0",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/http-errors": "*",
|
|
||||||
"@types/node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/stack-utils": {
|
"node_modules/@types/stack-utils": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
|
|
@ -8232,17 +8179,6 @@
|
||||||
"node": ">=6.5"
|
"node": ">=6.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/accepts": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"mime-types": "^3.0.0",
|
|
||||||
"negotiator": "^1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.16.0",
|
"version": "8.16.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -8915,28 +8851,6 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/body-parser": {
|
|
||||||
"version": "2.2.2",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"bytes": "^3.1.2",
|
|
||||||
"content-type": "^1.0.5",
|
|
||||||
"debug": "^4.4.3",
|
|
||||||
"http-errors": "^2.0.0",
|
|
||||||
"iconv-lite": "^0.7.0",
|
|
||||||
"on-finished": "^2.4.1",
|
|
||||||
"qs": "^6.14.1",
|
|
||||||
"raw-body": "^3.0.1",
|
|
||||||
"type-is": "^2.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/express"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/boolbase": {
|
"node_modules/boolbase": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
|
|
@ -9573,17 +9487,6 @@
|
||||||
"@babel/types": "^7.6.1"
|
"@babel/types": "^7.6.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/content-disposition": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/express"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/content-type": {
|
"node_modules/content-type": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -9606,13 +9509,6 @@
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/cookie-signature": {
|
|
||||||
"version": "1.2.2",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.6.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/copy-anything": {
|
"node_modules/copy-anything": {
|
||||||
"version": "4.0.5",
|
"version": "4.0.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -9637,21 +9533,6 @@
|
||||||
"url": "https://opencollective.com/core-js"
|
"url": "https://opencollective.com/core-js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cors": {
|
|
||||||
"version": "2.8.6",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"object-assign": "^4",
|
|
||||||
"vary": "^1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/express"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/cosmiconfig": {
|
"node_modules/cosmiconfig": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -11587,47 +11468,6 @@
|
||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/express": {
|
|
||||||
"version": "5.2.1",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"accepts": "^2.0.0",
|
|
||||||
"body-parser": "^2.2.1",
|
|
||||||
"content-disposition": "^1.0.0",
|
|
||||||
"content-type": "^1.0.5",
|
|
||||||
"cookie": "^0.7.1",
|
|
||||||
"cookie-signature": "^1.2.1",
|
|
||||||
"debug": "^4.4.0",
|
|
||||||
"depd": "^2.0.0",
|
|
||||||
"encodeurl": "^2.0.0",
|
|
||||||
"escape-html": "^1.0.3",
|
|
||||||
"etag": "^1.8.1",
|
|
||||||
"finalhandler": "^2.1.0",
|
|
||||||
"fresh": "^2.0.0",
|
|
||||||
"http-errors": "^2.0.0",
|
|
||||||
"merge-descriptors": "^2.0.0",
|
|
||||||
"mime-types": "^3.0.0",
|
|
||||||
"on-finished": "^2.4.1",
|
|
||||||
"once": "^1.4.0",
|
|
||||||
"parseurl": "^1.3.3",
|
|
||||||
"proxy-addr": "^2.0.7",
|
|
||||||
"qs": "^6.14.0",
|
|
||||||
"range-parser": "^1.2.1",
|
|
||||||
"router": "^2.2.0",
|
|
||||||
"send": "^1.1.0",
|
|
||||||
"serve-static": "^2.2.0",
|
|
||||||
"statuses": "^2.0.1",
|
|
||||||
"type-is": "^2.0.1",
|
|
||||||
"vary": "^1.1.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/express"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/fallback-ui": {
|
"node_modules/fallback-ui": {
|
||||||
"resolved": "apps/fallback-ui",
|
"resolved": "apps/fallback-ui",
|
||||||
"link": true
|
"link": true
|
||||||
|
|
@ -11809,25 +11649,6 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/finalhandler": {
|
|
||||||
"version": "2.1.1",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"debug": "^4.4.0",
|
|
||||||
"encodeurl": "^2.0.0",
|
|
||||||
"escape-html": "^1.0.3",
|
|
||||||
"on-finished": "^2.4.1",
|
|
||||||
"parseurl": "^1.3.3",
|
|
||||||
"statuses": "^2.0.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/express"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/find-up": {
|
"node_modules/find-up": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -11996,13 +11817,6 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fresh": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/fs.realpath": {
|
"node_modules/fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
|
|
@ -12439,6 +12253,15 @@
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/hono": {
|
||||||
|
"version": "4.12.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.9.tgz",
|
||||||
|
"integrity": "sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.9.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hosted-git-info": {
|
"node_modules/hosted-git-info": {
|
||||||
"version": "7.0.2",
|
"version": "7.0.2",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
|
@ -12486,20 +12309,6 @@
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"license": "BSD-3-Clause"
|
"license": "BSD-3-Clause"
|
||||||
},
|
},
|
||||||
"node_modules/iconv-lite": {
|
|
||||||
"version": "0.7.2",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/express"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ieee754": {
|
"node_modules/ieee754": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"funding": [
|
"funding": [
|
||||||
|
|
@ -12940,10 +12749,6 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-promise": {
|
|
||||||
"version": "4.0.0",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/is-regex": {
|
"node_modules/is-regex": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -13773,27 +13578,10 @@
|
||||||
"version": "2.0.14",
|
"version": "2.0.14",
|
||||||
"license": "CC0-1.0"
|
"license": "CC0-1.0"
|
||||||
},
|
},
|
||||||
"node_modules/media-typer": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/memoize-one": {
|
"node_modules/memoize-one": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/merge-descriptors": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/merge-stream": {
|
"node_modules/merge-stream": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
|
|
@ -14175,27 +13963,6 @@
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mime-db": {
|
|
||||||
"version": "1.54.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mime-types": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"mime-db": "^1.54.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/express"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mimic-fn": {
|
"node_modules/mimic-fn": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -14311,13 +14078,6 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/negotiator": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/nested-error-stacks": {
|
"node_modules/nested-error-stacks": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
|
|
@ -15443,19 +15203,6 @@
|
||||||
"qrcode-terminal": "bin/qrcode-terminal.js"
|
"qrcode-terminal": "bin/qrcode-terminal.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/qs": {
|
|
||||||
"version": "6.15.0",
|
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"dependencies": {
|
|
||||||
"side-channel": "^1.1.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.6"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/query-string": {
|
"node_modules/query-string": {
|
||||||
"version": "7.1.3",
|
"version": "7.1.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -15516,19 +15263,6 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/raw-body": {
|
|
||||||
"version": "3.0.2",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"bytes": "~3.1.2",
|
|
||||||
"http-errors": "~2.0.1",
|
|
||||||
"iconv-lite": "~0.7.0",
|
|
||||||
"unpipe": "~1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/rbush": {
|
"node_modules/rbush": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -16394,28 +16128,6 @@
|
||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/router": {
|
|
||||||
"version": "2.2.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"debug": "^4.4.0",
|
|
||||||
"depd": "^2.0.0",
|
|
||||||
"is-promise": "^4.0.0",
|
|
||||||
"parseurl": "^1.3.3",
|
|
||||||
"path-to-regexp": "^8.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/router/node_modules/path-to-regexp": {
|
|
||||||
"version": "8.3.0",
|
|
||||||
"license": "MIT",
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/express"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/run-parallel": {
|
"node_modules/run-parallel": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"funding": [
|
"funding": [
|
||||||
|
|
@ -16529,30 +16241,6 @@
|
||||||
"semver": "bin/semver.js"
|
"semver": "bin/semver.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/send": {
|
|
||||||
"version": "1.2.1",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"debug": "^4.4.3",
|
|
||||||
"encodeurl": "^2.0.0",
|
|
||||||
"escape-html": "^1.0.3",
|
|
||||||
"etag": "^1.8.1",
|
|
||||||
"fresh": "^2.0.0",
|
|
||||||
"http-errors": "^2.0.1",
|
|
||||||
"mime-types": "^3.0.2",
|
|
||||||
"ms": "^2.1.3",
|
|
||||||
"on-finished": "^2.4.1",
|
|
||||||
"range-parser": "^1.2.1",
|
|
||||||
"statuses": "^2.0.2"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/express"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/serialize-error": {
|
"node_modules/serialize-error": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
@ -16577,23 +16265,6 @@
|
||||||
"seroval": "^1.0"
|
"seroval": "^1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/serve-static": {
|
|
||||||
"version": "2.2.1",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"encodeurl": "^2.0.0",
|
|
||||||
"escape-html": "^1.0.3",
|
|
||||||
"parseurl": "^1.3.3",
|
|
||||||
"send": "^1.2.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 18"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/express"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/server-only": {
|
"node_modules/server-only": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
|
|
@ -17944,18 +17615,6 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/type-is": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"content-type": "^1.0.5",
|
|
||||||
"media-typer": "^1.1.0",
|
|
||||||
"mime-types": "^3.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 0.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/typed-array-buffer": {
|
"node_modules/typed-array-buffer": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue