document-ocr 0.0.0-stage → 3.1.3

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 (124) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +260 -2
  3. package/dist/index.cjs +659 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +293 -0
  6. package/dist/index.d.ts +293 -0
  7. package/dist/index.js +616 -0
  8. package/dist/index.js.map +1 -0
  9. package/hosting/.dockerignore +17 -0
  10. package/hosting/.gcloudignore +14 -0
  11. package/hosting/FEATURES.md +172 -0
  12. package/hosting/HOSTING.md +268 -0
  13. package/hosting/LICENSE +21 -0
  14. package/hosting/README.md +369 -0
  15. package/hosting/core/__init__.py +0 -0
  16. package/hosting/core/aadhaar_extractor.py +298 -0
  17. package/hosting/core/back_page_extractor.py +492 -0
  18. package/hosting/core/barcodes.py +125 -0
  19. package/hosting/core/card_recovery.py +244 -0
  20. package/hosting/core/document_bundle.py +82 -0
  21. package/hosting/core/document_classifier.py +233 -0
  22. package/hosting/core/document_input.py +135 -0
  23. package/hosting/core/document_registry.py +143 -0
  24. package/hosting/core/driving_licence_extractor.py +510 -0
  25. package/hosting/core/ead_recovery.py +54 -0
  26. package/hosting/core/evidence.py +54 -0
  27. package/hosting/core/form_recovery.py +61 -0
  28. package/hosting/core/jobs.py +232 -0
  29. package/hosting/core/kyc_ocr.py +132 -0
  30. package/hosting/core/kyc_validation.py +411 -0
  31. package/hosting/core/model_setup.py +13 -0
  32. package/hosting/core/mrz_parser.py +336 -0
  33. package/hosting/core/mrz_recovery.py +193 -0
  34. package/hosting/core/npr_extractor.py +410 -0
  35. package/hosting/core/nrega_extractor.py +827 -0
  36. package/hosting/core/ocr_engine.py +207 -0
  37. package/hosting/core/page_classifier.py +137 -0
  38. package/hosting/core/pan_extractor.py +183 -0
  39. package/hosting/core/pipeline.py +712 -0
  40. package/hosting/core/preprocessor.py +297 -0
  41. package/hosting/core/recovery_budget.py +67 -0
  42. package/hosting/core/redaction.py +48 -0
  43. package/hosting/core/review.html +244 -0
  44. package/hosting/core/structured_documents.py +422 -0
  45. package/hosting/core/travel_mrz.py +164 -0
  46. package/hosting/core/travel_recovery.py +187 -0
  47. package/hosting/core/validator.py +396 -0
  48. package/hosting/core/validators.py +179 -0
  49. package/hosting/core/voter_id_extractor.py +363 -0
  50. package/hosting/deploy/cloudflare/deploy.sh +44 -0
  51. package/hosting/deploy/cloudflare/package-lock.json +3088 -0
  52. package/hosting/deploy/cloudflare/package.json +29 -0
  53. package/hosting/deploy/cloudflare/src/gateway.ts +42 -0
  54. package/hosting/deploy/cloudflare/src/index.ts +21 -0
  55. package/hosting/deploy/cloudflare/test/gateway.test.ts +59 -0
  56. package/hosting/deploy/cloudflare/tsconfig.json +12 -0
  57. package/hosting/deploy/cloudflare/worker-configuration.d.ts +16253 -0
  58. package/hosting/deploy/cloudflare/wrangler.jsonc +26 -0
  59. package/hosting/deploy/cloudrun/cloudbuild.yaml +18 -0
  60. package/hosting/deploy/cloudrun/deploy.sh +71 -0
  61. package/hosting/deploy/cloudrun/render_service.py +47 -0
  62. package/hosting/deploy/common.sh +14 -0
  63. package/hosting/deploy/docker/Dockerfile +16 -0
  64. package/hosting/deploy/docker/server.py +313 -0
  65. package/hosting/deploy/lambda/Dockerfile.lambda +11 -0
  66. package/hosting/deploy/lambda/deploy.sh +22 -0
  67. package/hosting/deploy/lambda/handler.py +132 -0
  68. package/hosting/deploy/lambda/template.yaml +59 -0
  69. package/hosting/deploy/local/dev.sh +18 -0
  70. package/hosting/deploy/server/Caddyfile +5 -0
  71. package/hosting/deploy/server/compose.jobs.yaml +36 -0
  72. package/hosting/deploy/server/compose.yaml +38 -0
  73. package/hosting/deploy/server/deploy.sh +23 -0
  74. package/hosting/infra/cloudrun/main.tf +104 -0
  75. package/hosting/infra/cloudrun/terraform.tfvars.example +7 -0
  76. package/hosting/infra/cloudrun/variables.tf +55 -0
  77. package/hosting/infra/lambda/main.tf +63 -0
  78. package/hosting/infra/lambda/terraform.tfvars.example +6 -0
  79. package/hosting/infra/lambda/variables.tf +37 -0
  80. package/hosting/pyproject.toml +65 -0
  81. package/hosting/requirements.lock +134 -0
  82. package/package.json +76 -4
  83. package/python/core/__init__.py +0 -0
  84. package/python/core/aadhaar_extractor.py +298 -0
  85. package/python/core/back_page_extractor.py +492 -0
  86. package/python/core/barcodes.py +125 -0
  87. package/python/core/card_recovery.py +244 -0
  88. package/python/core/document_bundle.py +82 -0
  89. package/python/core/document_classifier.py +233 -0
  90. package/python/core/document_input.py +135 -0
  91. package/python/core/document_registry.py +143 -0
  92. package/python/core/driving_licence_extractor.py +510 -0
  93. package/python/core/ead_recovery.py +54 -0
  94. package/python/core/evidence.py +54 -0
  95. package/python/core/form_recovery.py +61 -0
  96. package/python/core/jobs.py +232 -0
  97. package/python/core/kyc_ocr.py +132 -0
  98. package/python/core/kyc_validation.py +411 -0
  99. package/python/core/model_setup.py +13 -0
  100. package/python/core/mrz_parser.py +336 -0
  101. package/python/core/mrz_recovery.py +193 -0
  102. package/python/core/npr_extractor.py +410 -0
  103. package/python/core/nrega_extractor.py +827 -0
  104. package/python/core/ocr_engine.py +207 -0
  105. package/python/core/page_classifier.py +137 -0
  106. package/python/core/pan_extractor.py +183 -0
  107. package/python/core/pipeline.py +712 -0
  108. package/python/core/preprocessor.py +297 -0
  109. package/python/core/recovery_budget.py +67 -0
  110. package/python/core/redaction.py +48 -0
  111. package/python/core/review.html +244 -0
  112. package/python/core/structured_documents.py +422 -0
  113. package/python/core/travel_mrz.py +164 -0
  114. package/python/core/travel_recovery.py +187 -0
  115. package/python/core/validator.py +396 -0
  116. package/python/core/validators.py +179 -0
  117. package/python/core/voter_id_extractor.py +363 -0
  118. package/python/pyproject.toml +34 -0
  119. package/python/requirements.lock +134 -0
  120. package/python/server.py +313 -0
  121. package/scripts/dococr.mjs +163 -0
  122. package/scripts/postinstall.mjs +173 -0
  123. package/scripts/sync-hosting.mjs +35 -0
  124. package/scripts/sync-python.sh +20 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Piyush Gambhir
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,261 @@
1
- # Temporary Holding Version
1
+ # document-ocr
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Document OCR for Node.js 18+, with a bundled local Python/RapidOCR runtime and
4
+ HTTP/Lambda clients. It extracts structured fields from passports, Indian and
5
+ experimental US identity, immigration and tax documents. The server
6
+ catalog reports each family’s required fields and experimental status.
7
+
8
+ > This is beta extraction software. It does not verify document authenticity,
9
+ > detect fraud, query issuing authorities, or by itself satisfy KYC obligations.
10
+ > NREGA and NPR extraction is experimental until measured against a
11
+ > representative private image dataset.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ npm install document-ocr
17
+ ```
18
+
19
+ When npm blocks dependency install scripts, run `npm install-scripts approve
20
+ document-ocr` followed by `npm rebuild document-ocr` to enable local Python setup.
21
+ HTTP and Lambda client modes do not require that setup.
22
+
23
+ Development uses Node.js 26.12.1. Local OCR requires Python 3.14. If [`uv`](https://docs.astral.sh/uv/) is
24
+ available, the postinstall script can create the local environment
25
+ automatically.
26
+
27
+ ## Local mode
28
+
29
+ ```typescript
30
+ import { DocumentOCR } from 'document-ocr'
31
+
32
+ const ocr = new DocumentOCR()
33
+ const result = await ocr.scan(imageBuffer)
34
+
35
+ if (result.status === 'success') {
36
+ switch (result.documentType) {
37
+ case 'passport':
38
+ console.log(result.fields?.passportNumber)
39
+ break
40
+ case 'pan':
41
+ console.log(result.panFields?.panNumber)
42
+ break
43
+ case 'aadhaar':
44
+ console.log(result.aadhaarFields?.aadhaarLast4)
45
+ break
46
+ case 'nrega_job_card':
47
+ console.log(result.nregaJobCardFields?.jobCardNumber)
48
+ break
49
+ case 'npr_letter':
50
+ console.log(result.nprLetterFields?.referenceNumber)
51
+ break
52
+ }
53
+ }
54
+
55
+ await ocr.stop()
56
+ ```
57
+
58
+ Local mode starts the bundled FastAPI process on `127.0.0.1`, reuses it across
59
+ scans, and stops it when `ocr.stop()` is called. Documents stay on the local
60
+ machine.
61
+
62
+ `PassportOCR` remains available as a compatibility alias for `DocumentOCR`.
63
+
64
+ For non-passport results, `status: 'success'` requires the document-specific
65
+ minimum fields and a conservative OCR-region confidence gate.
66
+ `identifierValid` reports only a local format/checksum check, not authenticity;
67
+ `missingRequiredFields` explains partial failures. In HTTP mode these
68
+ structured partial results use status `422` and are returned by the client
69
+ rather than thrown.
70
+
71
+ Set `DOCUMENT_OCR_KYC_LANGS=en,devanagari` (or `latin`, `ka`, `ta`, `te`) to
72
+ run known recognition models on the non-passport path. Each additional model
73
+ adds latency and memory, so choose the list from measured language slices.
74
+ Unsupported names or more than four models fail server readiness.
75
+
76
+ ## Other modes
77
+
78
+ ### HTTP
79
+
80
+ ```typescript
81
+ const ocr = new DocumentOCR({
82
+ mode: 'http',
83
+ endpoint: 'https://ocr.example.com',
84
+ apiKey: process.env.API_TOKEN,
85
+ })
86
+ ```
87
+
88
+ `apiKey` is sent as a Bearer token. The included Python server enforces it when
89
+ `API_TOKEN` is configured.
90
+
91
+ ### AWS Lambda
92
+
93
+ ```typescript
94
+ const ocr = new DocumentOCR({
95
+ mode: 'lambda',
96
+ functionName: 'document-ocr-prod',
97
+ })
98
+ ```
99
+
100
+ Lambda mode uses IAM-authenticated direct invocation through the AWS SDK.
101
+
102
+ ## Options
103
+
104
+ | Option | Type | Default | Description |
105
+ |---|---|---|---|
106
+ | `mode` | `local \| http \| lambda` | `local` | Invocation mode |
107
+ | `endpoint` | `string` | — | Required in HTTP mode |
108
+ | `functionName` | `string` | — | Required in Lambda mode |
109
+ | `timeoutMs` | `number` | `30000` | Per-attempt timeout |
110
+ | `retries` | `number` | `2` | Retry count |
111
+ | `apiKey` | `string` | — | Bearer token for HTTP mode |
112
+ | `authHeaders` | `(url, signal) => HeadersInit \| Promise<HeadersInit>` | — | Per-attempt HTTP credentials |
113
+
114
+ Accepted image inputs are `File`, `Blob`, `Buffer`, `ArrayBuffer`, base64
115
+ strings, and HTTP(S) URLs.
116
+
117
+ Set `PASSPORT_OCR_SKIP_PYTHON=1` during installation to skip local Python setup
118
+ when only HTTP or Lambda mode is required.
119
+
120
+ ## Privacy
121
+
122
+ HTTP and Lambda modes transmit identity documents to the configured
123
+ infrastructure. Protect the endpoint, avoid logging extracted personal data,
124
+ and define an appropriate retention policy. Never submit real identity
125
+ documents to public issues or test fixtures.
126
+
127
+ ## License
128
+
129
+ [MIT](LICENSE)
130
+
131
+ ## Document hints, evidence, and multiple pages
132
+
133
+ ```typescript
134
+ const options = { documentType: 'us_driver_license', country: 'USA', includeEvidence: true }
135
+ const result = await ocr.scan(imageBuffer, options)
136
+ console.log(result.documentFields, result.fieldEvidence, result.checks)
137
+
138
+ // Independent documents, with one result per input.
139
+ const batch = await ocr.scanBatch([firstImage, secondImage], options)
140
+
141
+ // Front/back images or a PDF belonging to one document.
142
+ const document = await ocr.scanDocument([frontImage, backImage], options)
143
+ console.log(document.documentFields, document.conflicts)
144
+
145
+ const catalog = await ocr.documents()
146
+ console.log(catalog.documents, catalog.capabilities)
147
+ ```
148
+
149
+ The catalog reports supported families, required fields, available extraction
150
+ sources, and experimental status. New families include US driver licences and
151
+ state IDs, passport cards, green cards, EADs, visas, I-94s and W-9s. These profiles
152
+ remain experimental. Bank statements, utility bills, payslips and Indian business
153
+ records are planned, not implemented profiles.
154
+ Support and required fields are defined by the server catalog; extraction does
155
+ not establish document authenticity.
156
+
157
+ `documentFields`, `issuingCountry`, `issuingRegion`, `fieldEvidence`, `checks`,
158
+ and `schemaVersion` extend the result without replacing legacy field blocks.
159
+ Evidence contains source text, bounding boxes, source type, confidence, and an
160
+ optional page number. Include it only when needed because it contains document
161
+ values. Grouped results expose conflicting page values in `conflicts` with
162
+ 1-based page numbers. Batch/group/catalog methods use local or HTTP mode.
163
+
164
+ ## Short-lived HTTP credentials
165
+
166
+ Provide an asynchronous `authHeaders` callback to refresh headers on every
167
+ attempt. It receives the request URL and attempt abort signal. Returned headers
168
+ override the static `apiKey` header, which otherwise remains a fallback.
169
+
170
+ For Cloud Run IAM, install `google-auth-library` in the application and obtain
171
+ an audience-matched ID-token client using Application Default Credentials, as
172
+ described in the [Google Auth Library documentation](https://github.com/googleapis/google-auth-library-nodejs#working-with-id-tokens):
173
+
174
+ ```typescript
175
+ import { GoogleAuth } from 'google-auth-library'
176
+
177
+ const endpoint = 'https://your-private-service.run.app'
178
+ const identity = await new GoogleAuth().getIdTokenClient(endpoint)
179
+ const ocr = new DocumentOCR({
180
+ mode: 'http',
181
+ endpoint,
182
+ authHeaders: async () => {
183
+ const headers = await identity.getRequestHeaders()
184
+ return { Authorization: headers.get('authorization')! }
185
+ },
186
+ })
187
+ ```
188
+
189
+ The caller needs Cloud Run Invoker permission. API bearer-token authentication
190
+ on your own server continues to use `apiKey`.
191
+
192
+ ## Larger Lambda documents
193
+
194
+ ```typescript
195
+ const result = await ocr.scanS3({
196
+ bucket: 'private-document-inputs',
197
+ key: 'uploads/opaque-sample.pdf',
198
+ versionId: 'optional-object-version',
199
+ }, { documentType: 'us_w9', country: 'USA' })
200
+ ```
201
+
202
+ `scanS3` requires Lambda mode. The Lambda deployment restricts readable S3
203
+ buckets/prefixes and its execution role must be authorized to read the object.
204
+ Direct image invocations count the exact UTF-8 JSON payload, including base64
205
+ and options, against Lambda's 6 MiB synchronous request ceiling. Oversized
206
+ requests and invalid local input fail immediately without retries; use S3 for
207
+ larger images. Transient transport errors retain per-attempt retry/timeouts.
208
+
209
+ ## Scaffold and deploy a service
210
+
211
+ ```bash
212
+ DOCUMENT_OCR_SKIP_PYTHON=1 npx document-ocr init --target cloudrun --directory my-ocr --project YOUR_PROJECT
213
+ cd my-ocr
214
+ npx document-ocr doctor
215
+ npx document-ocr deploy --dry-run
216
+ npx document-ocr deploy
217
+ ```
218
+
219
+ Targets are `cloudrun`, `lambda`, `cloudflare`, and `server`. Initialization
220
+ copies the versioned Python source, dependency lock, deployment templates,
221
+ and Terraform templates into the chosen directory and writes `dococr.json`.
222
+ It refuses to replace existing paths. `deploy --dry-run` prints the wrapper
223
+ command without contacting a provider; `deploy` executes that wrapper.
224
+
225
+ `dococr.json` stores nonsecret deployment settings: target, service name,
226
+ `economy`/`warm` profile, OCR languages, and optional project, region, image,
227
+ domain, bucket, and prefix. Credentials stay in your environment/provider CLI.
228
+ Cloud Run uses `GCP_PROJECT` and optional `GCP_REGION`; Lambda uses `AWS_REGION`
229
+ and optional S3 scope; server hosting requires `DOMAIN` and `API_TOKEN`.
230
+ Cloudflare uses its logged-in Wrangler account and separately configured
231
+ `API_TOKEN` secret. See the scaffolded `HOSTING.md` for provider-specific setup.
232
+
233
+ `doctor` checks local CLI/config prerequisites. Add `--endpoint URL` for a
234
+ liveness request to `/health`, or `--json` for a machine-readable report. It does
235
+ not prove model readiness, credentials, or provider permissions. Deployment
236
+ wrappers validate provider setup when executed. Server deployment runs on the
237
+ current machine or the configured Docker remote context.
238
+
239
+ Set `DOCUMENT_OCR_SKIP_PYTHON=1` when installing solely for remote clients or
240
+ hosting commands; `PASSPORT_OCR_SKIP_PYTHON=1` remains supported. Local OCR needs
241
+ the bundled Python runtime installed normally. Runtime dependencies are installed
242
+ against the included versioned dependency lock.
243
+
244
+
245
+ ## Persistent background jobs
246
+
247
+ ```typescript
248
+ const queued = await ocr.enqueueJob([frontImage, backImage], {
249
+ documentType: 'us_driver_license', grouped: true, notify: false,
250
+ })
251
+ const progress = await ocr.job(queued.id)
252
+ if (progress.status === 'succeeded') console.log(progress.result)
253
+ await ocr.deleteJob(queued.id)
254
+ ```
255
+
256
+ Jobs require an HTTP/local server with persistent job storage enabled; check
257
+ `catalog.capabilities.jobs`. Submitting a job does not retry automatically,
258
+ because a lost response could otherwise create duplicate persistent work.
259
+ Polling and deletion use normal transport retries. Job timestamps are Unix
260
+ seconds; results expire according to server retention. Notifications occur only
261
+ when `notify: true` and the server has an enabled notification integration.