{"_id":"@angloqq03/gpv","_rev":"6-be560773ae6456d6baf707ce7753f7dd","name":"@angloqq03/gpv","dist-tags":{"latest":"1.1.4"},"versions":{"1.0.0":{"name":"@angloqq03/gpv","version":"1.0.0","keywords":["gcash","ocr","tesseract","brainjs","brain.js","fraud-detection","payment-proof","receipt-validator","reference-validator"],"author":{"name":"anglo"},"license":"MIT","_id":"@angloqq03/gpv@1.0.0","maintainers":[{"name":"angloqq03","email":"angeloqq03@gmail.com"}],"dist":{"shasum":"e273fb43de6ddf63f1920bba3e2f7d63061f9f75","tarball":"https://registry.npmjs.org/@angloqq03/gpv/-/gpv-1.0.0.tgz","fileCount":21,"integrity":"sha512-9aY14J5qpyilSMO01kmkR2gNDSZOR59i6oEuNDXuw1NnS2lZHM8qdKr3zLeBjgTKx2THuE4WkTHfgTH+GsHu0w==","signatures":[{"sig":"MEQCIAzHUDn16EE5/1BgYWGdsv59+j6khiTmXSfJAfOXI2ECAiAObo4tUgVz1F4Io/CLiF4NVE2q+WmvaVSXfZXiNuS34w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1024362},"main":"./index.js","type":"module","types":"./index.d.ts","engines":{"node":">=18"},"exports":{".":"./index.js"},"scripts":{"test":"node test.js","train:model":"node scripts/train-model.js"},"_npmUser":{"name":"angloqq03","email":"angeloqq03@gmail.com"},"_npmVersion":"11.8.0","description":"OCR-powered GCash screenshot proof validation for Node.js using Tesseract.js and Brain.js.","directories":{},"_nodeVersion":"24.13.1","dependencies":{"brain.js":"^1.6.1","tesseract.js":"^6.0.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gpv_1.0.0_1775152643145_0.45398213760643835","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@angloqq03/gpv","version":"1.1.0","keywords":["gcash","ocr","tesseract","brainjs","brain.js","fraud-detection","payment-proof","receipt-validator","reference-validator"],"author":{"name":"anglo"},"license":"MIT","_id":"@angloqq03/gpv@1.1.0","maintainers":[{"name":"angloqq03","email":"angeloqq03@gmail.com"}],"dist":{"shasum":"2d602124f6ab83c1969d2128e807702b2453a861","tarball":"https://registry.npmjs.org/@angloqq03/gpv/-/gpv-1.1.0.tgz","fileCount":24,"integrity":"sha512-PTu06z1uc/AUPJ8m5T3M/Jzwcw+2Tfk3KTBWOu6f/ZW45gFUVzfjZ9Q7Ky/10IaHvloX2nbZAeZWmvBvQDV6qg==","signatures":[{"sig":"MEQCIBuJ5Cgs36q8RvXNf7+OkkWNjHdY4wu6rX4DYG4LYsECAiBHuTvYdXgYS4q1fXvzPNIv0krUipGuSgZBF/8Mt3RtMw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1041533},"main":"./index.js","type":"module","types":"./index.d.ts","engines":{"node":">=18"},"exports":{".":"./index.js"},"scripts":{"demo":"node scripts/run-demo.js","test":"node test.js","train:model":"node scripts/train-model.js"},"_npmUser":{"name":"angloqq03","email":"angeloqq03@gmail.com"},"_npmVersion":"11.8.0","description":"OCR-powered GCash screenshot proof validation for Node.js using Tesseract.js and Brain.js.","directories":{},"_nodeVersion":"24.13.1","dependencies":{"multer":"^2.0.2","express":"^5.1.0","brain.js":"^1.6.1","tesseract.js":"^6.0.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gpv_1.1.0_1775153731955_0.9946804921122381","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@angloqq03/gpv","version":"1.1.1","keywords":["gcash","ocr","tesseract","brainjs","brain.js","fraud-detection","payment-proof","receipt-validator","reference-validator"],"author":{"name":"anglo"},"license":"MIT","_id":"@angloqq03/gpv@1.1.1","maintainers":[{"name":"angloqq03","email":"angeloqq03@gmail.com"}],"dist":{"shasum":"909a9a70806a5b0b732b847806bad738c671ecba","tarball":"https://registry.npmjs.org/@angloqq03/gpv/-/gpv-1.1.1.tgz","fileCount":24,"integrity":"sha512-hZWMpaD74QeHt0+Zgr6MzG65/CgKEiQlR2QTlKNIZnBp0BsDveVU2RMTwosGsJMOig1oB9R531/ELr89qIvOHA==","signatures":[{"sig":"MEUCIEc8vLLi3cHVZNpQHCC+kd32IVoFoJCsb1kBSIArl4JeAiEA8iTx4mEHAuLEnc5rqAuP7Y+ohyVUQeWwk+47tvTANFA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1043374},"main":"./index.js","type":"module","types":"./index.d.ts","engines":{"node":">=18"},"exports":{".":"./index.js"},"scripts":{"demo":"node scripts/run-demo.js","test":"node test.js","train:model":"node scripts/train-model.js"},"_npmUser":{"name":"angloqq03","email":"angeloqq03@gmail.com"},"_npmVersion":"11.8.0","description":"OCR-powered GCash screenshot proof validation for Node.js using Tesseract.js and Brain.js.","directories":{},"_nodeVersion":"24.13.1","dependencies":{"multer":"^2.0.2","express":"^5.1.0","brain.js":"^1.6.1","tesseract.js":"^6.0.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gpv_1.1.1_1775156681629_0.7733657041619946","host":"s3://npm-registry-packages-npm-production"}},"1.1.2":{"name":"@angloqq03/gpv","version":"1.1.2","keywords":["gcash","ocr","tesseract","brainjs","brain.js","fraud-detection","payment-proof","receipt-validator","reference-validator"],"author":{"name":"anglo"},"license":"MIT","_id":"@angloqq03/gpv@1.1.2","maintainers":[{"name":"angloqq03","email":"angeloqq03@gmail.com"}],"dist":{"shasum":"f1bb18133641b8401525e24af2d42634c69a47ea","tarball":"https://registry.npmjs.org/@angloqq03/gpv/-/gpv-1.1.2.tgz","fileCount":24,"integrity":"sha512-/HxQZR35ZM31pLP1BubI1cQ+qaB9dcMc3ZdRYicB9MxPOg07sBOYtsQF7KbsoA6YfVKvOJgT5ZYJglHhbj4vnQ==","signatures":[{"sig":"MEQCIEf54a/oVAVPSw6XHNfkj3iKMWeWFNSkcBjN3/2sV7uTAiA+vOk27CfQDRUz5MqlUl/4rzAa1XMeQbUvPmQ1N+nBpg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1047306},"main":"./index.js","type":"module","types":"./index.d.ts","engines":{"node":">=18"},"exports":{".":"./index.js"},"scripts":{"demo":"node scripts/run-demo.js","test":"node test.js","train:model":"node scripts/train-model.js"},"_npmUser":{"name":"angloqq03","email":"angeloqq03@gmail.com"},"_npmVersion":"11.8.0","description":"OCR-powered GCash screenshot proof validation for Node.js using Tesseract.js and Brain.js.","directories":{},"_nodeVersion":"24.13.1","dependencies":{"multer":"^2.0.2","express":"^5.1.0","brain.js":"^1.6.1","tesseract.js":"^6.0.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gpv_1.1.2_1775157506744_0.792911161985373","host":"s3://npm-registry-packages-npm-production"}},"1.1.3":{"name":"@angloqq03/gpv","version":"1.1.3","keywords":["gcash","ocr","tesseract","brainjs","brain.js","fraud-detection","payment-proof","receipt-validator","reference-validator"],"author":{"name":"anglo"},"license":"MIT","_id":"@angloqq03/gpv@1.1.3","maintainers":[{"name":"angloqq03","email":"angeloqq03@gmail.com"}],"dist":{"shasum":"685603de746fbf59600adc6be200f71290447315","tarball":"https://registry.npmjs.org/@angloqq03/gpv/-/gpv-1.1.3.tgz","fileCount":24,"integrity":"sha512-mK17FlyNfc9+1VwMQikhwQLqQC6ypuhRJcin1UH/vV0S8Hu19fnVzOFs85Lyu5EulfMx0hUz2mTtck+lsIBX6w==","signatures":[{"sig":"MEUCIAbJR2t/pwJxVTyjDfeMN3Y3fAI3yiJZSUf2Lp6SdCQ6AiEAyUNQslE0qND8tDD06ESPEJhqEQZwME5wu9gmQiEPalc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1046802},"main":"./index.js","type":"module","types":"./index.d.ts","engines":{"node":">=18"},"exports":{".":"./index.js"},"scripts":{"demo":"node scripts/run-demo.js","test":"node test.js","train:model":"node scripts/train-model.js"},"_npmUser":{"name":"angloqq03","email":"angeloqq03@gmail.com"},"_npmVersion":"11.8.0","description":"OCR-powered GCash screenshot proof validation for Node.js using Tesseract.js and Brain.js.","directories":{},"_nodeVersion":"24.13.1","dependencies":{"multer":"^2.0.2","express":"^5.1.0","brain.js":"^1.6.1","tesseract.js":"^6.0.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/gpv_1.1.3_1775158018943_0.6884858804664473","host":"s3://npm-registry-packages-npm-production"}},"1.1.4":{"name":"@angloqq03/gpv","version":"1.1.4","description":"OCR-powered GCash screenshot proof validation for Node.js using Tesseract.js and Brain.js.","type":"module","main":"./index.js","exports":{".":"./index.js"},"scripts":{"test":"node test.js","train:model":"node scripts/train-model.js","demo":"node scripts/run-demo.js"},"keywords":["gcash","ocr","tesseract","brainjs","brain.js","fraud-detection","payment-proof","receipt-validator","reference-validator"],"author":{"name":"anglo"},"license":"MIT","dependencies":{"brain.js":"^1.6.1","express":"^5.1.0","multer":"^2.0.2","tesseract.js":"^6.0.1"},"engines":{"node":">=18"},"types":"./index.d.ts","_id":"@angloqq03/gpv@1.1.4","_nodeVersion":"24.13.1","_npmVersion":"11.8.0","dist":{"integrity":"sha512-jt5SSJUrvsd+kQjbhGgEr9IhpDkYxeJFi4di/BnFZFr+OHIz3tD6DR9OKHQgy8xdmOTMh0sPuqTf5RiPOk1fEA==","shasum":"118c0067e9073ec6854368cb5ab7b95a48345ea7","tarball":"https://registry.npmjs.org/@angloqq03/gpv/-/gpv-1.1.4.tgz","fileCount":24,"unpackedSize":1046160,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGbBnQGhvmUasu/VLK/4Ab8M2ITn5IarR3TzQeZSiSSCAiEA+ACss7BTrsHp65Lbx92OlKoCsrN6h40lkwPu2BRa6lM="}]},"_npmUser":{"name":"angloqq03","email":"angeloqq03@gmail.com"},"directories":{},"maintainers":[{"name":"angloqq03","email":"angeloqq03@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/gpv_1.1.4_1775232967820_0.007350714952853332"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-02T17:57:23.037Z","modified":"2026-04-03T16:16:08.107Z","1.0.0":"2026-04-02T17:57:23.343Z","1.1.0":"2026-04-02T18:15:32.187Z","1.1.1":"2026-04-02T19:04:41.842Z","1.1.2":"2026-04-02T19:18:26.941Z","1.1.3":"2026-04-02T19:26:59.211Z","1.1.4":"2026-04-03T16:16:07.997Z"},"author":{"name":"anglo"},"license":"MIT","keywords":["gcash","ocr","tesseract","brainjs","brain.js","fraud-detection","payment-proof","receipt-validator","reference-validator"],"description":"OCR-powered GCash screenshot proof validation for Node.js using Tesseract.js and Brain.js.","maintainers":[{"name":"angloqq03","email":"angeloqq03@gmail.com"}],"readme":"# @angloqq03/gpv\n\nGPV is a GCash proof validator toolkit for Node.js.\n\nIt gives you two main paths:\n\n- OCR-only mode if you just want to extract text, reference, amount, and date\n- OCR + risk scoring mode if you also want Brain.js-based fraud signals\n\nUnder the hood, GPV uses:\n\n- `tesseract.js` for OCR\n- `brain.js` for risk scoring\n\nIt also ships with an interactive Express demo so developers can test everything in a browser before integrating it into a real app.\n\n## Why GPV? 💸\n\nPayment proof screenshots are useful, but they can also be:\n\n- edited\n- cropped\n- reused\n- partially hidden\n- taken from different bank apps and passed off as something else\n\nGPV helps you:\n\n- read proof screenshots\n- extract likely proof fields\n- compare them against expected transaction data\n- optionally score how suspicious the proof looks\n\n## Pick your mode ✨\n\n### 1. OCR-only mode\n\nUse this when you only want extraction and parsing.\n\nMain functions:\n\n- `extractTextFromImage()`\n- `parseProofText()`\n- `extractProofDetails()`\n- `isReferenceDetected()`\n- `isAmountDetected()`\n- `isDateDetected()`\n\n### 2. Default built-in model mode\n\nUse this when you want OCR plus the package's built-in Brain.js JSON model.\n\nMain functions:\n\n- `validateProof()`\n- `fullAnalysis()`\n- `validateUploadedProof()`\n- `analyzeUploadedProof()`\n- `createExpressProofValidator()`\n\n### 3. Custom model mode\n\nUse this when you want to train your own Brain.js model from real proof samples.\n\nMain functions:\n\n- `npm run train:model`\n- `loadFraudModelFromFile()`\n- `setFraudModel()`\n- `resetFraudModel()`\n\nOnce you call `setFraudModel(customModel)`, GPV uses your custom model for scoring.\n\n## Install 📦\n\n```bash\nnpm install @angloqq03/gpv\n```\n\nThe required dependencies are installed automatically through npm.\n\n## Super quick start 🚀\n\n```js\nimport { isRefValid, fullAnalysis } from \"@angloqq03/gpv\";\n\nconsole.log(isRefValid(\"123456789012\"));\n\nconst result = await fullAnalysis(\"./proof.png\", {\n  reference: \"123456789012\",\n  amount: 499.99,\n  date: \"2026-04-03\"\n});\n\nconsole.log(result.ok);\nconsole.log(result.extracted);\nconsole.log(result.risk);\n```\n\n## Interactive demo server 🧪\n\nIf you want a browser playground for the package:\n\n```bash\nnpm run demo\n```\n\nThen open:\n\n```text\nhttp://localhost:3210/demo/\n```\n\nWhat you can do in the demo:\n\n- upload a proof image\n- switch between `OCR only`, `Validate with model`, and `Full analysis`\n- set expected reference, amount, date, bank, source bank, and destination\n- tweak OCR settings like `pageSegMode`\n- enable a custom OCR crop rectangle\n- inspect the live JSON result\n\nYou can also start the demo server in code:\n\n```js\nimport { startInteractiveDemoServer } from \"@angloqq03/gpv\";\n\nstartInteractiveDemoServer({\n  port: 3210\n});\n```\n\n## OCR-only usage 🔎\n\n### Extract raw OCR text\n\n```js\nimport { extractTextFromImage } from \"@angloqq03/gpv\";\n\nconst ocr = await extractTextFromImage(\"./proof.png\");\n\nconsole.log(ocr.confidence);\nconsole.log(ocr.text);\n```\n\n### Extract likely proof fields\n\n```js\nimport { extractProofDetails } from \"@angloqq03/gpv\";\n\nconst details = await extractProofDetails(\"./proof.png\");\n\nconsole.log(details.extracted.reference);\nconsole.log(details.extracted.amount);\nconsole.log(details.extracted.date);\n```\n\n### Parse OCR text manually\n\nUseful if OCR happens elsewhere.\n\n```js\nimport { parseProofText } from \"@angloqq03/gpv\";\n\nconst parsed = parseProofText(`\nAmount Paid PHP 3,000.00\nRef. No. 5695 5992 5\n12 April 2022 01:46:01 PM\n`);\n\nconsole.log(parsed.extracted);\n```\n\nGPV now uses context-aware parsing, so it is better at:\n\n- preferring `Ref. No.` over `Account Number`\n- preferring `Amount Paid` over `Fee`\n- recognizing full month-name dates like `12 April 2022`\n\n## Default model usage 🧠\n\n### Validate with the built-in model\n\n```js\nimport { validateProof } from \"@angloqq03/gpv\";\n\nconst result = await validateProof(\"./proof.png\", {\n  reference: \"123456789012\",\n  amount: 250,\n  date: \"2026-04-03\"\n});\n\nconsole.log(result.ok);\nconsole.log(result.checks);\nconsole.log(result.risk.level);\n```\n\n### Full analysis with summary\n\n```js\nimport { fullAnalysis } from \"@angloqq03/gpv\";\n\nconst analysis = await fullAnalysis(\"./proof.png\", {\n  reference: \"123456789012\",\n  amount: 250,\n  date: \"2026-04-03\"\n});\n\nconsole.log(analysis.summary);\nconsole.log(analysis.rawText);\nconsole.log(analysis.candidates);\n```\n\n## Express usage ⚡\n\n### Manual route style\n\n```bash\nnpm install express multer\n```\n\n```js\nimport express from \"express\";\nimport multer from \"multer\";\nimport { analyzeUploadedProof } from \"@angloqq03/gpv\";\n\nconst app = express();\nconst upload = multer({ dest: \"uploads/\" });\n\napp.post(\"/upload-proof\", upload.single(\"proof\"), async (req, res, next) => {\n  try {\n    const expected = {\n      reference: req.body.reference,\n      amount: Number(req.body.amount),\n      date: req.body.date\n    };\n\n    const result = await analyzeUploadedProof(req.file, expected, {\n      amountTolerance: 0\n    });\n\n    res.json({\n      success: true,\n      validation: result\n    });\n  } catch (error) {\n    next(error);\n  }\n});\n```\n\n### Middleware style\n\n```js\nimport express from \"express\";\nimport multer from \"multer\";\nimport { createExpressProofValidator } from \"@angloqq03/gpv\";\n\nconst app = express();\nconst upload = multer({ dest: \"uploads/\" });\n\napp.post(\n  \"/upload-proof\",\n  upload.single(\"proof\"),\n  createExpressProofValidator({\n    attachToRequestAs: \"proofAnalysis\",\n    run: \"fullAnalysis\",\n    getExpected: async (req) => ({\n      reference: req.body.reference,\n      amount: Number(req.body.amount),\n      date: req.body.date\n    })\n  }),\n  (req, res) => {\n    res.json({\n      success: true,\n      validation: req.proofAnalysis\n    });\n  }\n);\n```\n\n## Custom model workflow 🛠️\n\nIf you have real proof samples from:\n\n- GCash\n- CIMB to GCash\n- MariBank to GCash\n- other bank-to-GCash transfer flows\n\nthen you can train your own Brain.js JSON model.\n\n### Step 1: Add labeled samples\n\nPut screenshots in `proofsamples/` and describe them in `proofsamples/labels.json`.\n\nExample:\n\n```json\n{\n  \"language\": \"eng\",\n  \"amountTolerance\": 0,\n  \"logOcrProgress\": false,\n  \"trainingOptions\": {\n    \"iterations\": 4000,\n    \"log\": false\n  },\n  \"samples\": [\n    {\n      \"name\": \"gcash-real-001\",\n      \"image\": \"proofsamples/gcash-real-001.png\",\n      \"bank\": \"gcash\",\n      \"sourceBank\": \"gcash\",\n      \"destination\": \"gcash\",\n      \"route\": \"wallet_to_wallet\",\n      \"legitimate\": 1,\n      \"isEdited\": false,\n      \"isSynthetic\": false,\n      \"fraudType\": \"none\",\n      \"tags\": [\"real\", \"wallet-to-wallet\"],\n      \"notes\": \"Confirmed against real payment records.\",\n      \"expected\": {\n        \"reference\": \"123456789012\",\n        \"amount\": 250,\n        \"date\": \"2026-04-03\"\n      }\n    }\n  ]\n}\n```\n\n### Step 2: Train the model\n\n```bash\nnpm run train:model\n```\n\nThis generates:\n\n- `models/custom-risk-model.json`\n- `models/last-training-dataset.json`\n\n### Step 3: Load and use your model\n\n```js\nimport {\n  loadFraudModelFromFile,\n  setFraudModel,\n  validateUploadedProof\n} from \"@angloqq03/gpv\";\n\nconst customModel = await loadFraudModelFromFile(\"./models/custom-risk-model.json\");\nsetFraudModel(customModel);\n\nconst result = await validateUploadedProof(\"./proofsamples/gcash-real-001.png\", {\n  reference: \"123456789012\",\n  amount: 250,\n  date: \"2026-04-03\"\n});\n\nconsole.log(result.risk);\n```\n\n### Switch back to default model\n\n```js\nimport { resetFraudModel } from \"@angloqq03/gpv\";\n\nresetFraudModel();\n```\n\n## Helpful functions 🧩\n\n### OCR and parsing\n\n- `extractTextFromImage(image, options?)`\n- `parseProofText(text, options?)`\n- `extractProofDetails(image, options?)`\n\n### Validation and analysis\n\n- `validateProof(image, expected?, options?)`\n- `fullAnalysis(image, expected?, options?)`\n- `validateUploadedProof(upload, expected?, options?)`\n- `analyzeUploadedProof(upload, expected?, options?)`\n- `createInteractiveDemoServer(config?)`\n- `startInteractiveDemoServer(config?)`\n\n### Model helpers\n\n- `createFraudDetectionModel()`\n- `trainFraudModelFromDataset()`\n- `buildDatasetFromProofSamples()`\n- `loadFraudModelFromFile()`\n- `saveFraudModelToFile()`\n- `setFraudModel()`\n- `resetFraudModel()`\n\n### Comparison and detection\n\n- `compareReference(reference, expectedReference)`\n- `compareAmount(amount, expectedAmount, tolerance?)`\n- `compareDate(date, expectedDate)`\n- `isReferenceDetected(image)`\n- `isAmountDetected(image)`\n- `isDateDetected(image)`\n\n### Format and utility helpers\n\n- `isRefValid(reference)`\n- `isValidReference(reference)`\n- `isReferenceFormatValid(reference)`\n- `isAmountFormatValid(amount)`\n- `isDateFormatValid(date)`\n- `normalizeReference(reference)`\n- `normalizeAmount(amount)`\n- `normalizeDate(date)`\n- `parseNumericAmount(amount)`\n- `toCleanText(text)`\n- `safeDate(date)`\n- `isDateRecent(date, maxAgeDays?)`\n\n## Options 🎛️\n\n```js\nconst options = {\n  language: \"eng\",\n  amountTolerance: 0,\n  pageSegMode: 6,\n  rectangle: { top: 0, left: 0, width: 1080, height: 1920 },\n  logger: (message) => console.log(message)\n};\n```\n\nNotes:\n\n- `pageSegMode: 6` is a solid default for proof screenshots and receipts\n- OCR text is rebuilt in top-to-bottom order from Tesseract block data\n- `validateProof()` and `fullAnalysis()` use the active model automatically\n\n## Testing with `proof.png` 🧪\n\nIf `proof.png` exists in the package root, `npm test` will print:\n\n- OCR confidence\n- extracted OCR text\n- parser helper output\n\n## Important note ❤️\n\nGPV helps a lot, but it should not be your only fraud defense.\n\nFor best results, always compare against your own server-side order data:\n\n- expected amount\n- expected reference\n- expected payment date\n- order ownership\n- payment status in your own database\n","readmeFilename":"readme.md"}