@localpay/verification-engine 0.1.0

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 (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +251 -0
  3. package/dist/core/bank-fetch.service.d.ts +51 -0
  4. package/dist/core/bank-fetch.service.d.ts.map +1 -0
  5. package/dist/core/bank-fetch.service.js +147 -0
  6. package/dist/core/bank-fetch.service.js.map +1 -0
  7. package/dist/core/verification-engine.d.ts +68 -0
  8. package/dist/core/verification-engine.d.ts.map +1 -0
  9. package/dist/core/verification-engine.js +188 -0
  10. package/dist/core/verification-engine.js.map +1 -0
  11. package/dist/index.d.ts +14 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +28 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/parsers/ethiopia/abyssinia.parser.d.ts +19 -0
  16. package/dist/parsers/ethiopia/abyssinia.parser.d.ts.map +1 -0
  17. package/dist/parsers/ethiopia/abyssinia.parser.js +79 -0
  18. package/dist/parsers/ethiopia/abyssinia.parser.js.map +1 -0
  19. package/dist/parsers/ethiopia/cbe.parser.d.ts +25 -0
  20. package/dist/parsers/ethiopia/cbe.parser.d.ts.map +1 -0
  21. package/dist/parsers/ethiopia/cbe.parser.js +209 -0
  22. package/dist/parsers/ethiopia/cbe.parser.js.map +1 -0
  23. package/dist/parsers/ethiopia/ebirr.parser.d.ts +19 -0
  24. package/dist/parsers/ethiopia/ebirr.parser.d.ts.map +1 -0
  25. package/dist/parsers/ethiopia/ebirr.parser.js +75 -0
  26. package/dist/parsers/ethiopia/ebirr.parser.js.map +1 -0
  27. package/dist/parsers/ethiopia/index.d.ts +3 -0
  28. package/dist/parsers/ethiopia/index.d.ts.map +1 -0
  29. package/dist/parsers/ethiopia/index.js +14 -0
  30. package/dist/parsers/ethiopia/index.js.map +1 -0
  31. package/dist/parsers/ethiopia/telebirr.parser.d.ts +19 -0
  32. package/dist/parsers/ethiopia/telebirr.parser.d.ts.map +1 -0
  33. package/dist/parsers/ethiopia/telebirr.parser.js +123 -0
  34. package/dist/parsers/ethiopia/telebirr.parser.js.map +1 -0
  35. package/dist/parsers/index.d.ts +13 -0
  36. package/dist/parsers/index.d.ts.map +1 -0
  37. package/dist/parsers/index.js +20 -0
  38. package/dist/parsers/index.js.map +1 -0
  39. package/dist/parsers/kenya/index.d.ts +8 -0
  40. package/dist/parsers/kenya/index.d.ts.map +1 -0
  41. package/dist/parsers/kenya/index.js +10 -0
  42. package/dist/parsers/kenya/index.js.map +1 -0
  43. package/dist/shared/date-parser.util.d.ts +16 -0
  44. package/dist/shared/date-parser.util.d.ts.map +1 -0
  45. package/dist/shared/date-parser.util.js +68 -0
  46. package/dist/shared/date-parser.util.js.map +1 -0
  47. package/dist/shared/parser.interface.d.ts +41 -0
  48. package/dist/shared/parser.interface.d.ts.map +1 -0
  49. package/dist/shared/parser.interface.js +3 -0
  50. package/dist/shared/parser.interface.js.map +1 -0
  51. package/dist/shared/proxy.types.d.ts +27 -0
  52. package/dist/shared/proxy.types.d.ts.map +1 -0
  53. package/dist/shared/proxy.types.js +9 -0
  54. package/dist/shared/proxy.types.js.map +1 -0
  55. package/package.json +62 -0
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EBirrParser = void 0;
4
+ const jsdom_1 = require("jsdom");
5
+ const bank_fetch_service_1 = require("../../core/bank-fetch.service");
6
+ class EBirrParser {
7
+ constructor() {
8
+ this.fallbackFetcher = new bank_fetch_service_1.BankFetchService();
9
+ }
10
+ extract(sms, _accountNumber) {
11
+ const text = this.cleanText(sms);
12
+ const match = text.match(/https:\/\/transactioninfo\.ebirr\.com\/[\w-]+\/receipt\/([A-Z0-9]{8,})/i);
13
+ if (!match)
14
+ return { link: "" };
15
+ return {
16
+ link: `https://transactioninfo.ebirr.com/kaafimf-Ebirr/receipt/${match[1]}`,
17
+ };
18
+ }
19
+ transactionRef(transactionRef) {
20
+ const trx = transactionRef.replace(/[^A-Z0-9]/gi, "").toUpperCase();
21
+ return {
22
+ link: `https://transactioninfo.ebirr.com/kaafimf-Ebirr/receipt/${trx}`,
23
+ };
24
+ }
25
+ async fetch(link, context) {
26
+ if (!link)
27
+ throw new Error("No link provided");
28
+ const fetcher = context?.fetcher ?? this.fallbackFetcher;
29
+ const response = await fetcher.fetch(link, context?.countryCode ?? "ET", {
30
+ timeoutMs: 30000,
31
+ });
32
+ return { page: response.data };
33
+ }
34
+ async receiptParser(html) {
35
+ const dom = new jsdom_1.JSDOM(html);
36
+ const document = dom.window.document;
37
+ const getValueByLabel = (label) => {
38
+ const cells = Array.from(document.querySelectorAll("td.invoice"));
39
+ const labelCell = cells.find((td) => td.textContent?.trim().toUpperCase().includes(label));
40
+ if (!labelCell)
41
+ return "";
42
+ const valueCell = labelCell.nextElementSibling;
43
+ return (valueCell?.textContent?.trim() ?? "").replace(/ETB/gi, "").trim();
44
+ };
45
+ const headings = Array.from(document.querySelectorAll("div.heading"));
46
+ const receiverDiv = headings.find((div) => div.textContent?.includes("Receiver Info"));
47
+ let receiverName = "";
48
+ let receiverAccount = "";
49
+ if (receiverDiv) {
50
+ const table = receiverDiv.nextElementSibling;
51
+ const rows = Array.from(table?.querySelectorAll("tr") ?? []);
52
+ receiverName = rows[1]?.textContent?.trim() ?? "";
53
+ receiverAccount = rows[3]?.textContent?.trim() ?? "";
54
+ }
55
+ return {
56
+ bank: "EBIRR",
57
+ receipt: {
58
+ date: getValueByLabel("DATE"),
59
+ transactionNumber: getValueByLabel("RECEIPT NO"),
60
+ amount: getValueByLabel("AMOUNT"),
61
+ receiverName,
62
+ receiverAccount,
63
+ },
64
+ };
65
+ }
66
+ cleanText(text) {
67
+ return text
68
+ .replace(/\s+/g, " ")
69
+ .replace(/https:\s*\/\//gi, "https://")
70
+ .replace(/\s*\/\s*/g, "/")
71
+ .trim();
72
+ }
73
+ }
74
+ exports.EBirrParser = EBirrParser;
75
+ //# sourceMappingURL=ebirr.parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ebirr.parser.js","sourceRoot":"","sources":["../../../src/parsers/ethiopia/ebirr.parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { ParserRegistry } from "../../shared/parser.interface";
2
+ export declare const ETHIOPIA_PARSER_REGISTRY: ParserRegistry;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/parsers/ethiopia/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAM/D,eAAO,MAAM,wBAAwB,EAAE,cAKtC,CAAC"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ETHIOPIA_PARSER_REGISTRY = void 0;
4
+ const cbe_parser_1 = require("./cbe.parser");
5
+ const telebirr_parser_1 = require("./telebirr.parser");
6
+ const abyssinia_parser_1 = require("./abyssinia.parser");
7
+ const ebirr_parser_1 = require("./ebirr.parser");
8
+ exports.ETHIOPIA_PARSER_REGISTRY = {
9
+ CBE: new cbe_parser_1.CbeParser(),
10
+ TELEBIRR: new telebirr_parser_1.TelebirrParser(),
11
+ ABYSSINIA: new abyssinia_parser_1.AbyssiniaParser(),
12
+ EBIRR: new ebirr_parser_1.EBirrParser(),
13
+ };
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/parsers/ethiopia/index.ts"],"names":[],"mappings":";;;AACA,6CAAyC;AACzC,uDAAmD;AACnD,yDAAqD;AACrD,iDAA6C;AAEhC,QAAA,wBAAwB,GAAmB;IACtD,GAAG,EAAE,IAAI,sBAAS,EAAE;IACpB,QAAQ,EAAE,IAAI,gCAAc,EAAE;IAC9B,SAAS,EAAE,IAAI,kCAAe,EAAE;IAChC,KAAK,EAAE,IAAI,0BAAW,EAAE;CACzB,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { ParserAndExtractor, ParserFetchContext, RawReceipt } from "../../shared/parser.interface";
2
+ export declare class TelebirrParser implements ParserAndExtractor {
3
+ private readonly fallbackFetcher;
4
+ extract(text: string, _accountNumber?: string): {
5
+ link: string;
6
+ };
7
+ transactionRef(transactionRef: string): {
8
+ link: string;
9
+ };
10
+ fetch(link: string, context?: ParserFetchContext): Promise<{
11
+ page: any;
12
+ }>;
13
+ receiptParser(html: string): Promise<{
14
+ bank: string;
15
+ receipt: RawReceipt;
16
+ }>;
17
+ private cleanText;
18
+ }
19
+ //# sourceMappingURL=telebirr.parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telebirr.parser.d.ts","sourceRoot":"","sources":["../../../src/parsers/ethiopia/telebirr.parser.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,UAAU,EACX,MAAM,+BAA+B,CAAC;AAEvC,qBAAa,cAAe,YAAW,kBAAkB;IACvD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0B;IAE1D,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IA+BhE,cAAc,CAAC,cAAc,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IAKlD,KAAK,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,CAAA;KAAE,CAAC;IAenB,aAAa,CACjB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,UAAU,CAAA;KAAE,CAAC;IA0CjD,OAAO,CAAC,SAAS;CAOlB"}
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.TelebirrParser = void 0;
37
+ const cheerio = __importStar(require("cheerio"));
38
+ const bank_fetch_service_1 = require("../../core/bank-fetch.service");
39
+ class TelebirrParser {
40
+ constructor() {
41
+ this.fallbackFetcher = new bank_fetch_service_1.BankFetchService();
42
+ }
43
+ extract(text, _accountNumber) {
44
+ if (!text)
45
+ return { link: "" };
46
+ const cleaned = this.cleanText(text);
47
+ const txnNumberMatch = cleaned.match(/your transaction number is\s+([A-Z0-9]{8,12})/i);
48
+ if (txnNumberMatch) {
49
+ const trx = txnNumberMatch[1].replace(/[^A-Z0-9]/gi, "").toUpperCase();
50
+ return { link: `https://transactioninfo.ethiotelecom.et/receipt/${trx}` };
51
+ }
52
+ const appShareMatch = cleaned.match(/Transaction\s+Number\s*[:\-]?\s*([A-Z0-9]{8,12})(?:\s|$|[^A-Z0-9])/i);
53
+ if (appShareMatch) {
54
+ const trx = appShareMatch[1].replace(/[^A-Z0-9]/gi, "").toUpperCase();
55
+ return { link: `https://transactioninfo.ethiotelecom.et/receipt/${trx}` };
56
+ }
57
+ const rawMatch = text.match(/your transaction number is\s+([A-Z0-9]{8,12})/i);
58
+ if (rawMatch) {
59
+ const trx = rawMatch[1].replace(/[^A-Z0-9]/gi, "").toUpperCase();
60
+ return { link: `https://transactioninfo.ethiotelecom.et/receipt/${trx}` };
61
+ }
62
+ return { link: "" };
63
+ }
64
+ transactionRef(transactionRef) {
65
+ const trx = transactionRef.replace(/[^A-Z0-9]/gi, "").toUpperCase();
66
+ return { link: `https://transactioninfo.ethiotelecom.et/receipt/${trx}` };
67
+ }
68
+ async fetch(link, context) {
69
+ if (!link)
70
+ throw new Error("No link provided");
71
+ const fetcher = context?.fetcher ?? this.fallbackFetcher;
72
+ const response = await fetcher.fetchBrowserPage(link, context?.countryCode ?? "ET", {
73
+ waitUntil: "domcontentloaded",
74
+ waitForSelector: "table",
75
+ timeoutMs: 60000,
76
+ });
77
+ return { page: response.data };
78
+ }
79
+ async receiptParser(html) {
80
+ const $ = cheerio.load(html);
81
+ let transactionRow;
82
+ $("tr").each((_, tr) => {
83
+ const tds = $(tr).find("td");
84
+ if (tds.length === 3) {
85
+ const tx = tds.eq(0).text().trim();
86
+ if (/^[A-Z0-9]{8,12}$/.test(tx)) {
87
+ transactionRow = tds;
88
+ }
89
+ }
90
+ });
91
+ if (!transactionRow) {
92
+ throw new Error("Invalid Telebirr receipt: transaction row not found");
93
+ }
94
+ const extractByLabel = (label) => $("td")
95
+ .filter((_, el) => $(el).text().includes(label))
96
+ .next("td")
97
+ .text()
98
+ .trim();
99
+ return {
100
+ bank: "TELEBIRR",
101
+ receipt: {
102
+ transactionNumber: transactionRow.eq(0).text().trim(),
103
+ date: transactionRow.eq(1).text().trim(),
104
+ amount: transactionRow
105
+ .eq(2)
106
+ .text()
107
+ .trim()
108
+ .replace(/[^\d.]/g, ""),
109
+ receiverName: extractByLabel("Credited Party name"),
110
+ receiverAccount: extractByLabel("Credited party account no"),
111
+ },
112
+ };
113
+ }
114
+ cleanText(text) {
115
+ return text
116
+ .replace(/\s+/g, " ")
117
+ .replace(/https:\s*\/\//gi, "https://")
118
+ .replace(/\s*\/\s*/g, "/")
119
+ .trim();
120
+ }
121
+ }
122
+ exports.TelebirrParser = TelebirrParser;
123
+ //# sourceMappingURL=telebirr.parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telebirr.parser.js","sourceRoot":"","sources":["../../../src/parsers/ethiopia/telebirr.parser.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAmC;AAEnC,sEAAiE;AAOjE,MAAa,cAAc;IAA3B;QACmB,oBAAe,GAAG,IAAI,qCAAgB,EAAE,CAAC;IA2G5D,CAAC;IAzGC,OAAO,CAAC,IAAY,EAAE,cAAuB;QAC3C,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAErC,MAAM,cAAc,GAAG,OAAO,CAAC,KAAK,CAClC,gDAAgD,CACjD,CAAC;QACF,IAAI,cAAc,EAAE,CAAC;YACnB,MAAM,GAAG,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;YACvE,OAAO,EAAE,IAAI,EAAE,mDAAmD,GAAG,EAAE,EAAE,CAAC;QAC5E,CAAC;QAED,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,CACjC,qEAAqE,CACtE,CAAC;QACF,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;YACtE,OAAO,EAAE,IAAI,EAAE,mDAAmD,GAAG,EAAE,EAAE,CAAC;QAC5E,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CACzB,gDAAgD,CACjD,CAAC;QACF,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;YACjE,OAAO,EAAE,IAAI,EAAE,mDAAmD,GAAG,EAAE,EAAE,CAAC;QAC5E,CAAC;QAED,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;IACtB,CAAC;IAED,cAAc,CAAC,cAAsB;QACnC,MAAM,GAAG,GAAG,cAAc,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QACpE,OAAO,EAAE,IAAI,EAAE,mDAAmD,GAAG,EAAE,EAAE,CAAC;IAC5E,CAAC;IAED,KAAK,CAAC,KAAK,CACT,IAAY,EACZ,OAA4B;QAE5B,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAC/C,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC,eAAe,CAAC;QACzD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAC7C,IAAI,EACJ,OAAO,EAAE,WAAW,IAAI,IAAI,EAC5B;YACE,SAAS,EAAE,kBAAkB;YAC7B,eAAe,EAAE,OAAO;YACxB,SAAS,EAAE,KAAK;SACjB,CACF,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,IAAY;QAEZ,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE7B,IAAI,cAAoD,CAAC;QAEzD,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE;YACrB,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7B,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACrB,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;gBACnC,IAAI,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;oBAChC,cAAc,GAAG,GAAG,CAAC;gBACvB,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,CAAC;QAED,MAAM,cAAc,GAAG,CAAC,KAAa,EAAU,EAAE,CAC/C,CAAC,CAAC,IAAI,CAAC;aACJ,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;aAC/C,IAAI,CAAC,IAAI,CAAC;aACV,IAAI,EAAE;aACN,IAAI,EAAE,CAAC;QAEZ,OAAO;YACL,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE;gBACP,iBAAiB,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;gBACrD,IAAI,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;gBACxC,MAAM,EAAE,cAAc;qBACnB,EAAE,CAAC,CAAC,CAAC;qBACL,IAAI,EAAE;qBACN,IAAI,EAAE;qBACN,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC;gBACzB,YAAY,EAAE,cAAc,CAAC,qBAAqB,CAAC;gBACnD,eAAe,EAAE,cAAc,CAAC,2BAA2B,CAAC;aAC7D;SACF,CAAC;IACJ,CAAC;IAEO,SAAS,CAAC,IAAY;QAC5B,OAAO,IAAI;aACR,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;aACpB,OAAO,CAAC,iBAAiB,EAAE,UAAU,CAAC;aACtC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC;aACzB,IAAI,EAAE,CAAC;IACZ,CAAC;CACF;AA5GD,wCA4GC"}
@@ -0,0 +1,13 @@
1
+ import { ParserRegistry } from "../shared/parser.interface";
2
+ /**
3
+ * Master parser registry — maps parserKey → parser instance.
4
+ *
5
+ * TO ADD A NEW COUNTRY:
6
+ * 1. Create src/parsers/<country>/<bank>.parser.ts
7
+ * 2. Create src/parsers/<country>/index.ts and export the registry
8
+ * 3. Spread it into this object below
9
+ *
10
+ * That's it — the extraction engine picks it up automatically.
11
+ */
12
+ export declare const PARSER_REGISTRY: ParserRegistry;
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parsers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAI5D;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,cAG7B,CAAC"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PARSER_REGISTRY = void 0;
4
+ const ethiopia_1 = require("./ethiopia");
5
+ const kenya_1 = require("./kenya");
6
+ /**
7
+ * Master parser registry — maps parserKey → parser instance.
8
+ *
9
+ * TO ADD A NEW COUNTRY:
10
+ * 1. Create src/parsers/<country>/<bank>.parser.ts
11
+ * 2. Create src/parsers/<country>/index.ts and export the registry
12
+ * 3. Spread it into this object below
13
+ *
14
+ * That's it — the extraction engine picks it up automatically.
15
+ */
16
+ exports.PARSER_REGISTRY = {
17
+ ...ethiopia_1.ETHIOPIA_PARSER_REGISTRY,
18
+ ...kenya_1.KENYA_PARSER_REGISTRY,
19
+ };
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parsers/index.ts"],"names":[],"mappings":";;;AACA,yCAAsD;AACtD,mCAAgD;AAEhD;;;;;;;;;GASG;AACU,QAAA,eAAe,GAAmB;IAC7C,GAAG,mCAAwB;IAC3B,GAAG,6BAAqB;CACzB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { ParserRegistry } from "../../shared/parser.interface";
2
+ /**
3
+ * Kenya parsers — stubs, not yet implemented.
4
+ * Add parsers here as they are built.
5
+ * Set Bank.isActive = false in the DB until each one is ready.
6
+ */
7
+ export declare const KENYA_PARSER_REGISTRY: ParserRegistry;
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/parsers/kenya/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,cAAmB,CAAC"}
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KENYA_PARSER_REGISTRY = void 0;
4
+ /**
5
+ * Kenya parsers — stubs, not yet implemented.
6
+ * Add parsers here as they are built.
7
+ * Set Bank.isActive = false in the DB until each one is ready.
8
+ */
9
+ exports.KENYA_PARSER_REGISTRY = {};
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/parsers/kenya/index.ts"],"names":[],"mappings":";;;AAEA;;;;GAIG;AACU,QAAA,qBAAqB,GAAmB,EAAE,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Safely parse a raw date string — returns null instead of throwing.
3
+ * Use when a missing date should be handled gracefully.
4
+ */
5
+ export declare const safeParsDate: (raw: string | null | undefined) => Date | null;
6
+ /**
7
+ * Parse a raw bank date string into a Date object.
8
+ *
9
+ * Supported formats:
10
+ * - eBirr: "2026-02-11 20:07:02 +0300 EAT"
11
+ * - Telebirr: "18-03-2026 21:46:09"
12
+ * - CBE PDF: "3/11/2026, 6:15:00 PM"
13
+ * - BOA: "23/01/26 14:04" or "23/01/2026 14:04"
14
+ */
15
+ export declare const parseDate: (raw: string) => Date;
16
+ //# sourceMappingURL=date-parser.util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-parser.util.d.ts","sourceRoot":"","sources":["../../src/shared/date-parser.util.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,KAAG,IAAI,GAAG,IAQpE,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,GAAI,KAAK,MAAM,KAAG,IAuDvC,CAAC"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseDate = exports.safeParsDate = void 0;
4
+ const pad = (n) => n.toString().padStart(2, "0");
5
+ /**
6
+ * Safely parse a raw date string — returns null instead of throwing.
7
+ * Use when a missing date should be handled gracefully.
8
+ */
9
+ const safeParsDate = (raw) => {
10
+ if (!raw?.trim())
11
+ return null;
12
+ try {
13
+ const d = (0, exports.parseDate)(raw);
14
+ return isNaN(d.getTime()) ? null : d;
15
+ }
16
+ catch {
17
+ return null;
18
+ }
19
+ };
20
+ exports.safeParsDate = safeParsDate;
21
+ /**
22
+ * Parse a raw bank date string into a Date object.
23
+ *
24
+ * Supported formats:
25
+ * - eBirr: "2026-02-11 20:07:02 +0300 EAT"
26
+ * - Telebirr: "18-03-2026 21:46:09"
27
+ * - CBE PDF: "3/11/2026, 6:15:00 PM"
28
+ * - BOA: "23/01/26 14:04" or "23/01/2026 14:04"
29
+ */
30
+ const parseDate = (raw) => {
31
+ if (!raw?.trim())
32
+ throw new Error("Invalid date input: empty string");
33
+ const cleaned = raw.trim();
34
+ // eBirr: "2026-02-11 20:07:02 +0300 EAT"
35
+ const ebirrMatch = cleaned.match(/^(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})\s+([+-]\d{4})/);
36
+ if (ebirrMatch) {
37
+ const [, year, month, day, hour, minute, second, rawOffset] = ebirrMatch;
38
+ const offset = rawOffset.replace(/([+-]\d{2})(\d{2})$/, "$1:$2");
39
+ return new Date(`${year}-${month}-${day}T${hour}:${minute}:${second}${offset}`);
40
+ }
41
+ // Telebirr: "18-03-2026 21:46:09"
42
+ const telebirrMatch = cleaned.match(/^(\d{2})-(\d{2})-(\d{4})\s+(\d{2}):(\d{2}):(\d{2})$/);
43
+ if (telebirrMatch) {
44
+ const [, day, month, year, hour, minute, second] = telebirrMatch;
45
+ return new Date(`${year}-${month}-${day}T${hour}:${minute}:${second}+03:00`);
46
+ }
47
+ // CBE PDF: "3/11/2026, 6:15:00 PM"
48
+ const cbeMatch = cleaned.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4}),\s*(\d{1,2}):(\d{2}):(\d{2})\s*(AM|PM)$/i);
49
+ if (cbeMatch) {
50
+ const [, month, day, year, rawHour, minute, second, meridiem] = cbeMatch;
51
+ let h = parseInt(rawHour, 10);
52
+ if (meridiem.toUpperCase() === "PM" && h !== 12)
53
+ h += 12;
54
+ if (meridiem.toUpperCase() === "AM" && h === 12)
55
+ h = 0;
56
+ return new Date(`${year}-${pad(month)}-${pad(day)}T${pad(h)}:${minute}:${second}+03:00`);
57
+ }
58
+ // BOA: "23/01/26 14:04" or "23/01/2026 14:04"
59
+ const boaMatch = cleaned.match(/^(\d{1,2})\/(\d{1,2})\/(\d{2,4})\s+(\d{1,2}):(\d{2})$/);
60
+ if (boaMatch) {
61
+ const [, day, month, shortYear, hour, minute] = boaMatch;
62
+ const year = shortYear.length === 2 ? `20${shortYear}` : shortYear;
63
+ return new Date(`${year}-${pad(month)}-${pad(day)}T${pad(hour)}:${minute}:00+03:00`);
64
+ }
65
+ throw new Error(`Unsupported date format: "${raw}"`);
66
+ };
67
+ exports.parseDate = parseDate;
68
+ //# sourceMappingURL=date-parser.util.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-parser.util.js","sourceRoot":"","sources":["../../src/shared/date-parser.util.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { BankFetchService } from "../core/bank-fetch.service";
2
+ /**
3
+ * Raw receipt fields returned by every bank parser.
4
+ * All values are strings at extraction time.
5
+ */
6
+ export interface RawReceipt {
7
+ transactionNumber: string;
8
+ date: string;
9
+ amount: string;
10
+ receiverAccount: string;
11
+ receiverName: string;
12
+ }
13
+ export interface ParserFetchContext {
14
+ fetcher: BankFetchService;
15
+ countryCode: string;
16
+ }
17
+ /**
18
+ * Contract that every bank parser must implement.
19
+ *
20
+ * Three-step flow:
21
+ * 1. extract(text) → derives the receipt URL from raw SMS/OCR text
22
+ * 2. fetch(link) → downloads the receipt page from the bank
23
+ * 3. receiptParser → parses the page into a structured RawReceipt
24
+ */
25
+ export interface ParserAndExtractor {
26
+ extract(text: string, accountNumber?: string): {
27
+ link: string;
28
+ };
29
+ transactionRef?(transactionRef: string, accountNumber?: string): {
30
+ link: string;
31
+ };
32
+ fetch(link: string, context?: ParserFetchContext): Promise<{
33
+ page: any;
34
+ }>;
35
+ receiptParser(input: any): Promise<{
36
+ bank: string;
37
+ receipt: RawReceipt;
38
+ }>;
39
+ }
40
+ export type ParserRegistry = Record<string, ParserAndExtractor>;
41
+ //# sourceMappingURL=parser.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.interface.d.ts","sourceRoot":"","sources":["../../src/shared/parser.interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAChE,cAAc,CAAC,CACb,cAAc,EAAE,MAAM,EACtB,aAAa,CAAC,EAAE,MAAM,GACrB;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACpB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IAC1E,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,UAAU,CAAA;KAAE,CAAC,CAAC;CAC3E;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=parser.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.interface.js","sourceRoot":"","sources":["../../src/shared/parser.interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ export declare enum ProxyType {
2
+ HTTP_CONNECT = "HTTP_CONNECT",
3
+ SOCKS5 = "SOCKS5"
4
+ }
5
+ export interface ProxyConfig {
6
+ enabled: boolean;
7
+ url: string | null;
8
+ type: ProxyType;
9
+ }
10
+ /**
11
+ * Implement this interface in your host application and pass it to
12
+ * BankFetchService. The library never reads a database directly.
13
+ *
14
+ * Example with Prisma:
15
+ *
16
+ * class MyProxyResolver implements ProxyResolver {
17
+ * async resolve(countryCode: string) {
18
+ * const row = await prisma.countryProxy.findUnique({ where: { countryCode } });
19
+ * if (!row?.proxyEnabled) return null;
20
+ * return { enabled: true, url: row.proxyUrl, type: row.proxyType as ProxyType };
21
+ * }
22
+ * }
23
+ */
24
+ export interface ProxyResolver {
25
+ resolve(countryCode: string): Promise<ProxyConfig | null>;
26
+ }
27
+ //# sourceMappingURL=proxy.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.types.d.ts","sourceRoot":"","sources":["../../src/shared/proxy.types.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS;IACnB,YAAY,iBAAiB;IAC7B,MAAM,WAAW;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,IAAI,EAAE,SAAS,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CAC3D"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProxyType = void 0;
4
+ var ProxyType;
5
+ (function (ProxyType) {
6
+ ProxyType["HTTP_CONNECT"] = "HTTP_CONNECT";
7
+ ProxyType["SOCKS5"] = "SOCKS5";
8
+ })(ProxyType || (exports.ProxyType = ProxyType = {}));
9
+ //# sourceMappingURL=proxy.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.types.js","sourceRoot":"","sources":["../../src/shared/proxy.types.ts"],"names":[],"mappings":";;;AAAA,IAAY,SAGX;AAHD,WAAY,SAAS;IACnB,0CAA6B,CAAA;IAC7B,8BAAiB,CAAA;AACnB,CAAC,EAHW,SAAS,yBAAT,SAAS,QAGpB"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@localpay/verification-engine",
3
+ "version": "0.1.0",
4
+ "description": "Bank receipt verification engine for Ethiopian and East African banks",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "build:watch": "tsc --watch",
21
+ "lint": "tsc --noEmit",
22
+ "test": "npm run build && node --test tests/*.test.js",
23
+ "prepublishOnly": "npm test"
24
+ },
25
+ "keywords": [
26
+ "localpay",
27
+ "verification",
28
+ "bank",
29
+ "receipt",
30
+ "ethiopia",
31
+ "africa"
32
+ ],
33
+ "author": "LocalPay",
34
+ "license": "MIT",
35
+ "engines": {
36
+ "node": ">=20.19.0"
37
+ },
38
+ "sideEffects": false,
39
+ "dependencies": {
40
+ "axios": "^1.13.6",
41
+ "cheerio": "^1.2.0",
42
+ "https-proxy-agent": "^7.0.2",
43
+ "jsdom": "^28.1.0",
44
+ "pdf-parse": "^1.1.4",
45
+ "socks-proxy-agent": "^8.0.5",
46
+ "tesseract.js": "^7.0.0"
47
+ },
48
+ "peerDependencies": {
49
+ "puppeteer": "^24.0.0"
50
+ },
51
+ "peerDependenciesMeta": {
52
+ "puppeteer": {
53
+ "optional": true
54
+ }
55
+ },
56
+ "devDependencies": {
57
+ "@types/node": "^22.0.0",
58
+ "@types/pdf-parse": "^1.1.4",
59
+ "puppeteer": "^24.0.0",
60
+ "typescript": "^5.7.3"
61
+ }
62
+ }