FarelDeveloper commited on
Commit
da0af8f
·
verified ·
1 Parent(s): b50a7c6

Update app.js

Browse files
Files changed (1) hide show
  1. app.js +60 -39
app.js CHANGED
@@ -5,16 +5,20 @@ import crypto from "crypto";
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) {
@@ -22,12 +26,12 @@ function sendEvent(order_id, payload) {
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()}`;
@@ -46,15 +50,12 @@ app.post("/create", async (req, res) => {
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
  });
@@ -62,12 +63,12 @@ app.post("/create", async (req, res) => {
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
 
@@ -87,25 +88,27 @@ app.get("/events/:order_id", (req, 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 });
@@ -116,23 +119,40 @@ app.post("/webhook", async (req, res) => {
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" });
@@ -142,10 +162,11 @@ app.get("/status/:order_id", async (req, res) => {
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));
 
5
  const app = express();
6
  app.use(bodyParser.json());
7
 
8
+ /* ===== ENV ===== */
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
+ if (!PROJECT || !API_KEY) {
14
+ throw new Error("PAKASIR_PROJECT & PAKASIR_API_KEY wajib diisi");
15
+ }
16
+
17
+ /* ===== MEMORY STORE ===== */
18
+ const transactions = new Map(); // order_id => { amount, status }
19
+ const clients = new Map(); // order_id => [res]
20
 
21
+ /* ===== SSE HELPER ===== */
22
  function sendEvent(order_id, payload) {
23
  const arr = clients.get(order_id) || [];
24
  for (const res of arr) {
 
26
  }
27
  }
28
 
29
+ /* ===== CREATE ===== */
30
  app.post("/create", async (req, res) => {
31
  try {
32
  const { amount } = req.body;
33
  if (!amount || amount < 1000) {
34
+ return res.status(400).json({ error: "amount minimal 1000" });
35
  }
36
 
37
  const order_id = `INV-${Date.now()}`;
 
50
  const j = await r.json();
51
  const payment = j.payment || j;
52
 
53
+ const qris = payment.payment_number || j.qris_string;
54
+ if (!qris) {
55
+ return res.status(500).json({ error: "gagal create qris", raw: j });
56
+ }
 
 
57
 
58
  transactions.set(order_id, {
 
59
  amount,
60
  status: "PENDING"
61
  });
 
63
  res.json({
64
  success: true,
65
  order_id,
66
+ amount,
67
+ qr_url: `https://quickchart.io/qr?text=${encodeURIComponent(qris)}&size=500`
68
  });
69
  } catch (e) {
70
  console.error(e);
71
+ res.status(500).json({ error: "create error" });
72
  }
73
  });
74
 
 
88
  clients.set(order_id, arr);
89
 
90
  req.on("close", () => {
91
+ const left = (clients.get(order_id) || []).filter(r => r !== res);
92
+ if (left.length === 0) clients.delete(order_id);
93
+ else clients.set(order_id, left);
94
  });
95
  });
96
 
97
+ /* ===== WEBHOOK ===== */
98
+ app.post("/webhook", (req, res) => {
99
  try {
100
  const body = req.body;
101
+ const order_id = body.order_id || body.payment?.order_id;
102
+ let status = body.status || body.payment?.status;
103
+
104
+ if (!order_id || !status) {
105
+ return res.status(400).send("invalid payload");
106
+ }
107
 
108
+ status = status.toUpperCase();
109
 
110
  if (transactions.has(order_id)) {
111
+ transactions.get(order_id).status = status;
 
 
112
  }
113
 
114
  sendEvent(order_id, { order_id, status });
 
119
  }
120
  });
121
 
122
+ /* ===== STATUS (FIXED) ===== */
123
  app.get("/status/:order_id", async (req, res) => {
124
  try {
125
  const { order_id } = req.params;
126
+ const tx = transactions.get(order_id);
127
 
128
+ if (!tx) {
129
+ return res.json({ order_id, status: "NOT_FOUND" });
130
+ }
 
 
 
131
 
132
+ // kalau sudah PAID dari webhook → langsung return
133
+ if (tx.status === "PAID" || tx.status === "SUCCESS") {
134
+ return res.json({ order_id, status: tx.status });
135
  }
136
 
137
+ // fallback polling (WAJIB amount)
138
+ const params = new URLSearchParams({
139
+ project: PROJECT,
140
+ api_key: API_KEY,
141
+ order_id,
142
+ amount: tx.amount
143
+ });
144
+
145
+ const r = await fetch(
146
+ `https://app.pakasir.com/api/transactiondetail?${params}`
147
+ );
148
+ const j = await r.json();
149
+ const data = j.transaction || j;
150
+ const status = (data.status || "PENDING").toUpperCase();
151
+
152
+ tx.status = status;
153
+ transactions.set(order_id, tx);
154
+
155
+ res.json({ order_id, status });
156
  } catch (e) {
157
  console.error(e);
158
  res.status(500).json({ error: "status error" });
 
162
  /* ===== HEALTH ===== */
163
  app.get("/", (req, res) => {
164
  res.json({
165
+ name: "Pakasir Realtime Gateway",
166
  status: "running"
167
  });
168
  });
169
 
170
+ /* ===== START ===== */
171
  const PORT = process.env.PORT || 7860;
172
  app.listen(PORT, () => console.log("RUNNING ON", PORT));