elpaypg 0.0.0-stage → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/.env.example +8 -0
  2. package/README.md +176 -2
  3. package/package.json +21 -4
  4. package/public/elpay-checkout.js +769 -0
  5. package/public/elpay-sms-gateway.apk +0 -0
  6. package/public/elpay-sms-gateway.apk.sha256 +1 -0
  7. package/public/elpay.js +785 -0
  8. package/public/fonts/dm-sans.woff2 +0 -0
  9. package/public/fonts/sora.woff2 +0 -0
  10. package/public/views/checkout.html +2839 -0
  11. package/public/views/partials/auth.html +110 -0
  12. package/public/views/partials/footer.html +54 -0
  13. package/public/views/partials/header.html +101 -0
  14. package/public/views/partials/modals.html +179 -0
  15. package/public/views/partials/payment-methods.html +526 -0
  16. package/public/views/partials/sidebar.html +75 -0
  17. package/public/views/partials/splash.html +35 -0
  18. package/src/__tests__/smoke.test.js +8 -0
  19. package/src/auth-guard.js +95 -0
  20. package/src/index.js +137 -0
  21. package/src/router.js +46 -0
  22. package/src/routes/admin.routes.js +2424 -0
  23. package/src/routes/checkout.routes.js +2000 -0
  24. package/src/routes/customer.routes.js +650 -0
  25. package/src/routes/device.routes.js +303 -0
  26. package/src/routes/payments.routes.js +446 -0
  27. package/src/routes/pollers.routes.js +653 -0
  28. package/src/services/observer-poller.service.js +369 -0
  29. package/src/services/tunnel-manager.js +130 -0
  30. package/src/services/whatsapp-berry.service.js +743 -0
  31. package/src/vendor/common/__tests__/common.test.js +297 -0
  32. package/src/vendor/common/__tests__/common.test.ts +160 -0
  33. package/src/vendor/common/contracts.js +64 -0
  34. package/src/vendor/common/contracts.ts +188 -0
  35. package/src/vendor/common/crypto.js +132 -0
  36. package/src/vendor/common/crypto.ts +112 -0
  37. package/src/vendor/common/enums.js +91 -0
  38. package/src/vendor/common/enums.ts +91 -0
  39. package/src/vendor/common/index.js +12 -0
  40. package/src/vendor/common/index.ts +8 -0
  41. package/src/vendor/common/money.js +62 -0
  42. package/src/vendor/common/money.ts +56 -0
  43. package/src/vendor/common/observation.js +27 -0
  44. package/src/vendor/common/observation.ts +52 -0
  45. package/src/vendor/common/runtime-config.js +246 -0
  46. package/src/vendor/common/secrets.js +374 -0
  47. package/src/vendor/common/state-machine.d.ts +1 -0
  48. package/src/vendor/common/state-machine.js +1 -0
  49. package/src/vendor/common/state-transitions.js +85 -0
  50. package/src/vendor/common/tunnel-command.js +59 -0
  51. package/src/vendor/common/upi-providers.js +389 -0
  52. package/src/vendor/common/upi-providers.ts +400 -0
  53. package/src/vendor/common/upi.js +69 -0
  54. package/src/vendor/common/upi.ts +61 -0
  55. package/src/vendor/core/__tests__/core.test.js +683 -0
  56. package/src/vendor/core/__tests__/queue-timing.test.js +237 -0
  57. package/src/vendor/core/__tests__/webhook-engine.test.js +243 -0
  58. package/src/vendor/core/attribution-engine.js +855 -0
  59. package/src/vendor/core/bank-email-parser.js +105 -0
  60. package/src/vendor/core/bank-sms-parser.js +183 -0
  61. package/src/vendor/core/device-security.js +506 -0
  62. package/src/vendor/core/index.js +13 -0
  63. package/src/vendor/core/normalizer.js +165 -0
  64. package/src/vendor/core/qr-lib.js +8 -0
  65. package/src/vendor/core/qr.js +62 -0
  66. package/src/vendor/core/queue-engine.js +153 -0
  67. package/src/vendor/core/recovery-engine.js +159 -0
  68. package/src/vendor/core/state-machine.js +42 -0
  69. package/src/vendor/core/timing-engine.js +272 -0
  70. package/src/vendor/core/verification-pipeline.js +1164 -0
  71. package/src/vendor/core/webhook-engine.js +280 -0
  72. package/src/vendor/db/__tests__/auth-matrix.test.js +564 -0
  73. package/src/vendor/db/__tests__/customer-reset.test.js +95 -0
  74. package/src/vendor/db/__tests__/db.test.js +265 -0
  75. package/src/vendor/db/__tests__/schema-parity.test.js +137 -0
  76. package/src/vendor/db/__tests__/sqlite_verify.test.js +15 -0
  77. package/src/vendor/db/database.js +181 -0
  78. package/src/vendor/db/index.js +12 -0
  79. package/src/vendor/db/migrate.js +210 -0
  80. package/src/vendor/db/repositories/audit-log.repository.js +68 -0
  81. package/src/vendor/db/repositories/customer-session.repository.js +181 -0
  82. package/src/vendor/db/repositories/customer.repository.js +636 -0
  83. package/src/vendor/db/repositories/device.repository.js +285 -0
  84. package/src/vendor/db/repositories/merchant.repository.js +158 -0
  85. package/src/vendor/db/repositories/observation.repository.js +124 -0
  86. package/src/vendor/db/repositories/payment-session.repository.js +618 -0
  87. package/src/vendor/db/repositories/receiving-account.repository.js +244 -0
  88. package/src/vendor/db/repositories/support-ticket.repository.js +140 -0
  89. package/src/vendor/db/schema.sql +266 -0
  90. package/src/vendor/db/sqlite-schema.sql +270 -0
@@ -0,0 +1,270 @@
1
+ -- SQLite Schema for ELPAY PG
2
+ -- Native Local / Zero-Dependency Execution
3
+
4
+ -- 1. Merchants Table
5
+ CREATE TABLE IF NOT EXISTS merchants (
6
+ id TEXT PRIMARY KEY,
7
+ business_name TEXT NOT NULL,
8
+ slug TEXT UNIQUE NOT NULL,
9
+ contact_email TEXT NOT NULL,
10
+ contact_phone TEXT NOT NULL,
11
+ webhook_url TEXT,
12
+ webhook_secret TEXT NOT NULL,
13
+ branding TEXT NOT NULL DEFAULT '{"primaryColor":"#2563eb","appName":"ELPAY PG","logoUrl":null}',
14
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
15
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
16
+ );
17
+
18
+ -- 2. Payment Receiving Accounts
19
+ CREATE TABLE IF NOT EXISTS payment_receiving_accounts (
20
+ id TEXT PRIMARY KEY,
21
+ merchant_id TEXT NOT NULL REFERENCES merchants(id) ON DELETE CASCADE,
22
+ upi_id TEXT NOT NULL,
23
+ payee_name TEXT NOT NULL,
24
+ is_merchant_enabled INTEGER NOT NULL DEFAULT 1,
25
+ is_active INTEGER NOT NULL DEFAULT 1,
26
+ is_slot_busy INTEGER NOT NULL DEFAULT 0,
27
+ current_active_session_id TEXT,
28
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
29
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
30
+ );
31
+
32
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_single_active_vpa_per_merchant ON payment_receiving_accounts (merchant_id) WHERE is_active = 1;
33
+
34
+ -- 3. Customers Table (Gateway-owned Customer Identity with WhatsApp Berry OTP)
35
+ CREATE TABLE IF NOT EXISTS customers (
36
+ id TEXT PRIMARY KEY,
37
+ name TEXT NOT NULL,
38
+ email TEXT UNIQUE NOT NULL,
39
+ mobile_number TEXT UNIQUE NOT NULL,
40
+ password_hash TEXT,
41
+ otp_code TEXT,
42
+ otp_expires_at TEXT,
43
+ otp_attempts INTEGER NOT NULL DEFAULT 0,
44
+ is_phone_verified INTEGER DEFAULT 0,
45
+ status TEXT NOT NULL DEFAULT 'ACTIVE',
46
+ ban_reason TEXT,
47
+ banned_at TEXT,
48
+ unbanned_at TEXT,
49
+ last_device TEXT,
50
+ last_login_at TEXT,
51
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
52
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
53
+ );
54
+
55
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_customers_email ON customers (email);
56
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_customers_mobile ON customers (mobile_number);
57
+
58
+ -- 3b. Customer Sessions Table (Server-authoritative session engine)
59
+ CREATE TABLE IF NOT EXISTS customer_sessions (
60
+ id TEXT PRIMARY KEY,
61
+ customer_id TEXT NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
62
+ token TEXT UNIQUE NOT NULL,
63
+ expires_at TEXT NOT NULL,
64
+ is_active INTEGER NOT NULL DEFAULT 1,
65
+ ip_address TEXT,
66
+ user_agent TEXT,
67
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
68
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
69
+ );
70
+
71
+ CREATE INDEX IF NOT EXISTS idx_customer_sessions_token ON customer_sessions (token, is_active);
72
+ CREATE INDEX IF NOT EXISTS idx_customer_sessions_customer ON customer_sessions (customer_id);
73
+
74
+ -- 3c. Devices Table (Cryptographic Device Binding & Hardware Context Fingerprinting)
75
+ CREATE TABLE IF NOT EXISTS devices (
76
+ id TEXT PRIMARY KEY,
77
+ customer_id TEXT REFERENCES customers(id) ON DELETE SET NULL,
78
+ public_key TEXT NOT NULL,
79
+ fingerprint_hash TEXT NOT NULL,
80
+ user_agent TEXT,
81
+ platform TEXT,
82
+ browser TEXT,
83
+ timezone TEXT,
84
+ language TEXT,
85
+ screen_signature TEXT,
86
+ device_token TEXT UNIQUE,
87
+ status TEXT NOT NULL DEFAULT 'ACTIVE',
88
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
89
+ last_seen_at TEXT NOT NULL DEFAULT (datetime('now'))
90
+ );
91
+
92
+ CREATE INDEX IF NOT EXISTS idx_devices_customer ON devices (customer_id);
93
+ CREATE INDEX IF NOT EXISTS idx_devices_fingerprint ON devices (fingerprint_hash);
94
+ CREATE INDEX IF NOT EXISTS idx_devices_token ON devices (device_token);
95
+
96
+ -- 4. Payment Sessions Table
97
+ CREATE TABLE IF NOT EXISTS payment_sessions (
98
+ id TEXT PRIMARY KEY,
99
+ merchant_id TEXT NOT NULL REFERENCES merchants(id) ON DELETE CASCADE,
100
+ customer_id TEXT REFERENCES customers(id) ON DELETE SET NULL,
101
+ receiving_account_id TEXT REFERENCES payment_receiving_accounts(id),
102
+ order_id TEXT NOT NULL,
103
+ attempt_id TEXT,
104
+ amount_paise INTEGER NOT NULL CHECK (amount_paise > 0),
105
+ currency TEXT NOT NULL DEFAULT 'INR',
106
+ method TEXT NOT NULL DEFAULT 'UPI',
107
+ status TEXT NOT NULL DEFAULT 'INITIATED',
108
+ queue_position INTEGER DEFAULT 0,
109
+ slot_acquired_at TEXT,
110
+ expires_at TEXT,
111
+ processing_started_at TEXT,
112
+ processing_expires_at TEXT,
113
+ completed_at TEXT,
114
+ return_url TEXT,
115
+ attributed_observation_id TEXT,
116
+ idempotency_key TEXT,
117
+ device_id TEXT REFERENCES devices(id),
118
+ verification_level INTEGER DEFAULT 0,
119
+ verification_sources TEXT DEFAULT '[]',
120
+ verification_tag TEXT DEFAULT 'UNVERIFIED',
121
+ metadata TEXT NOT NULL DEFAULT '{}',
122
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
123
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
124
+ );
125
+
126
+ CREATE INDEX IF NOT EXISTS idx_payment_sessions_active ON payment_sessions (receiving_account_id, status);
127
+ CREATE INDEX IF NOT EXISTS idx_payment_sessions_order ON payment_sessions (merchant_id, order_id, created_at);
128
+ CREATE INDEX IF NOT EXISTS idx_payment_sessions_device ON payment_sessions (device_id);
129
+ -- At most one active/processing/queued/successful session per merchant order.
130
+ -- Retrying a terminal (FAILED, EXPIRED, CANCELLED) order allows a new attempt with the true orderId.
131
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_single_active_session_per_order
132
+ ON payment_sessions (merchant_id, order_id)
133
+ WHERE status NOT IN ('FAILED', 'EXPIRED', 'CANCELLED');
134
+ -- Slot exclusivity is a database invariant, not an application convention: at most one
135
+ -- session per receiving account may occupy the slot (ACTIVE or PROCESSING) at any time.
136
+ -- Concurrent writers are rejected by the engine instead of relying on lock contention.
137
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_one_slot_per_receiving_account
138
+ ON payment_sessions (receiving_account_id)
139
+ WHERE status IN ('ACTIVE', 'PROCESSING') AND receiving_account_id IS NOT NULL;
140
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_payment_sessions_attributed_obs
141
+ ON payment_sessions (attributed_observation_id)
142
+ WHERE attributed_observation_id IS NOT NULL;
143
+
144
+ -- 5. Payment Observations Table
145
+ CREATE TABLE IF NOT EXISTS payment_observations (
146
+ id TEXT PRIMARY KEY,
147
+ receiving_account_id TEXT NOT NULL REFERENCES payment_receiving_accounts(id) ON DELETE CASCADE,
148
+ source TEXT NOT NULL,
149
+ amount_paise INTEGER NOT NULL,
150
+ observed_at TEXT NOT NULL,
151
+ ingested_at TEXT NOT NULL DEFAULT (datetime('now')),
152
+ sender_vpa TEXT,
153
+ bank_reference_number TEXT,
154
+ fingerprint_hash TEXT NOT NULL,
155
+ raw_payload TEXT NOT NULL DEFAULT '{}',
156
+ attribution_status TEXT NOT NULL DEFAULT 'UNATTRIBUTED',
157
+ attributed_payment_id TEXT REFERENCES payment_sessions(id),
158
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
159
+ );
160
+
161
+ CREATE INDEX IF NOT EXISTS idx_observations_match ON payment_observations (receiving_account_id, amount_paise, attribution_status);
162
+ CREATE INDEX IF NOT EXISTS idx_observations_bank_ref ON payment_observations (bank_reference_number);
163
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_observations_unique_attributed_bank_ref
164
+ ON payment_observations (bank_reference_number)
165
+ WHERE bank_reference_number IS NOT NULL AND attributed_payment_id IS NOT NULL;
166
+ CREATE INDEX IF NOT EXISTS idx_observations_fingerprint ON payment_observations (fingerprint_hash);
167
+ CREATE INDEX IF NOT EXISTS idx_observations_attributed_payment ON payment_observations (attributed_payment_id);
168
+
169
+ -- 6. Android Devices Table
170
+ CREATE TABLE IF NOT EXISTS android_devices (
171
+ id TEXT PRIMARY KEY,
172
+ merchant_id TEXT NOT NULL REFERENCES merchants(id) ON DELETE CASCADE,
173
+ device_name TEXT NOT NULL,
174
+ device_model TEXT,
175
+ signing_key_hash TEXT NOT NULL,
176
+ is_active INTEGER NOT NULL DEFAULT 1,
177
+ last_heartbeat_at TEXT,
178
+ last_observation_at TEXT,
179
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
180
+ );
181
+
182
+ -- 7. Webhook Deliveries Table
183
+ CREATE TABLE IF NOT EXISTS webhook_deliveries (
184
+ id TEXT PRIMARY KEY,
185
+ merchant_id TEXT NOT NULL REFERENCES merchants(id) ON DELETE CASCADE,
186
+ payment_id TEXT NOT NULL REFERENCES payment_sessions(id) ON DELETE CASCADE,
187
+ event_type TEXT NOT NULL,
188
+ payload TEXT NOT NULL,
189
+ endpoint_url TEXT NOT NULL,
190
+ response_status INTEGER,
191
+ response_body TEXT,
192
+ attempt_count INTEGER NOT NULL DEFAULT 1,
193
+ is_successful INTEGER NOT NULL DEFAULT 0,
194
+ next_retry_at TEXT,
195
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
196
+ );
197
+
198
+ CREATE INDEX IF NOT EXISTS idx_webhook_deliveries_retry ON webhook_deliveries (is_successful, next_retry_at);
199
+
200
+ -- 8. Support Tickets & Ticket Messages
201
+ CREATE TABLE IF NOT EXISTS support_tickets (
202
+ id TEXT PRIMARY KEY,
203
+ merchant_id TEXT NOT NULL REFERENCES merchants(id) ON DELETE CASCADE,
204
+ customer_id TEXT NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
205
+ payment_id TEXT REFERENCES payment_sessions(id) ON DELETE SET NULL,
206
+ subject TEXT NOT NULL,
207
+ status TEXT NOT NULL DEFAULT 'OPEN',
208
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
209
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
210
+ );
211
+
212
+ CREATE INDEX IF NOT EXISTS idx_support_tickets_merchant ON support_tickets (merchant_id);
213
+ CREATE INDEX IF NOT EXISTS idx_support_tickets_customer ON support_tickets (customer_id);
214
+
215
+ CREATE TABLE IF NOT EXISTS ticket_messages (
216
+ id TEXT PRIMARY KEY,
217
+ ticket_id TEXT NOT NULL REFERENCES support_tickets(id) ON DELETE CASCADE,
218
+ sender_type TEXT NOT NULL,
219
+ sender_id TEXT NOT NULL,
220
+ message TEXT NOT NULL,
221
+ attachments TEXT DEFAULT '[]',
222
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
223
+ );
224
+
225
+ CREATE INDEX IF NOT EXISTS idx_ticket_messages_ticket ON ticket_messages (ticket_id);
226
+
227
+ -- 9. Audit Logs Table
228
+ CREATE TABLE IF NOT EXISTS audit_logs (
229
+ id TEXT PRIMARY KEY,
230
+ merchant_id TEXT REFERENCES merchants(id) ON DELETE CASCADE,
231
+ entity_type TEXT NOT NULL,
232
+ entity_id TEXT NOT NULL,
233
+ action TEXT NOT NULL,
234
+ actor_type TEXT NOT NULL,
235
+ actor_id TEXT,
236
+ details TEXT NOT NULL DEFAULT '{}',
237
+ ip_address TEXT,
238
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
239
+ );
240
+
241
+ CREATE INDEX IF NOT EXISTS idx_audit_logs_merchant ON audit_logs (merchant_id);
242
+ CREATE INDEX IF NOT EXISTS idx_audit_logs_entity ON audit_logs (entity_type, entity_id);
243
+
244
+ -- 10. Security Events Table (Forensic evidence for fraud, automatic and manual bans)
245
+ CREATE TABLE IF NOT EXISTS security_events (
246
+ id TEXT PRIMARY KEY,
247
+ merchant_id TEXT,
248
+ customer_id TEXT,
249
+ payment_session_id TEXT,
250
+ event_type TEXT NOT NULL,
251
+ source TEXT,
252
+ sender TEXT,
253
+ device_info TEXT,
254
+ raw_message TEXT NOT NULL,
255
+ normalized_message TEXT,
256
+ extracted_amount TEXT,
257
+ extracted_reference TEXT,
258
+ parser_results TEXT DEFAULT '{}',
259
+ verification_results TEXT DEFAULT '{}',
260
+ fraud_reason TEXT NOT NULL,
261
+ metadata TEXT DEFAULT '{}',
262
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
263
+ );
264
+
265
+ CREATE INDEX IF NOT EXISTS idx_security_events_customer ON security_events (customer_id);
266
+ CREATE INDEX IF NOT EXISTS idx_security_events_session ON security_events (payment_session_id);
267
+ CREATE INDEX IF NOT EXISTS idx_security_events_type ON security_events (event_type);
268
+
269
+
270
+