@damarkuncoro/posindonesia 1.0.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 (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +89 -0
  3. package/lib/cjs/api.d.ts +8 -0
  4. package/lib/cjs/api.d.ts.map +1 -0
  5. package/lib/cjs/api.js +37 -0
  6. package/lib/cjs/api.js.map +1 -0
  7. package/lib/cjs/core.d.ts +25 -0
  8. package/lib/cjs/core.d.ts.map +1 -0
  9. package/lib/cjs/core.js +90 -0
  10. package/lib/cjs/core.js.map +1 -0
  11. package/lib/cjs/index.d.ts +3 -0
  12. package/lib/cjs/index.d.ts.map +1 -0
  13. package/lib/cjs/index.js +96 -0
  14. package/lib/cjs/index.js.map +1 -0
  15. package/lib/cjs/logger.d.ts +4 -0
  16. package/lib/cjs/logger.d.ts.map +1 -0
  17. package/lib/cjs/logger.js +22 -0
  18. package/lib/cjs/logger.js.map +1 -0
  19. package/lib/cjs/main.d.ts +5 -0
  20. package/lib/cjs/main.d.ts.map +1 -0
  21. package/lib/cjs/main.js +21 -0
  22. package/lib/cjs/main.js.map +1 -0
  23. package/lib/cjs/parser.d.ts +15 -0
  24. package/lib/cjs/parser.d.ts.map +1 -0
  25. package/lib/cjs/parser.js +61 -0
  26. package/lib/cjs/parser.js.map +1 -0
  27. package/lib/cjs/utils.d.ts +16 -0
  28. package/lib/cjs/utils.d.ts.map +1 -0
  29. package/lib/cjs/utils.js +59 -0
  30. package/lib/cjs/utils.js.map +1 -0
  31. package/lib/esm/api.d.ts +8 -0
  32. package/lib/esm/api.d.ts.map +1 -0
  33. package/lib/esm/api.js +31 -0
  34. package/lib/esm/api.js.map +1 -0
  35. package/lib/esm/core.d.ts +25 -0
  36. package/lib/esm/core.d.ts.map +1 -0
  37. package/lib/esm/core.js +54 -0
  38. package/lib/esm/core.js.map +1 -0
  39. package/lib/esm/index.d.ts +3 -0
  40. package/lib/esm/index.d.ts.map +1 -0
  41. package/lib/esm/index.js +58 -0
  42. package/lib/esm/index.js.map +1 -0
  43. package/lib/esm/logger.d.ts +4 -0
  44. package/lib/esm/logger.d.ts.map +1 -0
  45. package/lib/esm/logger.js +17 -0
  46. package/lib/esm/logger.js.map +1 -0
  47. package/lib/esm/main.d.ts +5 -0
  48. package/lib/esm/main.d.ts.map +1 -0
  49. package/lib/esm/main.js +5 -0
  50. package/lib/esm/main.js.map +1 -0
  51. package/lib/esm/parser.d.ts +15 -0
  52. package/lib/esm/parser.d.ts.map +1 -0
  53. package/lib/esm/parser.js +25 -0
  54. package/lib/esm/parser.js.map +1 -0
  55. package/lib/esm/utils.d.ts +16 -0
  56. package/lib/esm/utils.d.ts.map +1 -0
  57. package/lib/esm/utils.js +52 -0
  58. package/lib/esm/utils.js.map +1 -0
  59. package/package.json +77 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 damarkuncoro
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 ADDED
@@ -0,0 +1,89 @@
1
+ # @damarkuncoro/posindonesia
2
+
3
+ [![NPM Version](https://img.shields.io/npm/v/@damarkuncoro/posindonesia.svg)](https://www.npmjs.com/package/@damarkuncoro/posindonesia)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ **Layanan Integrasi Data Kode Pos Indonesia**
7
+
8
+ Pustaka Node.js profesional yang menyediakan akses programatik ke database kode pos resmi Indonesia. Dirancang untuk keandalan tinggi, akurasi data, dan kemudahan integrasi ke dalam sistem skala perusahaan (*enterprise*).
9
+
10
+ ## Ikhtisar Layanan
11
+
12
+ Paket ini memungkinkan pengembang untuk melakukan sinkronisasi data wilayah administrasi Indonesia (Provinsi, Kabupaten/Kota, Kecamatan, Desa/Kelurahan) dengan database kode pos terbaru melalui jalur integrasi yang dioptimalkan.
13
+
14
+ ### Fitur Utama
15
+
16
+ - **Akurasi Data Terjamin**: Mengambil informasi langsung dari sumber data primer integrasi wilayah.
17
+ - **Smart Validation Engine**: Algoritma pencocokan cerdas yang mengoreksi variasi penulisan nama daerah untuk memastikan kode pos yang tepat.
18
+ - **Efisiensi Batch**: Kemampuan pemrosesan data masal (*bulk processing*) dengan manajemen beban kerja (*rate limiting*) otomatis.
19
+ - **Arsitektur Modular**: Mendukung penggunaan sebagai Command Line Interface (CLI) maupun sebagai Library (SDK) dalam aplikasi Node.js/TypeScript.
20
+
21
+ ## Instalasi
22
+
23
+ Gunakan pengelola paket npm untuk menginstal SDK ini ke dalam proyek Anda:
24
+
25
+ ```bash
26
+ npm install @damarkuncoro/posindonesia
27
+ ```
28
+
29
+ ## Panduan Penggunaan
30
+
31
+ ### Integrasi SDK (Library Mode)
32
+
33
+ SDK ini dirancang dengan dukungan TypeScript penuh untuk pengalaman pengembangan yang maksimal.
34
+
35
+ ```typescript
36
+ import { runScraper } from '@damarkuncoro/posindonesia';
37
+
38
+ async function syncPostalData() {
39
+ const results = await runScraper({
40
+ input: './data/villages.csv',
41
+ limit: 100,
42
+ delay: 1000
43
+ }, (current, total, village) => {
44
+ console.log(`Sinkronisasi: ${village} (${current}/${total})`);
45
+ });
46
+ }
47
+ ```
48
+
49
+ ### Antarmuka Baris Perintah (CLI Mode)
50
+
51
+ Gunakan perintah `scrape-pos` untuk menjalankan sinkronisasi data secara langsung melalui terminal:
52
+
53
+ ```bash
54
+ # Menjalankan sinkronisasi default
55
+ npm start
56
+
57
+ # Menjalankan dengan konfigurasi kustom
58
+ npm start -- --input ./data_input.csv --output ./hasil_sinkronisasi.json --limit 500 --delay 2000
59
+ ```
60
+
61
+ ## Spesifikasi Data Output
62
+
63
+ Hasil integrasi akan disajikan dalam format JSON standar industri:
64
+
65
+ ```json
66
+ {
67
+ "code": "11.01.01.2001",
68
+ "name": "Keude Bakongan",
69
+ "districtCode": "11.01.01",
70
+ "type": "DESA",
71
+ "provinceName": "Aceh",
72
+ "regencyName": "Kab. Aceh Selatan",
73
+ "districtName": "Bakongan",
74
+ "postalCode": "23773"
75
+ }
76
+ ```
77
+
78
+ ## Keamanan & Kepatuhan
79
+
80
+ Kami sangat menghargai integritas data dan keberlangsungan layanan. Pengguna diharapkan untuk:
81
+ 1. Mematuhi kebijakan penggunaan data wilayah yang berlaku.
82
+ 2. Menggunakan jeda waktu (`delay`) yang wajar dalam pemrosesan masal untuk menjaga stabilitas layanan.
83
+
84
+ ## Lisensi
85
+
86
+ Didistribusikan di bawah lisensi [MIT](LICENSE).
87
+
88
+ ---
89
+ *Dikembangkan secara profesional untuk mendukung digitalisasi data wilayah Indonesia.*
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Sends a POST request to Pos Indonesia CariKodepos endpoint.
3
+ * @param keyword - The search keyword (village name or postal code)
4
+ * @param cookie - Optional session cookie
5
+ * @returns The raw HTML response
6
+ */
7
+ export declare function fetchPostalCodeHtml(keyword: string, cookie?: string): Promise<string>;
8
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAqB3F"}
package/lib/cjs/api.js ADDED
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.fetchPostalCodeHtml = fetchPostalCodeHtml;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const qs_1 = __importDefault(require("qs"));
9
+ /**
10
+ * Sends a POST request to Pos Indonesia CariKodepos endpoint.
11
+ * @param keyword - The search keyword (village name or postal code)
12
+ * @param cookie - Optional session cookie
13
+ * @returns The raw HTML response
14
+ */
15
+ async function fetchPostalCodeHtml(keyword, cookie) {
16
+ const URL = 'https://kodepos.posindonesia.co.id/CariKodepos';
17
+ const payload = qs_1.default.stringify({ kodepos: keyword });
18
+ try {
19
+ const response = await axios_1.default.post(URL, payload, {
20
+ headers: {
21
+ 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
22
+ 'accept-language': 'en-US,en;q=0.9,id;q=0.8,ms;q=0.7',
23
+ 'content-type': 'application/x-www-form-urlencoded',
24
+ 'origin': 'https://kodepos.posindonesia.co.id',
25
+ 'referer': 'https://kodepos.posindonesia.co.id/CariKodepos',
26
+ 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36',
27
+ 'cookie': cookie || 'ci_session=siodf5sn3081n9fb1h3pfh7k8r92sjvt; TS011d97f9=01dc40192af9d2c68e0588cf6826f2541733c6f742d0e6382757bb95d8a2f8d27f6da94b22391892939703ae744a8f47fe7d578583'
28
+ },
29
+ timeout: 15000
30
+ });
31
+ return response.data;
32
+ }
33
+ catch (error) {
34
+ throw new Error(`Failed to fetch data for ${keyword}: ${error.message}`);
35
+ }
36
+ }
37
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":";;;;;AASA,kDAqBC;AA9BD,kDAA0B;AAC1B,4CAAoB;AAEpB;;;;;GAKG;AACI,KAAK,UAAU,mBAAmB,CAAC,OAAe,EAAE,MAAe;IACtE,MAAM,GAAG,GAAG,gDAAgD,CAAC;IAC7D,MAAM,OAAO,GAAG,YAAE,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IAEnD,IAAI,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,eAAK,CAAC,IAAI,CAAS,GAAG,EAAE,OAAO,EAAE;YACpD,OAAO,EAAE;gBACL,QAAQ,EAAE,yIAAyI;gBACnJ,iBAAiB,EAAE,kCAAkC;gBACrD,cAAc,EAAE,mCAAmC;gBACnD,QAAQ,EAAE,oCAAoC;gBAC9C,SAAS,EAAE,gDAAgD;gBAC3D,YAAY,EAAE,uHAAuH;gBACrI,QAAQ,EAAE,MAAM,IAAI,oKAAoK;aAC3L;YACD,OAAO,EAAE,KAAK;SACjB,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,IAAI,CAAC;IACzB,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,4BAA4B,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7E,CAAC;AACL,CAAC"}
@@ -0,0 +1,25 @@
1
+ export interface ScraperOptions {
2
+ input: string;
3
+ limit: number;
4
+ delay: number;
5
+ cookie?: string;
6
+ }
7
+ export interface ScrapedVillage {
8
+ code: string;
9
+ name: string;
10
+ districtCode: string;
11
+ type: string;
12
+ provinceName: string;
13
+ regencyName: string;
14
+ districtName: string;
15
+ postalCode: string;
16
+ }
17
+ export type ProgressCallback = (current: number, total: number, village: string) => void;
18
+ /**
19
+ * Core scraping logic separated from CLI.
20
+ * @param options - Configuration options
21
+ * @param onProgress - Callback for progress updates
22
+ * @returns Scraped results
23
+ */
24
+ export declare function runScraper(options: ScraperOptions, onProgress?: ProgressCallback): Promise<ScrapedVillage[]>;
25
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/core.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,cAAc;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAEzF;;;;;GAKG;AACH,wBAAsB,UAAU,CAC5B,OAAO,EAAE,cAAc,EACvB,UAAU,GAAE,gBAA2B,GACxC,OAAO,CAAC,cAAc,EAAE,CAAC,CAkD3B"}
@@ -0,0 +1,90 @@
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.runScraper = runScraper;
37
+ const fs = __importStar(require("fs"));
38
+ const api_1 = require("./api");
39
+ const parser_1 = require("./parser");
40
+ const utils_1 = require("./utils");
41
+ /**
42
+ * Core scraping logic separated from CLI.
43
+ * @param options - Configuration options
44
+ * @param onProgress - Callback for progress updates
45
+ * @returns Scraped results
46
+ */
47
+ async function runScraper(options, onProgress = () => { }) {
48
+ const { input, limit, delay, cookie } = options;
49
+ if (!fs.existsSync(input)) {
50
+ throw new Error(`Input file not found at ${input}`);
51
+ }
52
+ const csvData = fs.readFileSync(input, 'utf-8');
53
+ const lines = csvData.split('\n').filter(line => line.trim() !== '');
54
+ const rows = lines.slice(1);
55
+ const totalToProcess = Math.min(rows.length, limit);
56
+ const scrapedResults = [];
57
+ for (let i = 0; i < totalToProcess; i++) {
58
+ const values = rows[i].split(',');
59
+ const code = values[0];
60
+ const name = values[1];
61
+ const prov = values[2];
62
+ const kab = values[3];
63
+ const kec = values[4];
64
+ onProgress(i, totalToProcess, name);
65
+ try {
66
+ const html = await (0, api_1.fetchPostalCodeHtml)(name, cookie);
67
+ const results = (0, parser_1.parsePostalCodeTable)(html);
68
+ const bestMatch = (0, utils_1.findBestMatch)(results, name, kec);
69
+ scrapedResults.push({
70
+ code: (0, utils_1.formatCode)(code),
71
+ name: name,
72
+ districtCode: (0, utils_1.formatCode)(code.substring(0, 6)),
73
+ type: "DESA",
74
+ provinceName: prov,
75
+ regencyName: kab,
76
+ districtName: kec,
77
+ postalCode: bestMatch ? bestMatch.kodepos : ""
78
+ });
79
+ }
80
+ catch (error) {
81
+ console.error(`\n⚠️ Failed to scrape ${name}: ${error.message}`);
82
+ }
83
+ if (i < totalToProcess - 1) {
84
+ await new Promise(r => setTimeout(r, delay));
85
+ }
86
+ }
87
+ onProgress(totalToProcess, totalToProcess, 'Completed!');
88
+ return scrapedResults;
89
+ }
90
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const commander_1 = require("commander");
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const chalk_1 = __importDefault(require("chalk"));
44
+ const cliProgress = __importStar(require("cli-progress"));
45
+ const core_1 = require("./core");
46
+ commander_1.program
47
+ .name('@damarkuncoro/posindonesia')
48
+ .description('Professional Indonesian Postal Code Scraper')
49
+ .version('1.0.0')
50
+ .option('-i, --input <path>', 'Input CSV file path', path.join(__dirname, '../../../docs/database_final.csv'))
51
+ .option('-o, --output <path>', 'Output JSON file path', path.join(__dirname, '../results/scraped_villages_detailed.json'))
52
+ .option('-l, --limit <number>', 'Number of rows to process', '10')
53
+ .option('-d, --delay <ms>', 'Delay between requests in milliseconds', '1000')
54
+ .option('-c, --cookie <string>', 'Custom session cookie for Pos Indonesia site')
55
+ .action(async (options) => {
56
+ const { output, limit, delay } = options;
57
+ console.log(chalk_1.default.blue.bold('\n🚀 Starting Indonesian Postal Code Scraper (TypeScript)\n'));
58
+ const progressBar = new cliProgress.SingleBar({
59
+ format: chalk_1.default.green('Progress |') + chalk_1.default.cyan('{bar}') + '| {percentage}% || {value}/{total} Villages || {village}',
60
+ barCompleteChar: '\u2588',
61
+ barIncompleteChar: '\u2591',
62
+ hideCursor: true
63
+ });
64
+ try {
65
+ const results = await (0, core_1.runScraper)({
66
+ ...options,
67
+ limit: parseInt(limit),
68
+ delay: parseInt(delay)
69
+ }, (current, total, village) => {
70
+ if (current === 0) {
71
+ progressBar.start(total, 0, { village });
72
+ }
73
+ else {
74
+ progressBar.update(current, { village });
75
+ }
76
+ });
77
+ progressBar.stop();
78
+ // Ensure output directory exists
79
+ const outputDir = path.dirname(output);
80
+ if (!fs.existsSync(outputDir)) {
81
+ fs.mkdirSync(outputDir, { recursive: true });
82
+ }
83
+ fs.writeFileSync(output, JSON.stringify(results, null, 2));
84
+ console.log(chalk_1.default.green.bold(`\n✅ Success! Scraped data saved to:`));
85
+ console.log(chalk_1.default.underline(output));
86
+ console.log('\n');
87
+ }
88
+ catch (error) {
89
+ if (progressBar.isActive)
90
+ progressBar.stop();
91
+ console.error(chalk_1.default.red(`\n❌ Error: ${error.message}`));
92
+ process.exit(1);
93
+ }
94
+ });
95
+ commander_1.program.parse(process.argv);
96
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,yCAAoC;AACpC,uCAAyB;AACzB,2CAA6B;AAC7B,kDAA0B;AAC1B,0DAA4C;AAC5C,iCAAoC;AAEpC,mBAAO;KACJ,IAAI,CAAC,4BAA4B,CAAC;KAClC,WAAW,CAAC,6CAA6C,CAAC;KAC1D,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,oBAAoB,EAAE,qBAAqB,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kCAAkC,CAAC,CAAC;KAC7G,MAAM,CAAC,qBAAqB,EAAE,uBAAuB,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,2CAA2C,CAAC,CAAC;KACzH,MAAM,CAAC,sBAAsB,EAAE,2BAA2B,EAAE,IAAI,CAAC;KACjE,MAAM,CAAC,kBAAkB,EAAE,wCAAwC,EAAE,MAAM,CAAC;KAC5E,MAAM,CAAC,uBAAuB,EAAE,8CAA8C,CAAC;KAC/E,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAEzC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,IAAI,CAAC,6DAA6D,CAAC,CAAC,CAAC;IAE5F,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,SAAS,CAAC;QAC5C,MAAM,EAAE,eAAK,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,eAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,0DAA0D;QACpH,eAAe,EAAE,QAAQ;QACzB,iBAAiB,EAAE,QAAQ;QAC3B,UAAU,EAAE,IAAI;KACjB,CAAC,CAAC;IAEH,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,IAAA,iBAAU,EAAC;YAC7B,GAAG,OAAO;YACV,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC;YACtB,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC;SACzB,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YAC3B,IAAI,OAAO,KAAK,CAAC,EAAE,CAAC;gBAChB,WAAW,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;YAC7C,CAAC;iBAAM,CAAC;gBACJ,WAAW,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;YAC7C,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,WAAW,CAAC,IAAI,EAAE,CAAC;QAEnB,iCAAiC;QACjC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC5B,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,CAAC;QAED,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAE3D,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC,CAAC;QACrE,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QAClB,IAAI,WAAW,CAAC,QAAQ;YAAE,WAAW,CAAC,IAAI,EAAE,CAAC;QAC7C,OAAO,CAAC,KAAK,CAAC,eAAK,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,mBAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import winston from 'winston';
2
+ declare const logger: winston.Logger;
3
+ export default logger;
4
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAG9B,QAAA,MAAM,MAAM,gBAeV,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const winston_1 = __importDefault(require("winston"));
7
+ const path_1 = __importDefault(require("path"));
8
+ const logger = winston_1.default.createLogger({
9
+ level: 'info',
10
+ format: winston_1.default.format.combine(winston_1.default.format.timestamp(), winston_1.default.format.json()),
11
+ transports: [
12
+ new winston_1.default.transports.File({
13
+ filename: path_1.default.join(__dirname, '../results/error.log'),
14
+ level: 'error'
15
+ }),
16
+ new winston_1.default.transports.File({
17
+ filename: path_1.default.join(__dirname, '../results/combined.log')
18
+ }),
19
+ ],
20
+ });
21
+ exports.default = logger;
22
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":";;;;;AAAA,sDAA8B;AAC9B,gDAAwB;AAExB,MAAM,MAAM,GAAG,iBAAO,CAAC,YAAY,CAAC;IAClC,KAAK,EAAE,MAAM;IACb,MAAM,EAAE,iBAAO,CAAC,MAAM,CAAC,OAAO,CAC5B,iBAAO,CAAC,MAAM,CAAC,SAAS,EAAE,EAC1B,iBAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CACtB;IACD,UAAU,EAAE;QACV,IAAI,iBAAO,CAAC,UAAU,CAAC,IAAI,CAAC;YAC1B,QAAQ,EAAE,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,sBAAsB,CAAC;YACtD,KAAK,EAAE,OAAO;SACf,CAAC;QACF,IAAI,iBAAO,CAAC,UAAU,CAAC,IAAI,CAAC;YAC1B,QAAQ,EAAE,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,yBAAyB,CAAC;SAC1D,CAAC;KACH;CACF,CAAC,CAAC;AAEH,kBAAe,MAAM,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './core';
2
+ export * from './api';
3
+ export * from './parser';
4
+ export * from './utils';
5
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
@@ -0,0 +1,21 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./core"), exports);
18
+ __exportStar(require("./api"), exports);
19
+ __exportStar(require("./parser"), exports);
20
+ __exportStar(require("./utils"), exports);
21
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yCAAuB;AACvB,wCAAsB;AACtB,2CAAyB;AACzB,0CAAwB"}
@@ -0,0 +1,15 @@
1
+ export interface PostalCodeResult {
2
+ no: string;
3
+ kodepos: string;
4
+ desa_kelurahan: string;
5
+ kecamatan: string;
6
+ kabupaten_kota: string;
7
+ provinsi: string;
8
+ }
9
+ /**
10
+ * Parses the raw HTML response from Pos Indonesia CariKodepos.
11
+ * @param html - The raw HTML content
12
+ * @returns List of parsed postal code objects
13
+ */
14
+ export declare function parsePostalCodeTable(html: string): PostalCodeResult[];
15
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAmBrE"}
@@ -0,0 +1,61 @@
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.parsePostalCodeTable = parsePostalCodeTable;
37
+ const cheerio = __importStar(require("cheerio"));
38
+ /**
39
+ * Parses the raw HTML response from Pos Indonesia CariKodepos.
40
+ * @param html - The raw HTML content
41
+ * @returns List of parsed postal code objects
42
+ */
43
+ function parsePostalCodeTable(html) {
44
+ const $ = cheerio.load(html);
45
+ const results = [];
46
+ $('table tbody tr').each((_i, row) => {
47
+ const cols = $(row).find('td');
48
+ if (cols.length >= 6) {
49
+ results.push({
50
+ no: $(cols[0]).text().trim(),
51
+ kodepos: $(cols[1]).text().trim(),
52
+ desa_kelurahan: $(cols[2]).text().trim(),
53
+ kecamatan: $(cols[3]).text().trim(),
54
+ kabupaten_kota: $(cols[4]).text().trim(),
55
+ provinsi: $(cols[5]).text().trim()
56
+ });
57
+ }
58
+ });
59
+ return results;
60
+ }
61
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,oDAmBC;AAnCD,iDAAmC;AAWnC;;;;GAIG;AACH,SAAgB,oBAAoB,CAAC,IAAY;IAC7C,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,OAAO,GAAuB,EAAE,CAAC;IAEvC,CAAC,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE;QACjC,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;gBAC5B,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;gBACjC,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;gBACxC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;gBACnC,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;gBACxC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;aACrC,CAAC,CAAC;QACP,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACnB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { PostalCodeResult } from './parser';
2
+ /**
3
+ * Formats a raw numerical code into standard Indonesian administrative format (PP.KK.CC.DD).
4
+ * @param code - The raw code (e.g., 1101012001)
5
+ * @returns The formatted code (e.g., 11.01.01.2001)
6
+ */
7
+ export declare function formatCode(code: string): string;
8
+ /**
9
+ * Finds the best match in a list of search results using Fuzzy Matching.
10
+ * @param results - The list of parsed results
11
+ * @param villageName - The target village name
12
+ * @param districtName - The target district name
13
+ * @returns The best matching object or null
14
+ */
15
+ export declare function findBestMatch(results: PostalCodeResult[], villageName: string, districtName: string): PostalCodeResult | null;
16
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ/C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CACzB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACrB,gBAAgB,GAAG,IAAI,CAkCzB"}
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.formatCode = formatCode;
7
+ exports.findBestMatch = findBestMatch;
8
+ const fuse_js_1 = __importDefault(require("fuse.js"));
9
+ /**
10
+ * Formats a raw numerical code into standard Indonesian administrative format (PP.KK.CC.DD).
11
+ * @param code - The raw code (e.g., 1101012001)
12
+ * @returns The formatted code (e.g., 11.01.01.2001)
13
+ */
14
+ function formatCode(code) {
15
+ if (!code)
16
+ return '';
17
+ const cleanCode = code.replace(/\./g, '');
18
+ const p1 = cleanCode.substring(0, 2);
19
+ const p2 = cleanCode.substring(2, 4);
20
+ const p3 = cleanCode.substring(4, 6);
21
+ const p4 = cleanCode.substring(6);
22
+ return [p1, p2, p3, p4].filter(Boolean).join('.');
23
+ }
24
+ /**
25
+ * Finds the best match in a list of search results using Fuzzy Matching.
26
+ * @param results - The list of parsed results
27
+ * @param villageName - The target village name
28
+ * @param districtName - The target district name
29
+ * @returns The best matching object or null
30
+ */
31
+ function findBestMatch(results, villageName, districtName) {
32
+ if (!results || results.length === 0)
33
+ return null;
34
+ // 1. Try Exact Match First
35
+ const exactMatch = results.find(r => r.desa_kelurahan.toLowerCase() === villageName.toLowerCase() &&
36
+ r.kecamatan.toLowerCase() === districtName.toLowerCase());
37
+ if (exactMatch)
38
+ return exactMatch;
39
+ // 2. Fuzzy Match using Fuse.js
40
+ const fuseOptions = {
41
+ keys: [
42
+ { name: 'desa_kelurahan', weight: 0.7 },
43
+ { name: 'kecamatan', weight: 0.3 }
44
+ ],
45
+ threshold: 0.4, // Adjust for strictness (0.0 perfect, 1.0 match anything)
46
+ includeScore: true
47
+ };
48
+ const fuse = new fuse_js_1.default(results, fuseOptions);
49
+ const fuzzyResults = fuse.search(`${villageName} ${districtName}`);
50
+ if (fuzzyResults.length > 0) {
51
+ return fuzzyResults[0].item;
52
+ }
53
+ // 3. Fallback to simple contains logic
54
+ return results.find(r => (r.desa_kelurahan.toLowerCase().includes(villageName.toLowerCase()) ||
55
+ villageName.toLowerCase().includes(r.desa_kelurahan.toLowerCase())) &&
56
+ (r.kecamatan.toLowerCase().includes(districtName.toLowerCase()) ||
57
+ districtName.toLowerCase().includes(r.kecamatan.toLowerCase()))) || results[0];
58
+ }
59
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":";;;;;AAQA,gCAQC;AASD,sCAsCC;AA/DD,sDAA2B;AAG3B;;;;GAIG;AACH,SAAgB,UAAU,CAAC,IAAY;IACnC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1C,MAAM,EAAE,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAClC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,aAAa,CACzB,OAA2B,EAC3B,WAAmB,EACnB,YAAoB;IAEpB,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAElD,2BAA2B;IAC3B,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAChC,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,KAAK,WAAW,CAAC,WAAW,EAAE;QAC5D,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,KAAK,YAAY,CAAC,WAAW,EAAE,CAC3D,CAAC;IACF,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC;IAElC,+BAA+B;IAC/B,MAAM,WAAW,GAAG;QAChB,IAAI,EAAE;YACF,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,EAAE;YACvC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE;SACrC;QACD,SAAS,EAAE,GAAG,EAAE,0DAA0D;QAC1E,YAAY,EAAE,IAAI;KACrB,CAAC;IAEF,MAAM,IAAI,GAAG,IAAI,iBAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC5C,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,WAAW,IAAI,YAAY,EAAE,CAAC,CAAC;IAEnE,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChC,CAAC;IAED,uCAAuC;IACvC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CACpB,CAAC,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;QAClE,WAAW,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;YAC9D,YAAY,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CACnE,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Sends a POST request to Pos Indonesia CariKodepos endpoint.
3
+ * @param keyword - The search keyword (village name or postal code)
4
+ * @param cookie - Optional session cookie
5
+ * @returns The raw HTML response
6
+ */
7
+ export declare function fetchPostalCodeHtml(keyword: string, cookie?: string): Promise<string>;
8
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAqB3F"}
package/lib/esm/api.js ADDED
@@ -0,0 +1,31 @@
1
+ import axios from 'axios';
2
+ import qs from 'qs';
3
+ /**
4
+ * Sends a POST request to Pos Indonesia CariKodepos endpoint.
5
+ * @param keyword - The search keyword (village name or postal code)
6
+ * @param cookie - Optional session cookie
7
+ * @returns The raw HTML response
8
+ */
9
+ export async function fetchPostalCodeHtml(keyword, cookie) {
10
+ const URL = 'https://kodepos.posindonesia.co.id/CariKodepos';
11
+ const payload = qs.stringify({ kodepos: keyword });
12
+ try {
13
+ const response = await axios.post(URL, payload, {
14
+ headers: {
15
+ 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
16
+ 'accept-language': 'en-US,en;q=0.9,id;q=0.8,ms;q=0.7',
17
+ 'content-type': 'application/x-www-form-urlencoded',
18
+ 'origin': 'https://kodepos.posindonesia.co.id',
19
+ 'referer': 'https://kodepos.posindonesia.co.id/CariKodepos',
20
+ 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36',
21
+ 'cookie': cookie || 'ci_session=siodf5sn3081n9fb1h3pfh7k8r92sjvt; TS011d97f9=01dc40192af9d2c68e0588cf6826f2541733c6f742d0e6382757bb95d8a2f8d27f6da94b22391892939703ae744a8f47fe7d578583'
22
+ },
23
+ timeout: 15000
24
+ });
25
+ return response.data;
26
+ }
27
+ catch (error) {
28
+ throw new Error(`Failed to fetch data for ${keyword}: ${error.message}`);
29
+ }
30
+ }
31
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAe,EAAE,MAAe;IACtE,MAAM,GAAG,GAAG,gDAAgD,CAAC;IAC7D,MAAM,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IAEnD,IAAI,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAS,GAAG,EAAE,OAAO,EAAE;YACpD,OAAO,EAAE;gBACL,QAAQ,EAAE,yIAAyI;gBACnJ,iBAAiB,EAAE,kCAAkC;gBACrD,cAAc,EAAE,mCAAmC;gBACnD,QAAQ,EAAE,oCAAoC;gBAC9C,SAAS,EAAE,gDAAgD;gBAC3D,YAAY,EAAE,uHAAuH;gBACrI,QAAQ,EAAE,MAAM,IAAI,oKAAoK;aAC3L;YACD,OAAO,EAAE,KAAK;SACjB,CAAC,CAAC;QACH,OAAO,QAAQ,CAAC,IAAI,CAAC;IACzB,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,4BAA4B,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7E,CAAC;AACL,CAAC"}
@@ -0,0 +1,25 @@
1
+ export interface ScraperOptions {
2
+ input: string;
3
+ limit: number;
4
+ delay: number;
5
+ cookie?: string;
6
+ }
7
+ export interface ScrapedVillage {
8
+ code: string;
9
+ name: string;
10
+ districtCode: string;
11
+ type: string;
12
+ provinceName: string;
13
+ regencyName: string;
14
+ districtName: string;
15
+ postalCode: string;
16
+ }
17
+ export type ProgressCallback = (current: number, total: number, village: string) => void;
18
+ /**
19
+ * Core scraping logic separated from CLI.
20
+ * @param options - Configuration options
21
+ * @param onProgress - Callback for progress updates
22
+ * @returns Scraped results
23
+ */
24
+ export declare function runScraper(options: ScraperOptions, onProgress?: ProgressCallback): Promise<ScrapedVillage[]>;
25
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/core.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,cAAc;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAEzF;;;;;GAKG;AACH,wBAAsB,UAAU,CAC5B,OAAO,EAAE,cAAc,EACvB,UAAU,GAAE,gBAA2B,GACxC,OAAO,CAAC,cAAc,EAAE,CAAC,CAkD3B"}
@@ -0,0 +1,54 @@
1
+ import * as fs from 'fs';
2
+ import { fetchPostalCodeHtml } from './api';
3
+ import { parsePostalCodeTable } from './parser';
4
+ import { formatCode, findBestMatch } from './utils';
5
+ /**
6
+ * Core scraping logic separated from CLI.
7
+ * @param options - Configuration options
8
+ * @param onProgress - Callback for progress updates
9
+ * @returns Scraped results
10
+ */
11
+ export async function runScraper(options, onProgress = () => { }) {
12
+ const { input, limit, delay, cookie } = options;
13
+ if (!fs.existsSync(input)) {
14
+ throw new Error(`Input file not found at ${input}`);
15
+ }
16
+ const csvData = fs.readFileSync(input, 'utf-8');
17
+ const lines = csvData.split('\n').filter(line => line.trim() !== '');
18
+ const rows = lines.slice(1);
19
+ const totalToProcess = Math.min(rows.length, limit);
20
+ const scrapedResults = [];
21
+ for (let i = 0; i < totalToProcess; i++) {
22
+ const values = rows[i].split(',');
23
+ const code = values[0];
24
+ const name = values[1];
25
+ const prov = values[2];
26
+ const kab = values[3];
27
+ const kec = values[4];
28
+ onProgress(i, totalToProcess, name);
29
+ try {
30
+ const html = await fetchPostalCodeHtml(name, cookie);
31
+ const results = parsePostalCodeTable(html);
32
+ const bestMatch = findBestMatch(results, name, kec);
33
+ scrapedResults.push({
34
+ code: formatCode(code),
35
+ name: name,
36
+ districtCode: formatCode(code.substring(0, 6)),
37
+ type: "DESA",
38
+ provinceName: prov,
39
+ regencyName: kab,
40
+ districtName: kec,
41
+ postalCode: bestMatch ? bestMatch.kodepos : ""
42
+ });
43
+ }
44
+ catch (error) {
45
+ console.error(`\n⚠️ Failed to scrape ${name}: ${error.message}`);
46
+ }
47
+ if (i < totalToProcess - 1) {
48
+ await new Promise(r => setTimeout(r, delay));
49
+ }
50
+ }
51
+ onProgress(totalToProcess, totalToProcess, 'Completed!');
52
+ return scrapedResults;
53
+ }
54
+ //# sourceMappingURL=core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+ import chalk from 'chalk';
6
+ import * as cliProgress from 'cli-progress';
7
+ import { runScraper } from './core';
8
+ program
9
+ .name('@damarkuncoro/posindonesia')
10
+ .description('Professional Indonesian Postal Code Scraper')
11
+ .version('1.0.0')
12
+ .option('-i, --input <path>', 'Input CSV file path', path.join(__dirname, '../../../docs/database_final.csv'))
13
+ .option('-o, --output <path>', 'Output JSON file path', path.join(__dirname, '../results/scraped_villages_detailed.json'))
14
+ .option('-l, --limit <number>', 'Number of rows to process', '10')
15
+ .option('-d, --delay <ms>', 'Delay between requests in milliseconds', '1000')
16
+ .option('-c, --cookie <string>', 'Custom session cookie for Pos Indonesia site')
17
+ .action(async (options) => {
18
+ const { output, limit, delay } = options;
19
+ console.log(chalk.blue.bold('\n🚀 Starting Indonesian Postal Code Scraper (TypeScript)\n'));
20
+ const progressBar = new cliProgress.SingleBar({
21
+ format: chalk.green('Progress |') + chalk.cyan('{bar}') + '| {percentage}% || {value}/{total} Villages || {village}',
22
+ barCompleteChar: '\u2588',
23
+ barIncompleteChar: '\u2591',
24
+ hideCursor: true
25
+ });
26
+ try {
27
+ const results = await runScraper({
28
+ ...options,
29
+ limit: parseInt(limit),
30
+ delay: parseInt(delay)
31
+ }, (current, total, village) => {
32
+ if (current === 0) {
33
+ progressBar.start(total, 0, { village });
34
+ }
35
+ else {
36
+ progressBar.update(current, { village });
37
+ }
38
+ });
39
+ progressBar.stop();
40
+ // Ensure output directory exists
41
+ const outputDir = path.dirname(output);
42
+ if (!fs.existsSync(outputDir)) {
43
+ fs.mkdirSync(outputDir, { recursive: true });
44
+ }
45
+ fs.writeFileSync(output, JSON.stringify(results, null, 2));
46
+ console.log(chalk.green.bold(`\n✅ Success! Scraped data saved to:`));
47
+ console.log(chalk.underline(output));
48
+ console.log('\n');
49
+ }
50
+ catch (error) {
51
+ if (progressBar.isActive)
52
+ progressBar.stop();
53
+ console.error(chalk.red(`\n❌ Error: ${error.message}`));
54
+ process.exit(1);
55
+ }
56
+ });
57
+ program.parse(process.argv);
58
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import winston from 'winston';
2
+ declare const logger: winston.Logger;
3
+ export default logger;
4
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAG9B,QAAA,MAAM,MAAM,gBAeV,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1,17 @@
1
+ import winston from 'winston';
2
+ import path from 'path';
3
+ const logger = winston.createLogger({
4
+ level: 'info',
5
+ format: winston.format.combine(winston.format.timestamp(), winston.format.json()),
6
+ transports: [
7
+ new winston.transports.File({
8
+ filename: path.join(__dirname, '../results/error.log'),
9
+ level: 'error'
10
+ }),
11
+ new winston.transports.File({
12
+ filename: path.join(__dirname, '../results/combined.log')
13
+ }),
14
+ ],
15
+ });
16
+ export default logger;
17
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAClC,KAAK,EAAE,MAAM;IACb,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAC5B,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,EAC1B,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CACtB;IACD,UAAU,EAAE;QACV,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;YAC1B,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,sBAAsB,CAAC;YACtD,KAAK,EAAE,OAAO;SACf,CAAC;QACF,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;YAC1B,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,yBAAyB,CAAC;SAC1D,CAAC;KACH;CACF,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './core';
2
+ export * from './api';
3
+ export * from './parser';
4
+ export * from './utils';
5
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './core';
2
+ export * from './api';
3
+ export * from './parser';
4
+ export * from './utils';
5
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/main.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
@@ -0,0 +1,15 @@
1
+ export interface PostalCodeResult {
2
+ no: string;
3
+ kodepos: string;
4
+ desa_kelurahan: string;
5
+ kecamatan: string;
6
+ kabupaten_kota: string;
7
+ provinsi: string;
8
+ }
9
+ /**
10
+ * Parses the raw HTML response from Pos Indonesia CariKodepos.
11
+ * @param html - The raw HTML content
12
+ * @returns List of parsed postal code objects
13
+ */
14
+ export declare function parsePostalCodeTable(html: string): PostalCodeResult[];
15
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAmBrE"}
@@ -0,0 +1,25 @@
1
+ import * as cheerio from 'cheerio';
2
+ /**
3
+ * Parses the raw HTML response from Pos Indonesia CariKodepos.
4
+ * @param html - The raw HTML content
5
+ * @returns List of parsed postal code objects
6
+ */
7
+ export function parsePostalCodeTable(html) {
8
+ const $ = cheerio.load(html);
9
+ const results = [];
10
+ $('table tbody tr').each((_i, row) => {
11
+ const cols = $(row).find('td');
12
+ if (cols.length >= 6) {
13
+ results.push({
14
+ no: $(cols[0]).text().trim(),
15
+ kodepos: $(cols[1]).text().trim(),
16
+ desa_kelurahan: $(cols[2]).text().trim(),
17
+ kecamatan: $(cols[3]).text().trim(),
18
+ kabupaten_kota: $(cols[4]).text().trim(),
19
+ provinsi: $(cols[5]).text().trim()
20
+ });
21
+ }
22
+ });
23
+ return results;
24
+ }
25
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAWnC;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC7C,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,OAAO,GAAuB,EAAE,CAAC;IAEvC,CAAC,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE;QACjC,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;gBAC5B,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;gBACjC,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;gBACxC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;gBACnC,cAAc,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;gBACxC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;aACrC,CAAC,CAAC;QACP,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,OAAO,CAAC;AACnB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { PostalCodeResult } from './parser';
2
+ /**
3
+ * Formats a raw numerical code into standard Indonesian administrative format (PP.KK.CC.DD).
4
+ * @param code - The raw code (e.g., 1101012001)
5
+ * @returns The formatted code (e.g., 11.01.01.2001)
6
+ */
7
+ export declare function formatCode(code: string): string;
8
+ /**
9
+ * Finds the best match in a list of search results using Fuzzy Matching.
10
+ * @param results - The list of parsed results
11
+ * @param villageName - The target village name
12
+ * @param districtName - The target district name
13
+ * @returns The best matching object or null
14
+ */
15
+ export declare function findBestMatch(results: PostalCodeResult[], villageName: string, districtName: string): PostalCodeResult | null;
16
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ/C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CACzB,OAAO,EAAE,gBAAgB,EAAE,EAC3B,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,GACrB,gBAAgB,GAAG,IAAI,CAkCzB"}
@@ -0,0 +1,52 @@
1
+ import Fuse from 'fuse.js';
2
+ /**
3
+ * Formats a raw numerical code into standard Indonesian administrative format (PP.KK.CC.DD).
4
+ * @param code - The raw code (e.g., 1101012001)
5
+ * @returns The formatted code (e.g., 11.01.01.2001)
6
+ */
7
+ export function formatCode(code) {
8
+ if (!code)
9
+ return '';
10
+ const cleanCode = code.replace(/\./g, '');
11
+ const p1 = cleanCode.substring(0, 2);
12
+ const p2 = cleanCode.substring(2, 4);
13
+ const p3 = cleanCode.substring(4, 6);
14
+ const p4 = cleanCode.substring(6);
15
+ return [p1, p2, p3, p4].filter(Boolean).join('.');
16
+ }
17
+ /**
18
+ * Finds the best match in a list of search results using Fuzzy Matching.
19
+ * @param results - The list of parsed results
20
+ * @param villageName - The target village name
21
+ * @param districtName - The target district name
22
+ * @returns The best matching object or null
23
+ */
24
+ export function findBestMatch(results, villageName, districtName) {
25
+ if (!results || results.length === 0)
26
+ return null;
27
+ // 1. Try Exact Match First
28
+ const exactMatch = results.find(r => r.desa_kelurahan.toLowerCase() === villageName.toLowerCase() &&
29
+ r.kecamatan.toLowerCase() === districtName.toLowerCase());
30
+ if (exactMatch)
31
+ return exactMatch;
32
+ // 2. Fuzzy Match using Fuse.js
33
+ const fuseOptions = {
34
+ keys: [
35
+ { name: 'desa_kelurahan', weight: 0.7 },
36
+ { name: 'kecamatan', weight: 0.3 }
37
+ ],
38
+ threshold: 0.4, // Adjust for strictness (0.0 perfect, 1.0 match anything)
39
+ includeScore: true
40
+ };
41
+ const fuse = new Fuse(results, fuseOptions);
42
+ const fuzzyResults = fuse.search(`${villageName} ${districtName}`);
43
+ if (fuzzyResults.length > 0) {
44
+ return fuzzyResults[0].item;
45
+ }
46
+ // 3. Fallback to simple contains logic
47
+ return results.find(r => (r.desa_kelurahan.toLowerCase().includes(villageName.toLowerCase()) ||
48
+ villageName.toLowerCase().includes(r.desa_kelurahan.toLowerCase())) &&
49
+ (r.kecamatan.toLowerCase().includes(districtName.toLowerCase()) ||
50
+ districtName.toLowerCase().includes(r.kecamatan.toLowerCase()))) || results[0];
51
+ }
52
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,SAAS,CAAC;AAG3B;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACnC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1C,MAAM,EAAE,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAClC,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CACzB,OAA2B,EAC3B,WAAmB,EACnB,YAAoB;IAEpB,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAElD,2BAA2B;IAC3B,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAChC,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,KAAK,WAAW,CAAC,WAAW,EAAE;QAC5D,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,KAAK,YAAY,CAAC,WAAW,EAAE,CAC3D,CAAC;IACF,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC;IAElC,+BAA+B;IAC/B,MAAM,WAAW,GAAG;QAChB,IAAI,EAAE;YACF,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,EAAE;YACvC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE;SACrC;QACD,SAAS,EAAE,GAAG,EAAE,0DAA0D;QAC1E,YAAY,EAAE,IAAI;KACrB,CAAC;IAEF,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAC5C,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,WAAW,IAAI,YAAY,EAAE,CAAC,CAAC;IAEnE,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChC,CAAC;IAED,uCAAuC;IACvC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CACpB,CAAC,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;QAClE,WAAW,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC;YAC9D,YAAY,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC,CACnE,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "@damarkuncoro/posindonesia",
3
+ "version": "1.0.0",
4
+ "description": "Indonesian Postal Code Scraper from Pos Indonesia Official Website",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/damarkuncoro/posindonesia.git"
8
+ },
9
+ "bugs": {
10
+ "url": "https://github.com/damarkuncoro/posindonesia/issues"
11
+ },
12
+ "homepage": "https://github.com/damarkuncoro/posindonesia#readme",
13
+ "main": "lib/cjs/main.js",
14
+ "module": "lib/esm/main.js",
15
+ "types": "lib/cjs/main.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "import": "./lib/esm/main.js",
19
+ "require": "./lib/cjs/main.js",
20
+ "types": "./lib/cjs/main.d.ts"
21
+ }
22
+ },
23
+ "bin": {
24
+ "scrape-pos": "lib/cjs/index.js"
25
+ },
26
+ "scripts": {
27
+ "start": "ts-node src/index.ts",
28
+ "build:cjs": "tsc -p tsconfig.cjs.json",
29
+ "build:esm": "tsc -p tsconfig.esm.json",
30
+ "build": "rm -rf lib && npm run build:cjs && npm run build:esm",
31
+ "prepublishOnly": "npm run build && npm test",
32
+ "scrape": "ts-node src/index.ts",
33
+ "test": "jest"
34
+ },
35
+ "keywords": [
36
+ "indonesia",
37
+ "postal-code",
38
+ "kodepos",
39
+ "scraper",
40
+ "pos-indonesia",
41
+ "typescript"
42
+ ],
43
+ "author": "damarkuncoro",
44
+ "files": [
45
+ "lib",
46
+ "README.md",
47
+ "LICENSE"
48
+ ],
49
+ "license": "MIT",
50
+ "publishConfig": {
51
+ "access": "public"
52
+ },
53
+ "dependencies": {
54
+ "axios": "^1.13.6",
55
+ "chalk": "^4.1.2",
56
+ "cheerio": "^1.2.0",
57
+ "cli-progress": "^3.12.0",
58
+ "commander": "^14.0.3",
59
+ "puppeteer": "^24.39.0",
60
+ "qs": "^6.15.0",
61
+ "fuse.js": "^7.1.0",
62
+ "winston": "^3.19.0"
63
+ },
64
+ "devDependencies": {
65
+ "@types/axios": "^0.9.36",
66
+ "@types/chalk": "^0.4.31",
67
+ "@types/cheerio": "^0.22.35",
68
+ "@types/cli-progress": "^3.11.6",
69
+ "@types/jest": "^30.0.0",
70
+ "@types/node": "^25.5.0",
71
+ "@types/qs": "^6.15.0",
72
+ "jest": "^30.3.0",
73
+ "ts-jest": "^29.4.6",
74
+ "ts-node": "^10.9.2",
75
+ "typescript": "^5.9.3"
76
+ }
77
+ }