x
This commit is contained in:
1 parent
36f8ff0759
commit
182d0349fa
5 files changed
+70
-3
No files matched your search
@@ -12,11 +12,12 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@homaroma/types": "*",
|
|
||||||
"@elysiajs/cors": "^1.2.2",
|
"@elysiajs/cors": "^1.2.2",
|
||||||
"@elysiajs/jwt": "^1.4.1",
|
"@elysiajs/jwt": "^1.4.1",
|
||||||
"@elysiajs/static": "^1.4.7",
|
"@elysiajs/static": "^1.4.7",
|
||||||
"@elysiajs/swagger": "^1.2.1",
|
"@elysiajs/swagger": "^1.2.1",
|
||||||
|
"@homaroma/types": "*",
|
||||||
|
"@line/bot-sdk": "^11.0.1",
|
||||||
"@prisma/adapter-pg": "^7.6.0",
|
"@prisma/adapter-pg": "^7.6.0",
|
||||||
"@prisma/client": "^7.6.0",
|
"@prisma/client": "^7.6.0",
|
||||||
"bcryptjs": "^3.0.3",
|
"bcryptjs": "^3.0.3",
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import { promotionsRoute } from "./routes/promotions";
|
|||||||
import { pagesRoute } from "./routes/pages";
|
import { pagesRoute } from "./routes/pages";
|
||||||
import { paymentsRoute } from "./routes/payments";
|
import { paymentsRoute } from "./routes/payments";
|
||||||
import { profileRoute } from "./routes/profile";
|
import { profileRoute } from "./routes/profile";
|
||||||
|
import { lineRoutes } from "./routes/line";
|
||||||
const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3051;
|
const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3051;
|
||||||
const CORS_ORIGIN = process.env.CORS_ORIGIN || "http://localhost:5173";
|
const CORS_ORIGIN = process.env.CORS_ORIGIN || "http://localhost:5173";
|
||||||
const JWT_SECRET = process.env.JWT_SECRET || "homaroma_secret_2026_scent";
|
const JWT_SECRET = process.env.JWT_SECRET || "homaroma_secret_2026_scent";
|
||||||
@@ -88,7 +89,7 @@ const app = new Elysia()
|
|||||||
return file;
|
return file;
|
||||||
})
|
})
|
||||||
.group("/api", (app) =>
|
.group("/api", (app) =>
|
||||||
app.use(authRoute).use(categoriesRoute).use(productsRoute).use(uploadRoute).use(heroRoute).use(ordersRoute).use(settingsRoute).use(articlesRoute).use(tiktokRoute).use(rawMaterialsRoute).use(shopeeRoute).use(tiktokOrderRoute).use(lazadaOrderRoute).use(customersRoute).use(couponsRoute).use(reviewsRoute).use(promotionsRoute).use(pagesRoute).use(paymentsRoute).use(profileRoute)
|
app.use(authRoute).use(categoriesRoute).use(productsRoute).use(uploadRoute).use(heroRoute).use(ordersRoute).use(settingsRoute).use(articlesRoute).use(tiktokRoute).use(rawMaterialsRoute).use(shopeeRoute).use(tiktokOrderRoute).use(lazadaOrderRoute).use(customersRoute).use(couponsRoute).use(reviewsRoute).use(promotionsRoute).use(pagesRoute).use(paymentsRoute).use(profileRoute).use(lineRoutes)
|
||||||
)
|
)
|
||||||
.listen({ port: PORT, hostname: "0.0.0.0" });
|
.listen({ port: PORT, hostname: "0.0.0.0" });
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import * as line from '@line/bot-sdk';
|
||||||
|
|
||||||
|
const channelAccessToken = process.env.LINE_CHANNEL_ACCESS_TOKEN || '';
|
||||||
|
const channelSecret = process.env.LINE_CHANNEL_SECRET || '';
|
||||||
|
|
||||||
|
export const lineConfig = {
|
||||||
|
channelAccessToken,
|
||||||
|
channelSecret,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const lineClient = new line.messagingApi.MessagingApiClient({
|
||||||
|
channelAccessToken,
|
||||||
|
});
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { Elysia } from 'elysia';
|
||||||
|
import * as line from '@line/bot-sdk';
|
||||||
|
import { lineConfig, lineClient } from '../lib/lineClient';
|
||||||
|
import crypto from 'crypto';
|
||||||
|
|
||||||
|
export const lineRoutes = new Elysia({ prefix: '/line' })
|
||||||
|
.post('/webhook', async ({ request, body, set }) => {
|
||||||
|
// 1. Verify Signature
|
||||||
|
const signature = request.headers.get('x-line-signature');
|
||||||
|
if (!signature) {
|
||||||
|
set.status = 400;
|
||||||
|
return { error: 'Missing Signature' };
|
||||||
|
}
|
||||||
|
|
||||||
|
// get raw body string
|
||||||
|
const rawBody = await request.clone().text();
|
||||||
|
|
||||||
|
const hash = crypto
|
||||||
|
.createHmac('SHA256', lineConfig.channelSecret)
|
||||||
|
.update(rawBody)
|
||||||
|
.digest('base64');
|
||||||
|
|
||||||
|
if (hash !== signature) {
|
||||||
|
set.status = 401;
|
||||||
|
return { error: 'Invalid Signature' };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const events: line.WebhookEvent[] = (body as any).events || [];
|
||||||
|
|
||||||
|
for (const event of events) {
|
||||||
|
if (event.type === 'message' && event.message.type === 'text') {
|
||||||
|
// Simple echo bot for now
|
||||||
|
await lineClient.replyMessage({
|
||||||
|
replyToken: event.replyToken,
|
||||||
|
messages: [{
|
||||||
|
type: 'text',
|
||||||
|
text: `คุณส่งข้อความว่า: ${event.message.text}`
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { success: true };
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[LINE Webhook] Error:', err);
|
||||||
|
set.status = 500;
|
||||||
|
return { error: 'Webhook processing failed' };
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -46,6 +46,7 @@
|
|||||||
"@elysiajs/static": "^1.4.7",
|
"@elysiajs/static": "^1.4.7",
|
||||||
"@elysiajs/swagger": "^1.2.1",
|
"@elysiajs/swagger": "^1.2.1",
|
||||||
"@homaroma/types": "*",
|
"@homaroma/types": "*",
|
||||||
|
"@line/bot-sdk": "^11.0.1",
|
||||||
"@prisma/adapter-pg": "^7.6.0",
|
"@prisma/adapter-pg": "^7.6.0",
|
||||||
"@prisma/client": "^7.6.0",
|
"@prisma/client": "^7.6.0",
|
||||||
"bcryptjs": "^3.0.3",
|
"bcryptjs": "^3.0.3",
|
||||||
@@ -398,7 +399,7 @@
|
|||||||
|
|
||||||
"@liff/window-postmessage": ["@liff/window-postmessage@2.29.0", "", { "dependencies": { "@liff/consts": "2.29.0", "@liff/logger": "2.29.0", "@liff/util": "2.29.0" }, "peerDependencies": { "tslib": "^2.3.0" } }, "sha512-rIsGf3xC/3JAb/1Nyoqrcss5UUUECz7v36MhruGeaVvTfzXqz1sviaUnU+rNHxij9CJEqMpA1C8+YDKenF6wMw=="],
|
"@liff/window-postmessage": ["@liff/window-postmessage@2.29.0", "", { "dependencies": { "@liff/consts": "2.29.0", "@liff/logger": "2.29.0", "@liff/util": "2.29.0" }, "peerDependencies": { "tslib": "^2.3.0" } }, "sha512-rIsGf3xC/3JAb/1Nyoqrcss5UUUECz7v36MhruGeaVvTfzXqz1sviaUnU+rNHxij9CJEqMpA1C8+YDKenF6wMw=="],
|
||||||
|
|
||||||
"@line/bot-sdk": ["@line/bot-sdk@10.8.0", "", { "dependencies": { "@types/node": "^24.0.0" }, "optionalDependencies": { "axios": "^1.7.4" } }, "sha512-1Mdpw/WPS3QP6fGiwPRTL27k8MgmMe7rVKCKsItP/kPzogX7a/X1ipQqk/F6RkorP9DNyJIx590hnVUkfBQf3w=="],
|
"@line/bot-sdk": ["@line/bot-sdk@11.0.1", "", { "dependencies": { "@types/node": "^24.0.0" } }, "sha512-De9gBX2JfZs78nDSyzfetHJw0R6hncPVVy3tzPMwYZzgwK06C/tcijGy7Vq28K8uYKGVTSthbtMIoYKNhXISzw=="],
|
||||||
|
|
||||||
"@line/liff": ["@line/liff@2.29.0", "", { "dependencies": { "@liff/activity": "2.29.0", "@liff/analytics": "2.29.0", "@liff/close-window": "2.29.0", "@liff/consts": "2.29.0", "@liff/core": "2.29.0", "@liff/create-shortcut-on-home-screen": "2.29.0", "@liff/extensions": "2.29.0", "@liff/get-app-language": "2.29.0", "@liff/get-friendship": "2.29.0", "@liff/get-language": "2.29.0", "@liff/get-line-version": "2.29.0", "@liff/get-origins": "2.29.0", "@liff/get-os": "2.29.0", "@liff/get-profile": "2.29.0", "@liff/get-version": "2.29.0", "@liff/hooks": "2.29.0", "@liff/i18n": "2.29.0", "@liff/iap": "2.29.0", "@liff/init": "2.29.0", "@liff/is-api-available": "2.29.0", "@liff/is-in-client": "2.29.0", "@liff/is-logged-in": "2.29.0", "@liff/is-sub-window": "2.29.0", "@liff/liff-types": "2.29.0", "@liff/login": "2.29.0", "@liff/logout": "2.29.0", "@liff/native-bridge": "2.29.0", "@liff/open-window": "2.29.0", "@liff/permanent-link": "2.29.0", "@liff/permission": "2.29.0", "@liff/ready": "2.29.0", "@liff/request-friendship": "2.29.0", "@liff/scan-code-v2": "2.29.0", "@liff/send-messages": "2.29.0", "@liff/server-api": "2.29.0", "@liff/share-target-picker": "2.29.0", "@liff/store": "2.29.0", "@liff/sub-window": "2.29.0", "@liff/use": "2.29.0", "@liff/util": "2.29.0", "tslib": "^2.3.0", "whatwg-fetch": "^3.0.0" } }, "sha512-50xZ7D5FiOM/42d00GEZh2TJ9bHDkbml+5yjUceC5xF19jYQVMrGn70Qbc0GYkVmnZtKp2q9hXQEzk25/arGrA=="],
|
"@line/liff": ["@line/liff@2.29.0", "", { "dependencies": { "@liff/activity": "2.29.0", "@liff/analytics": "2.29.0", "@liff/close-window": "2.29.0", "@liff/consts": "2.29.0", "@liff/core": "2.29.0", "@liff/create-shortcut-on-home-screen": "2.29.0", "@liff/extensions": "2.29.0", "@liff/get-app-language": "2.29.0", "@liff/get-friendship": "2.29.0", "@liff/get-language": "2.29.0", "@liff/get-line-version": "2.29.0", "@liff/get-origins": "2.29.0", "@liff/get-os": "2.29.0", "@liff/get-profile": "2.29.0", "@liff/get-version": "2.29.0", "@liff/hooks": "2.29.0", "@liff/i18n": "2.29.0", "@liff/iap": "2.29.0", "@liff/init": "2.29.0", "@liff/is-api-available": "2.29.0", "@liff/is-in-client": "2.29.0", "@liff/is-logged-in": "2.29.0", "@liff/is-sub-window": "2.29.0", "@liff/liff-types": "2.29.0", "@liff/login": "2.29.0", "@liff/logout": "2.29.0", "@liff/native-bridge": "2.29.0", "@liff/open-window": "2.29.0", "@liff/permanent-link": "2.29.0", "@liff/permission": "2.29.0", "@liff/ready": "2.29.0", "@liff/request-friendship": "2.29.0", "@liff/scan-code-v2": "2.29.0", "@liff/send-messages": "2.29.0", "@liff/server-api": "2.29.0", "@liff/share-target-picker": "2.29.0", "@liff/store": "2.29.0", "@liff/sub-window": "2.29.0", "@liff/use": "2.29.0", "@liff/util": "2.29.0", "tslib": "^2.3.0", "whatwg-fetch": "^3.0.0" } }, "sha512-50xZ7D5FiOM/42d00GEZh2TJ9bHDkbml+5yjUceC5xF19jYQVMrGn70Qbc0GYkVmnZtKp2q9hXQEzk25/arGrA=="],
|
||||||
|
|
||||||
@@ -1656,6 +1657,8 @@
|
|||||||
|
|
||||||
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
|
"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
|
||||||
|
|
||||||
|
"@liff/send-messages/@line/bot-sdk": ["@line/bot-sdk@10.8.0", "", { "dependencies": { "@types/node": "^24.0.0" }, "optionalDependencies": { "axios": "^1.7.4" } }, "sha512-1Mdpw/WPS3QP6fGiwPRTL27k8MgmMe7rVKCKsItP/kPzogX7a/X1ipQqk/F6RkorP9DNyJIx590hnVUkfBQf3w=="],
|
||||||
|
|
||||||
"@modelcontextprotocol/sdk/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
|
"@modelcontextprotocol/sdk/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
|
||||||
|
|
||||||
"@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
"@modelcontextprotocol/sdk/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
|
||||||
|
|||||||
Reference in new issue
Block a user