UNPKG

phil-address

Version:

Lightweight Philippine address data fetcher with smart caching, search, and request deduplication

1,477 lines (1,438 loc) 49.8 kB
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _arrayWithHoles(r) { if (Array.isArray(r)) return r; } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); } function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; } function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var n = 0, F = function () {}; return { s: F, n: function () { return n >= r.length ? { done: !0 } : { done: !1, value: r[n++] }; }, e: function (r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function () { t = t.call(r); }, n: function () { var r = t.next(); return a = r.done, r; }, e: function (r) { u = !0, o = r; }, f: function () { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread2(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function (t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i.return) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine(u), _regeneratorDefine(u, o, "Generator"), _regeneratorDefine(u, n, function () { return this; }), _regeneratorDefine(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function () { return { w: i, m: f }; })(); } function _regeneratorDefine(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine = function (e, r, n, t) { if (r) i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n;else { function o(r, n) { _regeneratorDefine(e, r, function (e) { return this._invoke(r, n, e); }); } o("next", 0), o("throw", 1), o("return", 2); } }, _regeneratorDefine(e, r, n, t); } function _regeneratorValues(e) { if (null != e) { var t = e["function" == typeof Symbol && Symbol.iterator || "@@iterator"], r = 0; if (t) return t.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) return { next: function () { return e && r >= e.length && (e = void 0), { value: e && e[r++], done: !e }; } }; } throw new TypeError(typeof e + " is not iterable"); } function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } // --------------------------------------------------------------------- // API Base URL and Cache Configuration // --------------------------------------------------------------------- /** * The base URL for the Philippine address API. * All subsequent API calls will prepend this URL. * * @constant {string} */ var API = 'https://phil-address-api.portal-api.workers.dev'; /** * Cache Time-To-Live in milliseconds. * The default value (1 hour) determines how long cached data remains valid. * * @constant {number} */ var CACHE_TTL = 3600000; // --------------------------------------------------------------------- // Caching Variables with TTL Support // --------------------------------------------------------------------- /** * Cache for regions data. * @type {{data: Array|null, timestamp: number}} */ var regionsCache = { data: null, timestamp: 0 }; /** * Cache for provinces data, keyed by region code. * @type {Object.<string, {data: Array, timestamp: number}>} */ var provincesCache = {}; /** * Cache for cities data, keyed by province code. * @type {Object.<string, {data: Array, timestamp: number}>} */ var citiesCache = {}; /** * Cache for barangays data, keyed by city code. * @type {Object.<string, {data: Array, timestamp: number}>} */ var barangaysCache = {}; // --------------------------------------------------------------------- // Request Deduplication // Prevents multiple simultaneous requests for the same resource // --------------------------------------------------------------------- /** * Pending requests map to prevent duplicate API calls * @type {Map<string, Promise>} */ var pendingRequests = new Map(); // --------------------------------------------------------------------- // Configuration Options // --------------------------------------------------------------------- /** * Global configuration options * @type {{cacheTTL: number, timeout: number, retries: number}} */ var config = { cacheTTL: CACHE_TTL, timeout: 10000, // 10 seconds retries: 3 }; /** * Configure the package settings * @param {Object} options - Configuration options * @param {number} [options.cacheTTL] - Cache TTL in milliseconds * @param {number} [options.timeout] - Request timeout in milliseconds * @param {number} [options.retries] - Number of retry attempts */ function configure(options) { config = _objectSpread2(_objectSpread2({}, config), options); } // --------------------------------------------------------------------- // Utility Functions // --------------------------------------------------------------------- /** * Performs a fetch request with timeout and retry logic * @param {string} url - The URL to fetch * @param {number} [retries] - Number of retry attempts remaining * @returns {Promise<Response>} */ function fetchWithTimeout(_x) { return _fetchWithTimeout.apply(this, arguments); } /** * Performance monitoring configuration */ function _fetchWithTimeout() { _fetchWithTimeout = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(url) { var retries, controller, timeout, response, _args = arguments, _t; return _regenerator().w(function (_context) { while (1) switch (_context.n) { case 0: retries = _args.length > 1 && _args[1] !== undefined ? _args[1] : config.retries; controller = new AbortController(); timeout = setTimeout(function () { return controller.abort(); }, config.timeout); _context.p = 1; _context.n = 2; return fetch(url, { signal: controller.signal }); case 2: response = _context.v; clearTimeout(timeout); if (!(!response.ok && retries > 0)) { _context.n = 4; break; } _context.n = 3; return new Promise(function (resolve) { return setTimeout(resolve, (config.retries - retries + 1) * 1000); }); case 3: return _context.a(2, fetchWithTimeout(url, retries - 1)); case 4: return _context.a(2, response); case 5: _context.p = 5; _t = _context.v; clearTimeout(timeout); if (!(_t.name === 'AbortError')) { _context.n = 6; break; } throw new Error('Request timeout'); case 6: if (!(retries > 0)) { _context.n = 8; break; } _context.n = 7; return new Promise(function (resolve) { return setTimeout(resolve, (config.retries - retries + 1) * 1000); }); case 7: return _context.a(2, fetchWithTimeout(url, retries - 1)); case 8: throw _t; case 9: return _context.a(2); } }, _callee, null, [[1, 5]]); })); return _fetchWithTimeout.apply(this, arguments); } var performanceConfig = { enabled: false, logSlowRequests: true, slowRequestThreshold: 1000 // ms }; /** * Performance metrics storage */ var performanceMetrics = { apiCalls: 0, cacheHits: 0, cacheMisses: 0, totalResponseTime: 0, slowRequests: [] }; /** * Enable/disable performance monitoring * @param {boolean} enabled - Whether to enable monitoring * @param {Object} options - Monitoring options */ function configurePerformanceMonitoring(enabled) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; performanceConfig = _objectSpread2(_objectSpread2({}, performanceConfig), {}, { enabled: enabled }, options); } function getPerformanceMetrics() { var avgResponseTime = performanceMetrics.apiCalls > 0 ? Math.round(performanceMetrics.totalResponseTime / performanceMetrics.apiCalls) : 0; var cacheHitRate = performanceMetrics.cacheHits + performanceMetrics.cacheMisses > 0 ? Math.round(performanceMetrics.cacheHits / (performanceMetrics.cacheHits + performanceMetrics.cacheMisses) * 100) : 0; return _objectSpread2(_objectSpread2({}, performanceMetrics), {}, { avgResponseTime: avgResponseTime, cacheHitRate: "".concat(cacheHitRate, "%"), summary: { totalCalls: performanceMetrics.apiCalls, avgResponseTime: "".concat(avgResponseTime, "ms"), cacheEfficiency: "".concat(cacheHitRate, "%"), slowRequestCount: performanceMetrics.slowRequests.length } }); } /** * Reset performance metrics */ function resetPerformanceMetrics() { performanceMetrics.apiCalls = 0; performanceMetrics.cacheHits = 0; performanceMetrics.cacheMisses = 0; performanceMetrics.totalResponseTime = 0; performanceMetrics.slowRequests = []; } /** * Generic function to load data with caching and deduplication * @param {string} endpoint - API endpoint * @param {Object} cache - Cache object to use * @param {string} cacheKey - Key for caching * @returns {Promise<Array>} */ function loadData(_x4, _x5, _x6) { return _loadData.apply(this, arguments); } // --------------------------------------------------------------------- // API Functions // --------------------------------------------------------------------- /** * Fetches region data from the API * @async * @returns {Promise<Array>} Array of region objects */ function _loadData() { _loadData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(endpoint, cache, cacheKey) { var cacheEntry, pendingKey, requestPromise; return _regenerator().w(function (_context4) { while (1) switch (_context4.n) { case 0: cacheEntry = cache[cacheKey]; if (!(cacheEntry && Date.now() - cacheEntry.timestamp < config.cacheTTL)) { _context4.n = 1; break; } if (performanceConfig.enabled) performanceMetrics.cacheHits++; return _context4.a(2, cacheEntry.data); case 1: if (performanceConfig.enabled) performanceMetrics.cacheMisses++; // Check if there's already a pending request pendingKey = "".concat(endpoint, "-").concat(cacheKey); if (!pendingRequests.has(pendingKey)) { _context4.n = 2; break; } return _context4.a(2, pendingRequests.get(pendingKey)); case 2: // Create new request requestPromise = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() { var res, data, _t3; return _regenerator().w(function (_context3) { while (1) switch (_context3.n) { case 0: _context3.p = 0; _context3.n = 1; return fetchWithTimeout("".concat(API).concat(endpoint)); case 1: res = _context3.v; if (res.ok) { _context3.n = 2; break; } throw new Error("Network error while fetching ".concat(endpoint)); case 2: _context3.n = 3; return res.json(); case 3: data = _context3.v; // Update cache cache[cacheKey] = { data: data, timestamp: Date.now() }; return _context3.a(2, data); case 4: _context3.p = 4; _t3 = _context3.v; console.error("Error loading ".concat(endpoint, ":"), _t3); // Return cached data if available, even if expired if (!(cacheEntry !== null && cacheEntry !== void 0 && cacheEntry.data)) { _context3.n = 5; break; } return _context3.a(2, cacheEntry.data); case 5: return _context3.a(2, []); case 6: _context3.p = 6; // Clean up pending request pendingRequests.delete(pendingKey); return _context3.f(6); case 7: return _context3.a(2); } }, _callee3, null, [[0, 4, 6, 7]]); }))(); // Store pending request pendingRequests.set(pendingKey, requestPromise); return _context4.a(2, requestPromise); } }, _callee4); })); return _loadData.apply(this, arguments); } function loadRegions() { return _loadRegions.apply(this, arguments); } /** * Fetches province data for a given region code * @async * @param {string} regionCode - The region code * @returns {Promise<Array>} Array of province objects */ function _loadRegions() { _loadRegions = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() { var pendingKey, requestPromise; return _regenerator().w(function (_context6) { while (1) switch (_context6.n) { case 0: if (!(regionsCache.data && Date.now() - regionsCache.timestamp < config.cacheTTL)) { _context6.n = 1; break; } return _context6.a(2, regionsCache.data); case 1: pendingKey = 'regions'; if (!pendingRequests.has(pendingKey)) { _context6.n = 2; break; } return _context6.a(2, pendingRequests.get(pendingKey)); case 2: requestPromise = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5() { var res, data, _t4; return _regenerator().w(function (_context5) { while (1) switch (_context5.n) { case 0: _context5.p = 0; _context5.n = 1; return fetchWithTimeout("".concat(API, "/regions")); case 1: res = _context5.v; if (res.ok) { _context5.n = 2; break; } throw new Error("Network error while fetching regions"); case 2: _context5.n = 3; return res.json(); case 3: data = _context5.v; regionsCache = { data: data, timestamp: Date.now() }; return _context5.a(2, data); case 4: _context5.p = 4; _t4 = _context5.v; console.error("Error in loadRegions:", _t4); if (!regionsCache.data) { _context5.n = 5; break; } return _context5.a(2, regionsCache.data); case 5: return _context5.a(2, []); case 6: _context5.p = 6; pendingRequests.delete(pendingKey); return _context5.f(6); case 7: return _context5.a(2); } }, _callee5, null, [[0, 4, 6, 7]]); }))(); pendingRequests.set(pendingKey, requestPromise); return _context6.a(2, requestPromise); } }, _callee6); })); return _loadRegions.apply(this, arguments); } function loadProvinces(_x7) { return _loadProvinces.apply(this, arguments); } /** * Fetches cities data for a given province code * @async * @param {string} provCode - The province code * @returns {Promise<Array>} Array of city objects */ function _loadProvinces() { _loadProvinces = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee7(regionCode) { var cacheKey; return _regenerator().w(function (_context7) { while (1) switch (_context7.n) { case 0: if (!(typeof regionCode !== 'string' || !regionCode)) { _context7.n = 1; break; } console.error("Invalid region code"); return _context7.a(2, []); case 1: cacheKey = "provinces-".concat(regionCode); return _context7.a(2, loadData("/provinces/".concat(regionCode), provincesCache, cacheKey)); } }, _callee7); })); return _loadProvinces.apply(this, arguments); } function loadCities(_x8) { return _loadCities.apply(this, arguments); } /** * Fetches barangay data for a given city code * @async * @param {string} cityCode - The city code * @returns {Promise<Array>} Array of barangay objects */ function _loadCities() { _loadCities = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee8(provCode) { var cacheKey; return _regenerator().w(function (_context8) { while (1) switch (_context8.n) { case 0: if (!(typeof provCode !== 'string' || !provCode)) { _context8.n = 1; break; } console.error("Invalid province code"); return _context8.a(2, []); case 1: cacheKey = "cities-".concat(provCode); return _context8.a(2, loadData("/cities/".concat(provCode), citiesCache, cacheKey)); } }, _callee8); })); return _loadCities.apply(this, arguments); } function loadBarangays(_x9) { return _loadBarangays.apply(this, arguments); } // --------------------------------------------------------------------- // Helper Functions // --------------------------------------------------------------------- /** * Constructs a full address string from address parts * @param {Object} address - Address components * @param {string} [address.region] - Region name * @param {string} [address.province] - Province name * @param {string} [address.city] - City name * @param {string} [address.barangay] - Barangay name * @param {string} [address.street] - Street address * @param {string} [address.zipCode] - ZIP code * @returns {string} Full address string */ function _loadBarangays() { _loadBarangays = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee9(cityCode) { var cacheKey; return _regenerator().w(function (_context9) { while (1) switch (_context9.n) { case 0: if (!(typeof cityCode !== 'string' || !cityCode)) { _context9.n = 1; break; } console.error("Invalid city code"); return _context9.a(2, []); case 1: cacheKey = "barangays-".concat(cityCode); return _context9.a(2, loadData("/barangays/".concat(cityCode), barangaysCache, cacheKey)); } }, _callee9); })); return _loadBarangays.apply(this, arguments); } function constructAddress(address) { var parts = [address.street, address.barangay, address.city, address.province, address.region, address.zipCode].filter(Boolean); return parts.join(', '); } /** * Searches for a location by name across all levels * @param {string} query - Search query * @param {Object} [options] - Search options * @param {boolean} [options.includeRegions=true] - Include regions in search * @param {boolean} [options.includeProvinces=true] - Include provinces in search * @param {boolean} [options.includeCities=true] - Include cities in search * @param {boolean} [options.includeBarangays=false] - Include barangays in search * @param {number} [options.limit=10] - Maximum results to return * @returns {Promise<Array>} Search results */ function search(_x0) { return _search.apply(this, arguments); } /** * Clears all cached data */ function _search() { _search = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee0(query) { var options, _options$includeRegio, includeRegions, _options$includeProvi, includeProvinces, _options$includeCitie, includeCities, _options$limit, limit, normalizedQuery, results, regionsData, regionMatches, _regionsData, _iterator, _step, _loop, _args10 = arguments, _t6, _t7; return _regenerator().w(function (_context10) { while (1) switch (_context10.n) { case 0: options = _args10.length > 1 && _args10[1] !== undefined ? _args10[1] : {}; _options$includeRegio = options.includeRegions, includeRegions = _options$includeRegio === void 0 ? true : _options$includeRegio, _options$includeProvi = options.includeProvinces, includeProvinces = _options$includeProvi === void 0 ? true : _options$includeProvi, _options$includeCitie = options.includeCities, includeCities = _options$includeCitie === void 0 ? true : _options$includeCitie, options.includeBarangays, _options$limit = options.limit, limit = _options$limit === void 0 ? 10 : _options$limit; if (!(!query || typeof query !== 'string')) { _context10.n = 1; break; } return _context10.a(2, []); case 1: normalizedQuery = query.toLowerCase().trim(); results = []; _context10.p = 2; if (!includeRegions) { _context10.n = 4; break; } _context10.n = 3; return loadRegions(); case 3: regionsData = _context10.v; regionMatches = regionsData.filter(function (r) { return r.name.toLowerCase().includes(normalizedQuery); }).map(function (r) { return _objectSpread2(_objectSpread2({}, r), {}, { type: 'region' }); }); results.push.apply(results, _toConsumableArray(regionMatches)); case 4: if (!(includeProvinces || includeCities)) { _context10.n = 13; break; } _context10.n = 5; return loadRegions(); case 5: _regionsData = _context10.v; _iterator = _createForOfIteratorHelper(_regionsData); _context10.p = 6; _loop = /*#__PURE__*/_regenerator().m(function _loop() { var region, provincesData, provinceMatches, _provincesData, _iterator2, _step2, _loop2, _t5; return _regenerator().w(function (_context1) { while (1) switch (_context1.n) { case 0: region = _step.value; if (!(results.length >= limit)) { _context1.n = 1; break; } return _context1.a(2, 1); case 1: if (!includeProvinces) { _context1.n = 3; break; } _context1.n = 2; return loadProvinces(region.psgcCode); case 2: provincesData = _context1.v; provinceMatches = provincesData.filter(function (p) { return p.name.toLowerCase().includes(normalizedQuery); }).map(function (p) { return _objectSpread2(_objectSpread2({}, p), {}, { type: 'province', regionName: region.name }); }); results.push.apply(results, _toConsumableArray(provinceMatches)); case 3: if (!(includeCities && results.length < limit)) { _context1.n = 12; break; } _context1.n = 4; return loadProvinces(region.psgcCode); case 4: _provincesData = _context1.v; _iterator2 = _createForOfIteratorHelper(_provincesData); _context1.p = 5; _loop2 = /*#__PURE__*/_regenerator().m(function _loop2() { var province, citiesData, cityMatches; return _regenerator().w(function (_context0) { while (1) switch (_context0.n) { case 0: province = _step2.value; if (!(results.length >= limit)) { _context0.n = 1; break; } return _context0.a(2, 1); case 1: _context0.n = 2; return loadCities(province.id); case 2: citiesData = _context0.v; cityMatches = citiesData.filter(function (c) { return c.name.toLowerCase().includes(normalizedQuery); }).map(function (c) { return _objectSpread2(_objectSpread2({}, c), {}, { type: 'city', provinceName: province.name, regionName: region.name }); }); results.push.apply(results, _toConsumableArray(cityMatches)); case 3: return _context0.a(2); } }, _loop2); }); _iterator2.s(); case 6: if ((_step2 = _iterator2.n()).done) { _context1.n = 9; break; } return _context1.d(_regeneratorValues(_loop2()), 7); case 7: if (!_context1.v) { _context1.n = 8; break; } return _context1.a(3, 9); case 8: _context1.n = 6; break; case 9: _context1.n = 11; break; case 10: _context1.p = 10; _t5 = _context1.v; _iterator2.e(_t5); case 11: _context1.p = 11; _iterator2.f(); return _context1.f(11); case 12: return _context1.a(2); } }, _loop, null, [[5, 10, 11, 12]]); }); _iterator.s(); case 7: if ((_step = _iterator.n()).done) { _context10.n = 10; break; } return _context10.d(_regeneratorValues(_loop()), 8); case 8: if (!_context10.v) { _context10.n = 9; break; } return _context10.a(3, 10); case 9: _context10.n = 7; break; case 10: _context10.n = 12; break; case 11: _context10.p = 11; _t6 = _context10.v; _iterator.e(_t6); case 12: _context10.p = 12; _iterator.f(); return _context10.f(12); case 13: return _context10.a(2, results.slice(0, limit)); case 14: _context10.p = 14; _t7 = _context10.v; console.error('Error in search:', _t7); return _context10.a(2, []); } }, _callee0, null, [[6, 11, 12, 13], [2, 14]]); })); return _search.apply(this, arguments); } function clearCache() { regionsCache = { data: null, timestamp: 0 }; Object.keys(provincesCache).forEach(function (key) { return delete provincesCache[key]; }); Object.keys(citiesCache).forEach(function (key) { return delete citiesCache[key]; }); Object.keys(barangaysCache).forEach(function (key) { return delete barangaysCache[key]; }); pendingRequests.clear(); } /** * Gets cache statistics * @returns {Object} Cache statistics */ function getCacheStats() { var countCache = function countCache(cache) { return Object.keys(cache).length; }; return { regions: regionsCache.data ? 1 : 0, provinces: countCache(provincesCache), cities: countCache(citiesCache), barangays: countCache(barangaysCache), pendingRequests: pendingRequests.size, totalCached: (regionsCache.data ? 1 : 0) + countCache(provincesCache) + countCache(citiesCache) + countCache(barangaysCache) }; } // --------------------------------------------------------------------- // Public API Exports // --------------------------------------------------------------------- /** * Fetches all regions * @returns {Promise<Array>} Array of regions */ function regions() { return _regions.apply(this, arguments); } /** * Fetches provinces for a given region * @param {string} regionCode - Region code * @returns {Promise<Array>} Array of provinces */ function _regions() { _regions = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee1() { return _regenerator().w(function (_context11) { while (1) switch (_context11.n) { case 0: return _context11.a(2, loadRegions()); } }, _callee1); })); return _regions.apply(this, arguments); } function provinces(_x1) { return _provinces.apply(this, arguments); } /** * Fetches cities for a given province * @param {string} provCode - Province code * @returns {Promise<Array>} Array of cities */ function _provinces() { _provinces = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee10(regionCode) { return _regenerator().w(function (_context12) { while (1) switch (_context12.n) { case 0: return _context12.a(2, loadProvinces(regionCode)); } }, _callee10); })); return _provinces.apply(this, arguments); } function cities(_x10) { return _cities.apply(this, arguments); } /** * Fetches barangays for a given city * @param {string} cityCode - City code * @returns {Promise<Array>} Array of barangays */ function _cities() { _cities = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee11(provCode) { return _regenerator().w(function (_context13) { while (1) switch (_context13.n) { case 0: return _context13.a(2, loadCities(provCode)); } }, _callee11); })); return _cities.apply(this, arguments); } function barangays(_x11) { return _barangays.apply(this, arguments); } /** * Get region by code * @param {string} regionCode - Region code * @returns {Promise<Object|null>} Region object or null */ function _barangays() { _barangays = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee12(cityCode) { return _regenerator().w(function (_context14) { while (1) switch (_context14.n) { case 0: return _context14.a(2, loadBarangays(cityCode)); } }, _callee12); })); return _barangays.apply(this, arguments); } function getRegionByCode(_x12) { return _getRegionByCode.apply(this, arguments); } /** * Get province by code * @param {string} provinceCode - Province code * @returns {Promise<Object|null>} Province object with region info or null */ function _getRegionByCode() { _getRegionByCode = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee13(regionCode) { var regionsData; return _regenerator().w(function (_context15) { while (1) switch (_context15.n) { case 0: _context15.n = 1; return regions(); case 1: regionsData = _context15.v; return _context15.a(2, regionsData.find(function (r) { return r.psgcCode === regionCode; }) || null); } }, _callee13); })); return _getRegionByCode.apply(this, arguments); } function getProvinceByCode(_x13) { return _getProvinceByCode.apply(this, arguments); } /** * Get full address hierarchy by barangay code * @param {string} barangayCode - Barangay code * @returns {Promise<Object|null>} Complete address hierarchy */ function _getProvinceByCode() { _getProvinceByCode = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee14(provinceCode) { var regionsData, _iterator3, _step3, region, provincesData, province, _t8; return _regenerator().w(function (_context16) { while (1) switch (_context16.n) { case 0: _context16.n = 1; return regions(); case 1: regionsData = _context16.v; _iterator3 = _createForOfIteratorHelper(regionsData); _context16.p = 2; _iterator3.s(); case 3: if ((_step3 = _iterator3.n()).done) { _context16.n = 6; break; } region = _step3.value; _context16.n = 4; return provinces(region.psgcCode); case 4: provincesData = _context16.v; province = provincesData.find(function (p) { return p.psgcCode === provinceCode; }); if (!province) { _context16.n = 5; break; } return _context16.a(2, _objectSpread2(_objectSpread2({}, province), {}, { region: region })); case 5: _context16.n = 3; break; case 6: _context16.n = 8; break; case 7: _context16.p = 7; _t8 = _context16.v; _iterator3.e(_t8); case 8: _context16.p = 8; _iterator3.f(); return _context16.f(8); case 9: return _context16.a(2, null); } }, _callee14, null, [[2, 7, 8, 9]]); })); return _getProvinceByCode.apply(this, arguments); } function getAddressHierarchy(_x14) { return _getAddressHierarchy.apply(this, arguments); } /** * Validate Philippine ZIP code * @param {string} zipCode - ZIP code to validate * @returns {boolean} Whether the ZIP code is valid */ function _getAddressHierarchy() { _getAddressHierarchy = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee15(barangayCode) { var regionCode, provinceCode, cityCode, _yield$Promise$all, _yield$Promise$all2, regionsData, provincesData, citiesData, barangaysData, region, province, city, barangay, _t9; return _regenerator().w(function (_context17) { while (1) switch (_context17.n) { case 0: if (!(!barangayCode || barangayCode.length < 9)) { _context17.n = 1; break; } return _context17.a(2, null); case 1: regionCode = barangayCode.substring(0, 2); provinceCode = barangayCode.substring(0, 4); cityCode = barangayCode.substring(0, 6); _context17.p = 2; _context17.n = 3; return Promise.all([regions(), provinces(regionCode), cities(provinceCode), barangays(cityCode)]); case 3: _yield$Promise$all = _context17.v; _yield$Promise$all2 = _slicedToArray(_yield$Promise$all, 4); regionsData = _yield$Promise$all2[0]; provincesData = _yield$Promise$all2[1]; citiesData = _yield$Promise$all2[2]; barangaysData = _yield$Promise$all2[3]; region = regionsData.find(function (r) { return r.psgcCode === regionCode; }); province = provincesData.find(function (p) { return p.id === provinceCode; }); city = citiesData.find(function (c) { return c.id === cityCode; }); barangay = barangaysData.find(function (b) { return b.id === barangayCode; }); if (!(!region || !province || !city || !barangay)) { _context17.n = 4; break; } return _context17.a(2, null); case 4: return _context17.a(2, { region: region, province: province, city: city, barangay: barangay, fullAddress: constructAddress({ barangay: barangay.name, city: city.name, province: province.name, region: region.name }) }); case 5: _context17.p = 5; _t9 = _context17.v; console.error('Error getting address hierarchy:', _t9); return _context17.a(2, null); } }, _callee15, null, [[2, 5]]); })); return _getAddressHierarchy.apply(this, arguments); } function isValidZipCode(zipCode) { // Philippine ZIP codes are 4 digits return /^\d{4}$/.test(zipCode); } /** * Get all provinces grouped by region * @returns {Promise<Object>} Provinces grouped by region */ function getProvincesGroupedByRegion() { return _getProvincesGroupedByRegion.apply(this, arguments); } /** * Fuzzy search with scoring * @param {string} query - Search query * @param {Object} options - Search options * @returns {Promise<Array>} Search results with scores */ function _getProvincesGroupedByRegion() { _getProvincesGroupedByRegion = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee17() { var regionsData, grouped; return _regenerator().w(function (_context19) { while (1) switch (_context19.n) { case 0: _context19.n = 1; return regions(); case 1: regionsData = _context19.v; grouped = {}; _context19.n = 2; return Promise.all(regionsData.map(/*#__PURE__*/function () { var _ref3 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee16(region) { var provincesData; return _regenerator().w(function (_context18) { while (1) switch (_context18.n) { case 0: _context18.n = 1; return provinces(region.psgcCode); case 1: provincesData = _context18.v; grouped[region.name] = { code: region.psgcCode, provinces: provincesData }; case 2: return _context18.a(2); } }, _callee16); })); return function (_x16) { return _ref3.apply(this, arguments); }; }())); case 2: return _context19.a(2, grouped); } }, _callee17); })); return _getProvincesGroupedByRegion.apply(this, arguments); } function fuzzySearch(_x15) { return _fuzzySearch.apply(this, arguments); } /** * Calculate string similarity (Levenshtein distance based) * @private */ function _fuzzySearch() { _fuzzySearch = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee18(query) { var options, results, _args20 = arguments; return _regenerator().w(function (_context20) { while (1) switch (_context20.n) { case 0: options = _args20.length > 1 && _args20[1] !== undefined ? _args20[1] : {}; _context20.n = 1; return search(query, options); case 1: results = _context20.v; return _context20.a(2, results.map(function (result) { var name = result.name.toLowerCase(); var searchQuery = query.toLowerCase(); var score = 0; if (name === searchQuery) { score = 100; // Exact match } else if (name.startsWith(searchQuery)) { score = 90; // Starts with query } else if (name.includes(searchQuery)) { score = 70; // Contains query } else { // Calculate similarity score score = calculateSimilarity(name, searchQuery); } return _objectSpread2(_objectSpread2({}, result), {}, { score: score }); }).sort(function (a, b) { return b.score - a.score; })); } }, _callee18); })); return _fuzzySearch.apply(this, arguments); } function calculateSimilarity(str1, str2) { var longer = str1.length > str2.length ? str1 : str2; var shorter = str1.length > str2.length ? str2 : str1; if (longer.length === 0) return 100; var editDistance = levenshteinDistance(longer, shorter); return Math.round((longer.length - editDistance) / longer.length * 100); } /** * Levenshtein distance algorithm * @private */ function levenshteinDistance(str1, str2) { var matrix = []; for (var i = 0; i <= str2.length; i++) { matrix[i] = [i]; } for (var j = 0; j <= str1.length; j++) { matrix[0][j] = j; } for (var _i = 1; _i <= str2.length; _i++) { for (var _j = 1; _j <= str1.length; _j++) { if (str2.charAt(_i - 1) === str1.charAt(_j - 1)) { matrix[_i][_j] = matrix[_i - 1][_j - 1]; } else { matrix[_i][_j] = Math.min(matrix[_i - 1][_j - 1] + 1, matrix[_i][_j - 1] + 1, matrix[_i - 1][_j] + 1); } } } return matrix[str2.length][str1.length]; } // Default export for convenience var index = { regions: regions, provinces: provinces, cities: cities, barangays: barangays, constructAddress: constructAddress, search: search, configure: configure, clearCache: clearCache, getCacheStats: getCacheStats, getRegionByCode: getRegionByCode, getProvinceByCode: getProvinceByCode, getAddressHierarchy: getAddressHierarchy, isValidZipCode: isValidZipCode, getProvincesGroupedByRegion: getProvincesGroupedByRegion, fuzzySearch: fuzzySearch, configurePerformanceMonitoring: configurePerformanceMonitoring, getPerformanceMetrics: getPerformanceMetrics, resetPerformanceMetrics: resetPerformanceMetrics }; export { barangays, cities, clearCache, configure, configurePerformanceMonitoring, constructAddress, index as default, fuzzySearch, getAddressHierarchy, getCacheStats, getPerformanceMetrics, getProvinceByCode, getProvincesGroupedByRegion, getRegionByCode, isValidZipCode, provinces, regions, resetPerformanceMetrics, search }; //# sourceMappingURL=index.esm.js.map