@archerjessop/utilities 7.18.0 → 7.19.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.
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function extractPhoneNumber(){const t
|
|
1
|
+
function extractPhoneNumber(){const t=/(\+?1?\s*\(?[0-9]{3}\)?[\s.-]*[0-9]{3}[\s.-]*[0-9]{4})/,e=document.querySelector("a[href^='tel:']");if(e&&e.href){const o=decodeURIComponent(e.href.replace(/^tel:/,"")).trim();if(t.test(o))return o}for(const e of[".phone-number",".number","[class*='phone']"]){const o=document.querySelector(e);if(!o)continue;const r=(o.textContent||"").match(t);if(r)return r[1].trim();if(o.href){const e=decodeURIComponent(o.href.replace(/^tel:/,"")).trim();if(t.test(e))return e}}const o=(document.body&&document.body.textContent||"").match(t);return o?o[1].trim():"Not found"}function extractBedrooms(){try{const t=document.body?.textContent||"",e=[/(\d+)\s*bed/i,/(\d+)\s*bedroom/i,/beds?\s*:\s*(\d+)/i,/bedrooms?\s*:\s*(\d+)/i,/(\d+)\s*BR/i,/(\d+)br/i];for(const o of e){const e=t.match(o);if(e){const t=parseInt(e[1]);if(t>0&&t<100)return t}}const o=document.querySelector(".property-details")||document.querySelector("#PropertyDetails")||document.querySelector(".details");if(o){const t=o.textContent||"";for(const o of e){const e=t.match(o);if(e){const t=parseInt(e[1]);if(t>0&&t<100)return t}}}return 10}catch(t){return 10}}export{extractBedrooms,extractPhoneNumber};
|
|
2
2
|
//# sourceMappingURL=extractors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractors.js","sources":["../../../src/browser/data/extractors.js"],"sourcesContent":["export function extractPhoneNumber() {\r\n const
|
|
1
|
+
{"version":3,"file":"extractors.js","sources":["../../../src/browser/data/extractors.js"],"sourcesContent":["export function extractPhoneNumber() {\r\n const PHONE_RE = /(\\+?1?\\s*\\(?[0-9]{3}\\)?[\\s.-]*[0-9]{3}[\\s.-]*[0-9]{4})/;\r\n\r\n // A tel: link is unambiguous — prefer it. Its href holds the real number even when the\r\n // visible text is a label (\"Call\") or, on LoopNet, a lead-form validation message.\r\n const telLink = document.querySelector(\"a[href^='tel:']\");\r\n if (telLink && telLink.href) {\r\n const num = decodeURIComponent(telLink.href.replace(/^tel:/, \"\")).trim();\r\n if (PHONE_RE.test(num)) return num;\r\n }\r\n\r\n // Other phone-ish elements, but accept their TEXT only if it actually looks like a phone —\r\n // guards against lead-capture form fields (class*=\"phone\") whose text is a label/validation\r\n // message (\"Phone* Valid phone number is required\"), not a number.\r\n for (const sel of [\".phone-number\", \".number\", \"[class*='phone']\"]) {\r\n const el = document.querySelector(sel);\r\n if (!el) continue;\r\n const m = (el.textContent || \"\").match(PHONE_RE);\r\n if (m) return m[1].trim();\r\n if (el.href) {\r\n const num = decodeURIComponent(el.href.replace(/^tel:/, \"\")).trim();\r\n if (PHONE_RE.test(num)) return num;\r\n }\r\n }\r\n\r\n // Fallback to a body-text scan.\r\n const pageText = document.body ? document.body.textContent || \"\" : \"\";\r\n const phoneMatch = pageText.match(PHONE_RE);\r\n if (phoneMatch) {\r\n return phoneMatch[1].trim();\r\n }\r\n\r\n return \"Not found\";\r\n}\r\n\r\nexport function extractBedrooms() {\r\n try {\r\n // Look for bedroom information in various places\r\n const bodyText = document.body?.textContent || \"\";\r\n\r\n // Common patterns for bedroom information\r\n const bedroomPatterns = [\r\n /(\\d+)\\s*bed/i,\r\n /(\\d+)\\s*bedroom/i,\r\n /beds?\\s*:\\s*(\\d+)/i,\r\n /bedrooms?\\s*:\\s*(\\d+)/i,\r\n /(\\d+)\\s*BR/i,\r\n /(\\d+)br/i\r\n ];\r\n\r\n for (const pattern of bedroomPatterns) {\r\n const match = bodyText.match(pattern);\r\n if (match) {\r\n const bedrooms = parseInt(match[1]);\r\n if (bedrooms > 0 && bedrooms < 100) { // Sanity check\r\n return bedrooms;\r\n }\r\n }\r\n }\r\n\r\n // Look in property details section specifically\r\n const propertyDetails = document.querySelector(\".property-details\") ||\r\n document.querySelector(\"#PropertyDetails\") ||\r\n document.querySelector(\".details\");\r\n\r\n if (propertyDetails) {\r\n const detailsText = propertyDetails.textContent || \"\";\r\n for (const pattern of bedroomPatterns) {\r\n const match = detailsText.match(pattern);\r\n if (match) {\r\n const bedrooms = parseInt(match[1]);\r\n if (bedrooms > 0 && bedrooms < 100) {\r\n return bedrooms;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Default fallback\r\n return 10; // Default assumption for assisted living\r\n } catch (error) {\r\n return 10; // Default fallback\r\n }\r\n}\r\n"],"names":["extractPhoneNumber","PHONE_RE","telLink","document","querySelector","href","num","decodeURIComponent","replace","trim","test","sel","el","m","textContent","match","phoneMatch","body","extractBedrooms","bodyText","bedroomPatterns","pattern","bedrooms","parseInt","propertyDetails","detailsText","error"],"mappings":"AAAO,SAASA,qBACd,MAAMC,EAAW,yDAIXC,EAAUC,SAASC,cAAc,mBACvC,GAAIF,GAAWA,EAAQG,KAAM,CAC3B,MAAMC,EAAMC,mBAAmBL,EAAQG,KAAKG,QAAQ,QAAS,KAAKC,OAClE,GAAIR,EAASS,KAAKJ,GAAM,OAAOA,CACjC,CAKA,IAAK,MAAMK,IAAO,CAAC,gBAAiB,UAAW,oBAAqB,CAClE,MAAMC,EAAKT,SAASC,cAAcO,GAClC,IAAKC,EAAI,SACT,MAAMC,GAAKD,EAAGE,aAAe,IAAIC,MAAMd,GACvC,GAAIY,EAAG,OAAOA,EAAE,GAAGJ,OACnB,GAAIG,EAAGP,KAAM,CACX,MAAMC,EAAMC,mBAAmBK,EAAGP,KAAKG,QAAQ,QAAS,KAAKC,OAC7D,GAAIR,EAASS,KAAKJ,GAAM,OAAOA,CACjC,CACF,CAGA,MACMU,GADWb,SAASc,MAAOd,SAASc,KAAKH,aAAoB,IACvCC,MAAMd,GAClC,OAAIe,EACKA,EAAW,GAAGP,OAGhB,WACT,CAEO,SAASS,kBACd,IAEE,MAAMC,EAAWhB,SAASc,MAAMH,aAAe,GAGzCM,EAAkB,CACtB,eACA,mBACA,qBACA,yBACA,cACA,YAGF,IAAK,MAAMC,KAAWD,EAAiB,CACrC,MAAML,EAAQI,EAASJ,MAAMM,GAC7B,GAAIN,EAAO,CACT,MAAMO,EAAWC,SAASR,EAAM,IAChC,GAAIO,EAAW,GAAKA,EAAW,IAC7B,OAAOA,CAEX,CACF,CAGA,MAAME,EAAkBrB,SAASC,cAAc,sBACxBD,SAASC,cAAc,qBACvBD,SAASC,cAAc,YAE9C,GAAIoB,EAAiB,CACnB,MAAMC,EAAcD,EAAgBV,aAAe,GACnD,IAAK,MAAMO,KAAWD,EAAiB,CACrC,MAAML,EAAQU,EAAYV,MAAMM,GAChC,GAAIN,EAAO,CACT,MAAMO,EAAWC,SAASR,EAAM,IAChC,GAAIO,EAAW,GAAKA,EAAW,IAC7B,OAAOA,CAEX,CACF,CACF,CAGA,OAAO,EACT,CAAE,MAAOI,GACP,OAAO,EACT,CACF"}
|
package/dist/services/debt.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
async function fetchDebt(e,{baseUrl:t="https://api.archerjessop.com"}={}){const a=await fetch(`${t}/debt?address=${encodeURIComponent(e)}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!a.ok)throw new Error(`HTTP error! status: ${a.status}`);const r=await a.json(),s="number"==typeof r.estimatedMortgageBalance&&Number.isFinite(r.estimatedMortgageBalance)?r.estimatedMortgageBalance:null;return{address:"string"==typeof r.address?r.address:e,currentMortgages:Array.isArray(r.currentMortgages)?r.currentMortgages:[],estimatedMortgageBalance:s,source:null===s?"estimated":"api"}}export{fetchDebt};
|
|
1
|
+
async function fetchDebt(e,{baseUrl:t="https://api.archerjessop.com"}={}){const a=await fetch(`${t}/debt?address=${encodeURIComponent(e)}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(404===a.status)return{address:e,currentMortgages:[],estimatedMortgageBalance:null,source:"estimated"};if(!a.ok)throw new Error(`HTTP error! status: ${a.status}`);const r=await a.json(),s="number"==typeof r.estimatedMortgageBalance&&Number.isFinite(r.estimatedMortgageBalance)?r.estimatedMortgageBalance:null;return{address:"string"==typeof r.address?r.address:e,currentMortgages:Array.isArray(r.currentMortgages)?r.currentMortgages:[],estimatedMortgageBalance:s,source:null===s?"estimated":"api"}}export{fetchDebt};
|
|
2
2
|
//# sourceMappingURL=debt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debt.js","sources":["../../src/services/debt.js"],"sourcesContent":["// Agnostic debt fetcher: receives an address, returns the property's outstanding debt.\n//\n// PURE IO — no per-repo state, no panel DOM, no caching. Works in both Node (the dashboard\n// add-by-address flow) and the browser (the analyzer engine). The caller owns caching, the\n// loading indicator, the equity computation, and the \"estimated = 100%\" fallback.\n//\n// Returns { address, estimatedMortgageBalance, currentMortgages, source }:\n// - estimatedMortgageBalance: number (debt owing) or null when the service has no figure\n// - currentMortgages: array of lien objects (amount, position, lenderName, loanType, ...)\n// - source: \"api\" when a numeric balance came back, \"estimated\" when it did not\n// Throws on a network / non-OK HTTP error so the caller can
|
|
1
|
+
{"version":3,"file":"debt.js","sources":["../../src/services/debt.js"],"sourcesContent":["// Agnostic debt fetcher: receives an address, returns the property's outstanding debt.\n//\n// PURE IO — no per-repo state, no panel DOM, no caching. Works in both Node (the dashboard\n// add-by-address flow) and the browser (the analyzer engine). The caller owns caching, the\n// loading indicator, the equity computation, and the \"estimated = 100%\" fallback.\n//\n// Returns { address, estimatedMortgageBalance, currentMortgages, source }:\n// - estimatedMortgageBalance: number (debt owing) or null when the service has no figure\n// - currentMortgages: array of lien objects (amount, position, lenderName, loanType, ...)\n// - source: \"api\" when a numeric balance came back, \"estimated\" when it did not\n// A 404 means the service definitively has no debt record for the address — returned as the\n// estimated case (not thrown). Throws on a genuine network / non-OK HTTP error (e.g. 500) so\n// the caller can log it and still fall back to the estimated case.\nexport async function fetchDebt(address, { baseUrl = \"https://api.archerjessop.com\" } = {}) {\n const response = await fetch(\n `${baseUrl}/debt?address=${encodeURIComponent(address)}`,\n { method: \"GET\", headers: { \"Content-Type\": \"application/json\" } }\n );\n\n if (response.status === 404) {\n return {\n address,\n currentMortgages: [],\n estimatedMortgageBalance: null,\n source: \"estimated\",\n };\n }\n\n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n const data = await response.json();\n\n const balance = typeof data.estimatedMortgageBalance === \"number\" && Number.isFinite(data.estimatedMortgageBalance)\n ? data.estimatedMortgageBalance\n : null;\n\n return {\n address: typeof data.address === \"string\" ? data.address : address,\n currentMortgages: Array.isArray(data.currentMortgages) ? data.currentMortgages : [],\n estimatedMortgageBalance: balance,\n source: balance === null ? \"estimated\" : \"api\",\n };\n}\n"],"names":["async","fetchDebt","address","baseUrl","response","fetch","encodeURIComponent","method","headers","status","currentMortgages","estimatedMortgageBalance","source","ok","Error","data","json","balance","Number","isFinite","Array","isArray"],"mappings":"AAaOA,eAAeC,UAAUC,GAASC,QAAEA,EAAU,gCAAmC,CAAA,GACtF,MAAMC,QAAiBC,MACrB,GAAGF,kBAAwBG,mBAAmBJ,KAC9C,CAAEK,OAAQ,MAAOC,QAAS,CAAE,eAAgB,sBAG9C,GAAwB,MAApBJ,EAASK,OACX,MAAO,CACLP,UACAQ,iBAAkB,GAClBC,yBAA0B,KAC1BC,OAAQ,aAIZ,IAAKR,EAASS,GACZ,MAAM,IAAIC,MAAM,uBAAuBV,EAASK,UAGlD,MAAMM,QAAaX,EAASY,OAEtBC,EAAmD,iBAAlCF,EAAKJ,0BAAyCO,OAAOC,SAASJ,EAAKJ,0BACtFI,EAAKJ,yBACL,KAEJ,MAAO,CACLT,QAAiC,iBAAjBa,EAAKb,QAAuBa,EAAKb,QAAUA,EAC3DQ,iBAAkBU,MAAMC,QAAQN,EAAKL,kBAAoBK,EAAKL,iBAAmB,GACjFC,yBAA0BM,EAC1BL,OAAoB,OAAZK,EAAmB,YAAc,MAE7C"}
|