indycheck 0.1.2 → 0.2.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.
package/dist/index.d.ts CHANGED
@@ -144,10 +144,13 @@ export interface VoterParsed {
144
144
  }
145
145
  export interface VehicleParsed {
146
146
  registration: string;
147
- state_code: string;
148
- district: string;
147
+ series_type: "state" | "bharat";
148
+ state_code?: string;
149
+ district?: string;
149
150
  series: string;
150
151
  number: string;
152
+ year?: string;
153
+ suffix?: string;
151
154
  }
152
155
  export interface DetectParsed {
153
156
  type: string | null;
package/dist/index.js CHANGED
@@ -905,6 +905,11 @@ function validateVehicle(input) {
905
905
  if (chars.length < 8 || chars.length > 10) {
906
906
  return fail("INVALID_LENGTH", "Vehicle registration number must be 8-10 characters (e.g. DL01AB1234)", "Vehicle registration number 8 se 10 character ka hona chahiye (jaise DL01AB1234)");
907
907
  }
908
+ // Bharat (BH) series: YYBH####XX — starts with 2 digits (the year),
909
+ // so it must be checked before the state format (2 leading letters).
910
+ if (chars.slice(0, 2).every(isAsciiDigit)) {
911
+ return validateBharat(cleaned, chars);
912
+ }
908
913
  if (!chars.slice(0, 2).every(isAsciiAlpha)) {
909
914
  return fail("INVALID_FORMAT", "Vehicle registration number must start with 2 state-code letters (e.g. DL01AB1234)", "Vehicle registration number 2 state-code akshar se shuru hona chahiye (jaise DL01AB1234)");
910
915
  }
@@ -927,12 +932,37 @@ function validateVehicle(input) {
927
932
  return fail("INVALID_FORMAT", "Vehicle registration format must be state letters + district digits + series letters + number digits (e.g. DL01AB1234). Registration numbers have no checksum, so only the format is checked", "Vehicle registration ka format state akshar + district digit + series akshar + number digit hona chahiye (jaise DL01AB1234). Registration number ka koi checksum nahi hai, isliye sirf format check hota hai");
928
933
  }
929
934
  const stateCode = chars.slice(0, 2).join("");
930
- return ok("Vehicle registration format is valid. Registration numbers have no checksum, so this only checks the format", "Vehicle registration ka format sahi hai. Registration number ka koi checksum nahi hai, isliye sirf format check hua hai", { registration: cleaned, state_code: stateCode, district, series, number });
935
+ return ok("Vehicle registration format is valid. Registration numbers have no checksum, so this only checks the format", "Vehicle registration ka format sahi hai. Registration number ka koi checksum nahi hai, isliye sirf format check hua hai", { registration: cleaned, series_type: "state", state_code: stateCode, district, series, number });
931
936
  }
932
937
  catch {
933
938
  return invalidType();
934
939
  }
935
940
  }
941
+ /** Bharat (BH) series: `YYBH####XX` — called only when the cleaned input starts with digits. */
942
+ function validateBharat(cleaned, chars) {
943
+ const notBharat = (en, hi) => fail("INVALID_FORMAT", en, hi);
944
+ const shapeOk = chars.length === 10 &&
945
+ chars[2] === "B" &&
946
+ chars[3] === "H" &&
947
+ chars.slice(4, 8).every(isAsciiDigit) &&
948
+ chars.slice(8, 10).every(isAsciiAlpha);
949
+ if (!shapeOk) {
950
+ return notBharat("Vehicle registration number must start with 2 state-code letters (e.g. DL01AB1234), or be a Bharat series number (e.g. 22BH1234AA)", "Vehicle registration number 2 state-code akshar se shuru hona chahiye (jaise DL01AB1234), ya Bharat series number hona chahiye (jaise 22BH1234AA)");
951
+ }
952
+ const year = chars.slice(0, 2).join("");
953
+ if (Number(year) < 21) {
954
+ return notBharat("Bharat (BH) series numbers start from 2021 — the year must be 21 or later (e.g. 22BH1234AA)", "Bharat (BH) series number 2021 se shuru hue hain — saal 21 ya usse baad ka hona chahiye (jaise 22BH1234AA)");
955
+ }
956
+ const number = chars.slice(4, 8).join("");
957
+ if (number === "0000") {
958
+ return notBharat("Bharat (BH) series number must be 0001-9999 (e.g. 22BH1234AA)", "Bharat (BH) series number 0001 se 9999 ke beech hona chahiye (jaise 22BH1234AA)");
959
+ }
960
+ const suffix = chars.slice(8, 10).join("");
961
+ if (suffix.includes("I") || suffix.includes("O")) {
962
+ return notBharat("Bharat (BH) series suffix letters cannot be I or O (e.g. 22BH1234AA)", "Bharat (BH) series ke aakhiri akshar I ya O nahi ho sakte (jaise 22BH1234AA)");
963
+ }
964
+ return ok("Bharat (BH) series vehicle registration format is valid. Registration numbers have no checksum, so this only checks the format", "Bharat (BH) series vehicle registration ka format sahi hai. Registration number ka koi checksum nahi hai, isliye sirf format check hua hai", { registration: cleaned, series_type: "bharat", year, series: "BH", number, suffix });
965
+ }
936
966
  /** Alias for `validateVehicle`. */
937
967
  function validateVehicleRegistration(input) {
938
968
  return validateVehicle(input);
@@ -0,0 +1,122 @@
1
+ /**
2
+ * indycheck — optional native (napi-rs) backend.
3
+ *
4
+ * Same public API as the pure-TypeScript mirror in `./index`, but the
5
+ * validation itself runs in the compiled Rust core through the
6
+ * napi-rs addon in `crates/indycheck-napi` instead of the TypeScript
7
+ * re-implementation. The addon is optional: when it is not built (or
8
+ * cannot be loaded) every function below falls back to `./index`
9
+ * silently, so the package works with no native code at all.
10
+ *
11
+ * How it loads: `isNativeAvailable()` tries, in order,
12
+ * 1. `INDYCHECK_NATIVE_PATH` — a path to the addon's `index.js` (or
13
+ * directly to a `.node` file), when the env var is set;
14
+ * 2. `crates/indycheck-napi/index.js` relative to this file (works
15
+ * from both `src/` under vitest and `dist/`);
16
+ * 3. the same path found by walking up from the current working
17
+ * directory to a repo checkout.
18
+ * The `.node` binary itself is never committed to the repo — build it
19
+ * with `npm run build` in `crates/indycheck-napi` (see its README).
20
+ *
21
+ * Shape note: the Rust wrappers return JSON strings (see
22
+ * `crates/indycheck-napi/src/lib.rs`); they are parsed here into the
23
+ * same `{ valid, code, reason_en, reason_hi, parsed }` objects the
24
+ * TypeScript implementation returns. `detect` in Rust returns only
25
+ * the type string ("pan" | "aadhaar" | ... | "unknown"), so the
26
+ * `ValidationResult<DetectParsed>` shape is rebuilt here from the
27
+ * native type + the matching native validator, exactly like
28
+ * `detect` in `./index`. `validateMany` in Rust returns a bare
29
+ * `ValidationResult[]` (one per input, in order); the
30
+ * `input` / `type` / totals wrapper is rebuilt here with the same
31
+ * `VALID` / `SOME_INVALID` codes and reason strings as `./index`.
32
+ * The `*WithOptions` variants have no native equivalent (the Rust
33
+ * core's options live behind different entry points), so they always
34
+ * use the TypeScript implementation.
35
+ *
36
+ * Every function here never throws on bad input, like `./index`.
37
+ */
38
+ import type { AadhaarParsed, CinParsed, DetectParsed, GstinParsed, IfscParsed, LlpinParsed, MobileParsed, PincodeParsed, TanParsed, UpiParsed, ValidateManyParsed, ValidationResult, VehicleParsed, VoterParsed } from "./index";
39
+ import * as tsImpl from "./index";
40
+ import type { PanParsed } from "./index";
41
+ /** `true` when the native addon loaded and can be used. */
42
+ export declare function isNativeAvailable(): boolean;
43
+ /** Which backend the functions below are currently using. */
44
+ export declare function backend(): "native" | "typescript";
45
+ export declare function validatePan(input: unknown): ValidationResult<PanParsed>;
46
+ export declare function validateAadhaar(input: unknown): ValidationResult<AadhaarParsed>;
47
+ export declare function validateGstin(input: unknown): ValidationResult<GstinParsed>;
48
+ export declare function validateIfsc(input: unknown): ValidationResult<IfscParsed>;
49
+ export declare function validateUpi(input: unknown): ValidationResult<UpiParsed>;
50
+ export declare function validateMobile(input: unknown): ValidationResult<MobileParsed>;
51
+ export declare function validatePincode(input: unknown): ValidationResult<PincodeParsed>;
52
+ export declare function validateTan(input: unknown): ValidationResult<TanParsed>;
53
+ export declare function validateCin(input: unknown): ValidationResult<CinParsed>;
54
+ export declare function validateLlpin(input: unknown): ValidationResult<LlpinParsed>;
55
+ export declare function validateVoterId(input: unknown): ValidationResult<VoterParsed>;
56
+ /** Alias for `validateVoterId`: EPIC is the name printed on the card. */
57
+ export declare function validateEpic(input: unknown): ValidationResult<VoterParsed>;
58
+ export declare function validateVehicle(input: unknown): ValidationResult<VehicleParsed>;
59
+ /** Alias for `validateVehicle`. */
60
+ export declare function validateVehicleRegistration(input: unknown): ValidationResult<VehicleParsed>;
61
+ /** The Rust `detect` string for a trimmed input. */
62
+ export declare function detectType(input: string): string;
63
+ export declare function detect(input: unknown): ValidationResult<DetectParsed>;
64
+ export declare function validateMany(inputs: unknown): ValidationResult<ValidateManyParsed>;
65
+ export declare function formatMobile(input: unknown): ValidationResult<MobileParsed>;
66
+ export declare function formatPan(input: unknown): string | null;
67
+ export declare function formatGstin(input: unknown): string | null;
68
+ export declare function maskAadhaar(input: unknown): ValidationResult<AadhaarParsed>;
69
+ export declare function maskPan(input: unknown): string;
70
+ export declare function maskMobile(input: unknown): string;
71
+ export declare function generatePan(entity?: unknown): string;
72
+ export declare function generateAadhaar(): string;
73
+ export declare function generateGstin(stateCode?: unknown): string;
74
+ export declare function generateMobile(): string;
75
+ export declare const validateMobileWithOptions: typeof tsImpl.validateMobileWithOptions;
76
+ export declare const validatePanWithOptions: typeof tsImpl.validatePanWithOptions;
77
+ export declare const validateAadhaarWithOptions: typeof tsImpl.validateAadhaarWithOptions;
78
+ export declare const validateGstinWithOptions: typeof tsImpl.validateGstinWithOptions;
79
+ export declare const formatMobileWithOptions: typeof tsImpl.formatMobileWithOptions;
80
+ export declare const defaultOptions: typeof tsImpl.defaultOptions;
81
+ export declare const lenientOptions: typeof tsImpl.lenientOptions;
82
+ export declare const noSpacesHyphensOptions: typeof tsImpl.noSpacesHyphensOptions;
83
+ declare const _default: {
84
+ backend: typeof backend;
85
+ isNativeAvailable: typeof isNativeAvailable;
86
+ validateMobile: typeof validateMobile;
87
+ validatePan: typeof validatePan;
88
+ validateAadhaar: typeof validateAadhaar;
89
+ validateGstin: typeof validateGstin;
90
+ validateIfsc: typeof validateIfsc;
91
+ validateUpi: typeof validateUpi;
92
+ validatePincode: typeof validatePincode;
93
+ validateTan: typeof validateTan;
94
+ validateCin: typeof validateCin;
95
+ validateLlpin: typeof validateLlpin;
96
+ validateVoterId: typeof validateVoterId;
97
+ validateEpic: typeof validateEpic;
98
+ validateVehicle: typeof validateVehicle;
99
+ validateVehicleRegistration: typeof validateVehicleRegistration;
100
+ validateMobileWithOptions: typeof tsImpl.validateMobileWithOptions;
101
+ validatePanWithOptions: typeof tsImpl.validatePanWithOptions;
102
+ validateAadhaarWithOptions: typeof tsImpl.validateAadhaarWithOptions;
103
+ validateGstinWithOptions: typeof tsImpl.validateGstinWithOptions;
104
+ formatMobile: typeof formatMobile;
105
+ formatMobileWithOptions: typeof tsImpl.formatMobileWithOptions;
106
+ formatPan: typeof formatPan;
107
+ formatGstin: typeof formatGstin;
108
+ maskAadhaar: typeof maskAadhaar;
109
+ maskPan: typeof maskPan;
110
+ maskMobile: typeof maskMobile;
111
+ generatePan: typeof generatePan;
112
+ generateAadhaar: typeof generateAadhaar;
113
+ generateGstin: typeof generateGstin;
114
+ generateMobile: typeof generateMobile;
115
+ defaultOptions: typeof tsImpl.defaultOptions;
116
+ lenientOptions: typeof tsImpl.lenientOptions;
117
+ noSpacesHyphensOptions: typeof tsImpl.noSpacesHyphensOptions;
118
+ detect: typeof detect;
119
+ detectType: typeof detectType;
120
+ validateMany: typeof validateMany;
121
+ };
122
+ export default _default;
package/dist/native.js ADDED
@@ -0,0 +1,518 @@
1
+ "use strict";
2
+ /**
3
+ * indycheck — optional native (napi-rs) backend.
4
+ *
5
+ * Same public API as the pure-TypeScript mirror in `./index`, but the
6
+ * validation itself runs in the compiled Rust core through the
7
+ * napi-rs addon in `crates/indycheck-napi` instead of the TypeScript
8
+ * re-implementation. The addon is optional: when it is not built (or
9
+ * cannot be loaded) every function below falls back to `./index`
10
+ * silently, so the package works with no native code at all.
11
+ *
12
+ * How it loads: `isNativeAvailable()` tries, in order,
13
+ * 1. `INDYCHECK_NATIVE_PATH` — a path to the addon's `index.js` (or
14
+ * directly to a `.node` file), when the env var is set;
15
+ * 2. `crates/indycheck-napi/index.js` relative to this file (works
16
+ * from both `src/` under vitest and `dist/`);
17
+ * 3. the same path found by walking up from the current working
18
+ * directory to a repo checkout.
19
+ * The `.node` binary itself is never committed to the repo — build it
20
+ * with `npm run build` in `crates/indycheck-napi` (see its README).
21
+ *
22
+ * Shape note: the Rust wrappers return JSON strings (see
23
+ * `crates/indycheck-napi/src/lib.rs`); they are parsed here into the
24
+ * same `{ valid, code, reason_en, reason_hi, parsed }` objects the
25
+ * TypeScript implementation returns. `detect` in Rust returns only
26
+ * the type string ("pan" | "aadhaar" | ... | "unknown"), so the
27
+ * `ValidationResult<DetectParsed>` shape is rebuilt here from the
28
+ * native type + the matching native validator, exactly like
29
+ * `detect` in `./index`. `validateMany` in Rust returns a bare
30
+ * `ValidationResult[]` (one per input, in order); the
31
+ * `input` / `type` / totals wrapper is rebuilt here with the same
32
+ * `VALID` / `SOME_INVALID` codes and reason strings as `./index`.
33
+ * The `*WithOptions` variants have no native equivalent (the Rust
34
+ * core's options live behind different entry points), so they always
35
+ * use the TypeScript implementation.
36
+ *
37
+ * Every function here never throws on bad input, like `./index`.
38
+ */
39
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
40
+ if (k2 === undefined) k2 = k;
41
+ var desc = Object.getOwnPropertyDescriptor(m, k);
42
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
43
+ desc = { enumerable: true, get: function() { return m[k]; } };
44
+ }
45
+ Object.defineProperty(o, k2, desc);
46
+ }) : (function(o, m, k, k2) {
47
+ if (k2 === undefined) k2 = k;
48
+ o[k2] = m[k];
49
+ }));
50
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
51
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
52
+ }) : function(o, v) {
53
+ o["default"] = v;
54
+ });
55
+ var __importStar = (this && this.__importStar) || (function () {
56
+ var ownKeys = function(o) {
57
+ ownKeys = Object.getOwnPropertyNames || function (o) {
58
+ var ar = [];
59
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
60
+ return ar;
61
+ };
62
+ return ownKeys(o);
63
+ };
64
+ return function (mod) {
65
+ if (mod && mod.__esModule) return mod;
66
+ var result = {};
67
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
68
+ __setModuleDefault(result, mod);
69
+ return result;
70
+ };
71
+ })();
72
+ Object.defineProperty(exports, "__esModule", { value: true });
73
+ exports.noSpacesHyphensOptions = exports.lenientOptions = exports.defaultOptions = exports.formatMobileWithOptions = exports.validateGstinWithOptions = exports.validateAadhaarWithOptions = exports.validatePanWithOptions = exports.validateMobileWithOptions = void 0;
74
+ exports.isNativeAvailable = isNativeAvailable;
75
+ exports.backend = backend;
76
+ exports.validatePan = validatePan;
77
+ exports.validateAadhaar = validateAadhaar;
78
+ exports.validateGstin = validateGstin;
79
+ exports.validateIfsc = validateIfsc;
80
+ exports.validateUpi = validateUpi;
81
+ exports.validateMobile = validateMobile;
82
+ exports.validatePincode = validatePincode;
83
+ exports.validateTan = validateTan;
84
+ exports.validateCin = validateCin;
85
+ exports.validateLlpin = validateLlpin;
86
+ exports.validateVoterId = validateVoterId;
87
+ exports.validateEpic = validateEpic;
88
+ exports.validateVehicle = validateVehicle;
89
+ exports.validateVehicleRegistration = validateVehicleRegistration;
90
+ exports.detectType = detectType;
91
+ exports.detect = detect;
92
+ exports.validateMany = validateMany;
93
+ exports.formatMobile = formatMobile;
94
+ exports.formatPan = formatPan;
95
+ exports.formatGstin = formatGstin;
96
+ exports.maskAadhaar = maskAadhaar;
97
+ exports.maskPan = maskPan;
98
+ exports.maskMobile = maskMobile;
99
+ exports.generatePan = generatePan;
100
+ exports.generateAadhaar = generateAadhaar;
101
+ exports.generateGstin = generateGstin;
102
+ exports.generateMobile = generateMobile;
103
+ const node_module_1 = require("node:module");
104
+ const node_fs_1 = require("node:fs");
105
+ const node_path_1 = require("node:path");
106
+ const tsImpl = __importStar(require("./index"));
107
+ const nativeRequire = (0, node_module_1.createRequire)((0, node_path_1.join)(process.cwd(), "package.json"));
108
+ function bindingCandidates() {
109
+ const envPath = process.env.INDYCHECK_NATIVE_PATH;
110
+ // An explicit path is authoritative: if it cannot be loaded, the
111
+ // addon is treated as absent (TypeScript fallback) instead of
112
+ // silently loading a different binary.
113
+ if (envPath)
114
+ return [envPath];
115
+ const candidates = [];
116
+ // CommonJS: relative to this file (dist/ or src/ under packages/js).
117
+ if (typeof __dirname !== "undefined") {
118
+ candidates.push((0, node_path_1.join)(__dirname, "..", "..", "..", "crates", "indycheck-napi", "index.js"));
119
+ }
120
+ // Walk up from the working directory to a repo checkout (covers
121
+ // vitest, where __dirname is not defined, and `npm test` from anywhere).
122
+ let dir = process.cwd();
123
+ for (let i = 0; i < 6; i++) {
124
+ candidates.push((0, node_path_1.join)(dir, "crates", "indycheck-napi", "index.js"));
125
+ const parent = (0, node_path_1.dirname)(dir);
126
+ if (parent === dir)
127
+ break;
128
+ dir = parent;
129
+ }
130
+ return [...new Set(candidates)].filter((c) => (0, node_fs_1.existsSync)(c));
131
+ }
132
+ let binding = null;
133
+ let attempted = false;
134
+ function loadBinding() {
135
+ if (attempted)
136
+ return binding;
137
+ attempted = true;
138
+ for (const candidate of bindingCandidates()) {
139
+ try {
140
+ const mod = nativeRequire(candidate);
141
+ if (mod &&
142
+ typeof mod.validatePan === "function" &&
143
+ typeof mod.validateVehicle === "function" &&
144
+ typeof mod.detect === "function" &&
145
+ typeof mod.validateMany === "function") {
146
+ binding = mod;
147
+ break;
148
+ }
149
+ }
150
+ catch {
151
+ // Not built / not loadable here — try the next candidate.
152
+ }
153
+ }
154
+ return binding;
155
+ }
156
+ /** `true` when the native addon loaded and can be used. */
157
+ function isNativeAvailable() {
158
+ return loadBinding() !== null;
159
+ }
160
+ /** Which backend the functions below are currently using. */
161
+ function backend() {
162
+ return loadBinding() !== null ? "native" : "typescript";
163
+ }
164
+ // ---------------------------------------------------------------------------
165
+ // Call helpers
166
+ // ---------------------------------------------------------------------------
167
+ /** Rust `ValidationResult::err` omits `parsed` from the JSON entirely
168
+ * (serde `skip_serializing_if`), while the TS mirror sets it to
169
+ * `null` — normalise so both backends return identical shapes. */
170
+ function normalizeResult(r) {
171
+ if (r.parsed === undefined)
172
+ r.parsed = null;
173
+ return r;
174
+ }
175
+ /** Run a native call that returns a JSON `ValidationResult`; on any
176
+ * failure (missing addon, bad JSON) use the TypeScript fallback. */
177
+ function callJson(fn, fallback) {
178
+ const b = loadBinding();
179
+ if (b === null)
180
+ return fallback();
181
+ try {
182
+ return normalizeResult(JSON.parse(fn(b)));
183
+ }
184
+ catch {
185
+ return fallback();
186
+ }
187
+ }
188
+ /** Run a native call returning a plain value; fall back on any failure. */
189
+ function callPlain(fn, fallback) {
190
+ const b = loadBinding();
191
+ if (b === null)
192
+ return fallback();
193
+ try {
194
+ return fn(b);
195
+ }
196
+ catch {
197
+ return fallback();
198
+ }
199
+ }
200
+ /** Native validator for a `detect` type string, or null for "unknown". */
201
+ function validateByNativeType(b, type, input) {
202
+ let json;
203
+ switch (type) {
204
+ case "pan":
205
+ json = b.validatePan(input);
206
+ break;
207
+ case "aadhaar":
208
+ json = b.validateAadhaar(input);
209
+ break;
210
+ case "gstin":
211
+ json = b.validateGstin(input);
212
+ break;
213
+ case "ifsc":
214
+ json = b.validateIfsc(input);
215
+ break;
216
+ case "upi":
217
+ json = b.validateUpi(input);
218
+ break;
219
+ case "mobile":
220
+ json = b.validateMobile(input);
221
+ break;
222
+ case "pincode":
223
+ json = b.validatePincode(input);
224
+ break;
225
+ case "tan":
226
+ json = b.validateTan(input);
227
+ break;
228
+ case "cin":
229
+ json = b.validateCin(input);
230
+ break;
231
+ case "llpin":
232
+ json = b.validateLlpin(input);
233
+ break;
234
+ case "voter":
235
+ json = b.validateVoterId(input);
236
+ break;
237
+ case "vehicle":
238
+ json = b.validateVehicle(input);
239
+ break;
240
+ default:
241
+ return null;
242
+ }
243
+ return normalizeResult(JSON.parse(json));
244
+ }
245
+ // ---------------------------------------------------------------------------
246
+ // Validators — native when available, TypeScript otherwise
247
+ // ---------------------------------------------------------------------------
248
+ function validatePan(input) {
249
+ if (typeof input !== "string")
250
+ return tsImpl.validatePan(input);
251
+ return callJson((b) => b.validatePan(input), () => tsImpl.validatePan(input));
252
+ }
253
+ function validateAadhaar(input) {
254
+ if (typeof input !== "string")
255
+ return tsImpl.validateAadhaar(input);
256
+ return callJson((b) => b.validateAadhaar(input), () => tsImpl.validateAadhaar(input));
257
+ }
258
+ function validateGstin(input) {
259
+ if (typeof input !== "string")
260
+ return tsImpl.validateGstin(input);
261
+ return callJson((b) => b.validateGstin(input), () => tsImpl.validateGstin(input));
262
+ }
263
+ function validateIfsc(input) {
264
+ if (typeof input !== "string")
265
+ return tsImpl.validateIfsc(input);
266
+ return callJson((b) => b.validateIfsc(input), () => tsImpl.validateIfsc(input));
267
+ }
268
+ function validateUpi(input) {
269
+ if (typeof input !== "string")
270
+ return tsImpl.validateUpi(input);
271
+ return callJson((b) => b.validateUpi(input), () => tsImpl.validateUpi(input));
272
+ }
273
+ function validateMobile(input) {
274
+ if (typeof input !== "string")
275
+ return tsImpl.validateMobile(input);
276
+ return callJson((b) => b.validateMobile(input), () => tsImpl.validateMobile(input));
277
+ }
278
+ function validatePincode(input) {
279
+ if (typeof input !== "string")
280
+ return tsImpl.validatePincode(input);
281
+ return callJson((b) => b.validatePincode(input), () => tsImpl.validatePincode(input));
282
+ }
283
+ function validateTan(input) {
284
+ if (typeof input !== "string")
285
+ return tsImpl.validateTan(input);
286
+ return callJson((b) => b.validateTan(input), () => tsImpl.validateTan(input));
287
+ }
288
+ function validateCin(input) {
289
+ if (typeof input !== "string")
290
+ return tsImpl.validateCin(input);
291
+ return callJson((b) => b.validateCin(input), () => tsImpl.validateCin(input));
292
+ }
293
+ function validateLlpin(input) {
294
+ if (typeof input !== "string")
295
+ return tsImpl.validateLlpin(input);
296
+ return callJson((b) => b.validateLlpin(input), () => tsImpl.validateLlpin(input));
297
+ }
298
+ function validateVoterId(input) {
299
+ if (typeof input !== "string")
300
+ return tsImpl.validateVoterId(input);
301
+ return callJson((b) => b.validateVoterId(input), () => tsImpl.validateVoterId(input));
302
+ }
303
+ /** Alias for `validateVoterId`: EPIC is the name printed on the card. */
304
+ function validateEpic(input) {
305
+ return validateVoterId(input);
306
+ }
307
+ function validateVehicle(input) {
308
+ if (typeof input !== "string")
309
+ return tsImpl.validateVehicle(input);
310
+ return callJson((b) => b.validateVehicle(input), () => tsImpl.validateVehicle(input));
311
+ }
312
+ /** Alias for `validateVehicle`. */
313
+ function validateVehicleRegistration(input) {
314
+ return validateVehicle(input);
315
+ }
316
+ // ---------------------------------------------------------------------------
317
+ // detect / validateMany — shapes rebuilt from the native primitives
318
+ // ---------------------------------------------------------------------------
319
+ /** The Rust `detect` string for a trimmed input. */
320
+ function detectType(input) {
321
+ const b = loadBinding();
322
+ if (b === null)
323
+ return tsImpl.detectType(input);
324
+ try {
325
+ return b.detect(input);
326
+ }
327
+ catch {
328
+ return tsImpl.detectType(input);
329
+ }
330
+ }
331
+ function detect(input) {
332
+ if (typeof input !== "string")
333
+ return tsImpl.detect(input);
334
+ const b = loadBinding();
335
+ if (b === null)
336
+ return tsImpl.detect(input);
337
+ try {
338
+ const type = b.detect(input);
339
+ const trimmed = input.trim();
340
+ if (type === "unknown") {
341
+ return {
342
+ valid: false,
343
+ code: "UNKNOWN_TYPE",
344
+ reason_en: "Could not detect the type of this input",
345
+ reason_hi: "Is input ka type pehchana nahi ja saka",
346
+ parsed: { type: "unknown", value: trimmed, result: null },
347
+ };
348
+ }
349
+ const result = validateByNativeType(b, type, input);
350
+ if (result === null)
351
+ return tsImpl.detect(input);
352
+ return {
353
+ valid: result.valid,
354
+ code: result.code,
355
+ reason_en: result.reason_en,
356
+ reason_hi: result.reason_hi,
357
+ parsed: { type, value: trimmed, result },
358
+ };
359
+ }
360
+ catch {
361
+ return tsImpl.detect(input);
362
+ }
363
+ }
364
+ function validateMany(inputs) {
365
+ if (!Array.isArray(inputs) || inputs.length === 0) {
366
+ return tsImpl.validateMany(inputs);
367
+ }
368
+ if (!inputs.every((item) => typeof item === "string")) {
369
+ // Typed `{ value, type }` entries and non-strings are a
370
+ // TypeScript-wrapper feature — the native batch takes strings only.
371
+ return tsImpl.validateMany(inputs);
372
+ }
373
+ const b = loadBinding();
374
+ if (b === null)
375
+ return tsImpl.validateMany(inputs);
376
+ try {
377
+ const results = JSON.parse(b.validateMany(inputs));
378
+ const items = inputs.map((item, i) => {
379
+ const result = normalizeResult(results[i]);
380
+ const type = b.detect(item);
381
+ return {
382
+ input: item,
383
+ type: type === "unknown" ? null : type,
384
+ valid: result.valid,
385
+ code: result.code,
386
+ reason_en: result.reason_en,
387
+ reason_hi: result.reason_hi,
388
+ parsed: result.parsed,
389
+ };
390
+ });
391
+ const validCount = items.filter((r) => r.valid).length;
392
+ const invalidCount = items.length - validCount;
393
+ const parsed = {
394
+ results: items,
395
+ total: items.length,
396
+ validCount,
397
+ invalidCount,
398
+ };
399
+ if (invalidCount === 0) {
400
+ return {
401
+ valid: true,
402
+ code: "VALID",
403
+ reason_en: "All inputs are valid.",
404
+ reason_hi: "Saare input sahi hain.",
405
+ parsed,
406
+ };
407
+ }
408
+ return {
409
+ valid: false,
410
+ code: "SOME_INVALID",
411
+ reason_en: "Some inputs are invalid.",
412
+ reason_hi: "Kuch input galat hain.",
413
+ parsed,
414
+ };
415
+ }
416
+ catch {
417
+ return tsImpl.validateMany(inputs);
418
+ }
419
+ }
420
+ // ---------------------------------------------------------------------------
421
+ // Format / mask — same contracts as ./index
422
+ // ---------------------------------------------------------------------------
423
+ function formatMobile(input) {
424
+ // Same contract as validateMobile (see ./index).
425
+ return validateMobile(input);
426
+ }
427
+ function formatPan(input) {
428
+ if (typeof input !== "string")
429
+ return tsImpl.formatPan(input);
430
+ return callPlain((b) => b.formatPan(input), () => tsImpl.formatPan(input));
431
+ }
432
+ function formatGstin(input) {
433
+ if (typeof input !== "string")
434
+ return tsImpl.formatGstin(input);
435
+ return callPlain((b) => b.formatGstin(input), () => tsImpl.formatGstin(input));
436
+ }
437
+ function maskAadhaar(input) {
438
+ // Same contract as validateAadhaar (see ./index) — NOT the Rust
439
+ // `mask_aadhaar` string function, which masks any 12-digit string.
440
+ return validateAadhaar(input);
441
+ }
442
+ function maskPan(input) {
443
+ if (typeof input !== "string")
444
+ return tsImpl.maskPan(input);
445
+ return callPlain((b) => b.maskPan(input), () => tsImpl.maskPan(input));
446
+ }
447
+ function maskMobile(input) {
448
+ if (typeof input !== "string")
449
+ return tsImpl.maskMobile(input);
450
+ return callPlain((b) => b.maskMobile(input), () => tsImpl.maskMobile(input));
451
+ }
452
+ // ---------------------------------------------------------------------------
453
+ // Mock test-data generators — TEST DATA ONLY, never real issued IDs
454
+ // ---------------------------------------------------------------------------
455
+ function generatePan(entity) {
456
+ const code = typeof entity === "string" && entity.length > 0 ? entity : "P";
457
+ return callPlain((b) => b.generatePan(code), () => tsImpl.generatePan(entity));
458
+ }
459
+ function generateAadhaar() {
460
+ return callPlain((b) => b.generateAadhaar(), () => tsImpl.generateAadhaar());
461
+ }
462
+ function generateGstin(stateCode) {
463
+ const code = typeof stateCode === "string" ? stateCode : "18";
464
+ return callPlain((b) => b.generateGstin(code), () => tsImpl.generateGstin(stateCode));
465
+ }
466
+ function generateMobile() {
467
+ return callPlain((b) => b.generateMobile(), () => tsImpl.generateMobile());
468
+ }
469
+ // ---------------------------------------------------------------------------
470
+ // Options variants — no native equivalent; always TypeScript
471
+ // ---------------------------------------------------------------------------
472
+ exports.validateMobileWithOptions = tsImpl.validateMobileWithOptions;
473
+ exports.validatePanWithOptions = tsImpl.validatePanWithOptions;
474
+ exports.validateAadhaarWithOptions = tsImpl.validateAadhaarWithOptions;
475
+ exports.validateGstinWithOptions = tsImpl.validateGstinWithOptions;
476
+ exports.formatMobileWithOptions = tsImpl.formatMobileWithOptions;
477
+ exports.defaultOptions = tsImpl.defaultOptions;
478
+ exports.lenientOptions = tsImpl.lenientOptions;
479
+ exports.noSpacesHyphensOptions = tsImpl.noSpacesHyphensOptions;
480
+ exports.default = {
481
+ backend,
482
+ isNativeAvailable,
483
+ validateMobile,
484
+ validatePan,
485
+ validateAadhaar,
486
+ validateGstin,
487
+ validateIfsc,
488
+ validateUpi,
489
+ validatePincode,
490
+ validateTan,
491
+ validateCin,
492
+ validateLlpin,
493
+ validateVoterId,
494
+ validateEpic,
495
+ validateVehicle,
496
+ validateVehicleRegistration,
497
+ validateMobileWithOptions: exports.validateMobileWithOptions,
498
+ validatePanWithOptions: exports.validatePanWithOptions,
499
+ validateAadhaarWithOptions: exports.validateAadhaarWithOptions,
500
+ validateGstinWithOptions: exports.validateGstinWithOptions,
501
+ formatMobile,
502
+ formatMobileWithOptions: exports.formatMobileWithOptions,
503
+ formatPan,
504
+ formatGstin,
505
+ maskAadhaar,
506
+ maskPan,
507
+ maskMobile,
508
+ generatePan,
509
+ generateAadhaar,
510
+ generateGstin,
511
+ generateMobile,
512
+ defaultOptions: exports.defaultOptions,
513
+ lenientOptions: exports.lenientOptions,
514
+ noSpacesHyphensOptions: exports.noSpacesHyphensOptions,
515
+ detect,
516
+ detectType,
517
+ validateMany,
518
+ };
package/package.json CHANGED
@@ -33,9 +33,10 @@
33
33
  },
34
34
  "scripts": {
35
35
  "build": "tsc -p tsconfig.build.json",
36
+ "native:build": "npm --prefix ../../crates/indycheck-napi run build",
36
37
  "test": "vitest run",
37
38
  "typecheck": "tsc --noEmit"
38
39
  },
39
40
  "types": "dist/index.d.ts",
40
- "version": "0.1.2"
41
+ "version": "0.2.1"
41
42
  }