FarelDeveloper commited on
Commit
1538b06
·
verified ·
1 Parent(s): ec821a8

Create app.js

Browse files
Files changed (1) hide show
  1. app.js +151 -0
app.js ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express from "express";
2
+ import bodyParser from "body-parser";
3
+ import crypto from "crypto";
4
+
5
+ const app = express();
6
+ app.use(bodyParser.json());
7
+
8
+ /* ===== ENV (dari HF Spaces) ===== */
9
+ const PROJECT = process.env.PAKASIR_PROJECT;
10
+ const API_KEY = process.env.PAKASIR_API_KEY;
11
+ const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET || "pakasir";
12
+
13
+ /* ===== In-memory storage (cukup untuk HF Space) ===== */
14
+ const transactions = new Map(); // order_id => data
15
+ const clients = new Map(); // order_id => [res,res]
16
+
17
+ /* ===== Helper ===== */
18
+ function sendEvent(order_id, payload) {
19
+ const arr = clients.get(order_id) || [];
20
+ for (const res of arr) {
21
+ res.write(`data: ${JSON.stringify(payload)}\n\n`);
22
+ }
23
+ }
24
+
25
+ /* ===== CREATE TRANSACTION ===== */
26
+ app.post("/create", async (req, res) => {
27
+ try {
28
+ const { amount } = req.body;
29
+ if (!amount || amount < 1000) {
30
+ return res.status(400).json({ error: "amount invalid" });
31
+ }
32
+
33
+ const order_id = `INV-${Date.now()}`;
34
+
35
+ const r = await fetch("https://app.pakasir.com/api/transactioncreate/qris", {
36
+ method: "POST",
37
+ headers: { "Content-Type": "application/json" },
38
+ body: JSON.stringify({
39
+ project: PROJECT,
40
+ api_key: API_KEY,
41
+ order_id,
42
+ amount
43
+ })
44
+ });
45
+
46
+ const j = await r.json();
47
+ const payment = j.payment || j;
48
+
49
+ const code = j.code || payment.code || "";
50
+ const qris_string = payment.payment_number || j.qris_string || "";
51
+
52
+ const qr_url = code
53
+ ? `https://app.pakasir.com/qris/${code}.png`
54
+ : `https://quickchart.io/qr?text=${encodeURIComponent(qris_string)}&size=500`;
55
+
56
+ transactions.set(order_id, {
57
+ order_id,
58
+ amount,
59
+ status: "PENDING"
60
+ });
61
+
62
+ res.json({
63
+ success: true,
64
+ order_id,
65
+ qr_url,
66
+ raw: j
67
+ });
68
+ } catch (e) {
69
+ console.error(e);
70
+ res.status(500).json({ error: "failed create transaction" });
71
+ }
72
+ });
73
+
74
+ /* ===== SSE REALTIME ===== */
75
+ app.get("/events/:order_id", (req, res) => {
76
+ const { order_id } = req.params;
77
+
78
+ res.writeHead(200, {
79
+ "Content-Type": "text/event-stream",
80
+ "Cache-Control": "no-cache",
81
+ Connection: "keep-alive"
82
+ });
83
+ res.write("\n");
84
+
85
+ const arr = clients.get(order_id) || [];
86
+ arr.push(res);
87
+ clients.set(order_id, arr);
88
+
89
+ req.on("close", () => {
90
+ const updated = (clients.get(order_id) || []).filter(r => r !== res);
91
+ if (updated.length === 0) clients.delete(order_id);
92
+ else clients.set(order_id, updated);
93
+ });
94
+ });
95
+
96
+ /* ===== WEBHOOK PAKASIR ===== */
97
+ app.post("/webhook", async (req, res) => {
98
+ try {
99
+ const body = req.body;
100
+ const order_id = body.payment?.order_id || body.order_id;
101
+ const status = (body.payment?.status || body.status || "").toUpperCase();
102
+
103
+ if (!order_id) return res.status(400).send("no order_id");
104
+
105
+ if (transactions.has(order_id)) {
106
+ const tx = transactions.get(order_id);
107
+ tx.status = status;
108
+ transactions.set(order_id, tx);
109
+ }
110
+
111
+ sendEvent(order_id, { order_id, status });
112
+ res.json({ ok: true });
113
+ } catch (e) {
114
+ console.error(e);
115
+ res.status(500).send("webhook error");
116
+ }
117
+ });
118
+
119
+ /* ===== POLLING FALLBACK ===== */
120
+ app.get("/status/:order_id", async (req, res) => {
121
+ try {
122
+ const { order_id } = req.params;
123
+
124
+ const url = `https://app.pakasir.com/api/transactiondetail?project=${PROJECT}&order_id=${order_id}&api_key=${API_KEY}`;
125
+ const r = await fetch(url);
126
+ const j = await r.json();
127
+
128
+ const tx = j.transaction || j;
129
+ const status = (tx.status || "UNKNOWN").toUpperCase();
130
+
131
+ if (transactions.has(order_id)) {
132
+ transactions.get(order_id).status = status;
133
+ }
134
+
135
+ res.json({ order_id, status, raw: j });
136
+ } catch (e) {
137
+ console.error(e);
138
+ res.status(500).json({ error: "status error" });
139
+ }
140
+ });
141
+
142
+ /* ===== HEALTH ===== */
143
+ app.get("/", (req, res) => {
144
+ res.json({
145
+ name: "Pakasir Real-Time API",
146
+ status: "running"
147
+ });
148
+ });
149
+
150
+ const PORT = process.env.PORT || 7860;
151
+ app.listen(PORT, () => console.log("RUNNING ON", PORT));