← back to Commercialrealestate
chore: lint, refactor (shared normalizeCrexiId), v0.26.1 (session close TK-12033)
5ddda1e259ae837eb9d837f3e24bd88a2812b71b · 2026-09-23 12:44:11 -0700 · Steve Abrams
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Files touched
M package-lock.jsonM package.jsonM scripts/refresh-listings-multi.jsM scripts/sources/firms.js
Diff
commit 5ddda1e259ae837eb9d837f3e24bd88a2812b71b
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Sep 23 12:44:11 2026 -0700
chore: lint, refactor (shared normalizeCrexiId), v0.26.1 (session close TK-12033)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---
package-lock.json | 4 ++--
package.json | 2 +-
scripts/refresh-listings-multi.js | 4 ++--
scripts/sources/firms.js | 9 ++++++---
4 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index fee7b5e..c339a6e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "commercialrealestate",
- "version": "0.26.0",
+ "version": "0.26.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "commercialrealestate",
- "version": "0.26.0",
+ "version": "0.26.1",
"dependencies": {
"better-sqlite3": "^12.11.1",
"express": "^4.22.2",
diff --git a/package.json b/package.json
index cad439f..c9d0caf 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "commercialrealestate",
- "version": "0.26.0",
+ "version": "0.26.1",
"private": true,
"description": "LA County CRE investment explorer — multi-firm sourced, Census + assessor enriched, Qwen-analyzed",
"scripts": {
diff --git a/scripts/refresh-listings-multi.js b/scripts/refresh-listings-multi.js
index 1403932..cb843b1 100644
--- a/scripts/refresh-listings-multi.js
+++ b/scripts/refresh-listings-multi.js
@@ -14,6 +14,7 @@
const fs = require('fs');
const path = require('path');
const { chromium } = require('playwright-core');
+const { normalizeCrexiId } = require('./sources/firms');
const ROOT = path.join(__dirname, '..');
const CFG = JSON.parse(fs.readFileSync(path.join(ROOT, 'data', 'metro-listings-config.json'), 'utf8'));
@@ -61,8 +62,7 @@ async function makeBrowser() {
: (a.address && typeof a.address === 'object' ? a.address : ((a.locations && a.locations[0]) || {}));
const st = String(loc.stateCode || loc.state || loc.stateName || '').toUpperCase();
if (st && st !== 'CA' && st !== 'CALIFORNIA') continue;
- const rawId = a.id || a.assetId; // "sales-N" -> "N" (canonical detail URL + crxN id namespace, TK-12033)
- const id = rawId == null ? null : String(rawId).replace(/^(?:sales|lease|auction)-/i, "");
+ const id = normalizeCrexiId(a.id || a.assetId); // "sales-N" -> "N" (canonical detail URL + crxN id namespace, TK-12033)
const price = (a.propertyPrice && a.propertyPrice.total) || a.askingPrice || a.price;
const city = loc.city || loc.cityName;
const address = loc.streetAddress || loc.address || loc.fullAddress || a.propertyName || a.name || '';
diff --git a/scripts/sources/firms.js b/scripts/sources/firms.js
index 86ba78f..301344c 100644
--- a/scripts/sources/firms.js
+++ b/scripts/sources/firms.js
@@ -110,6 +110,10 @@ function genericExtract(json) {
return out;
}
+// Crexi v2 ids arrive as "sales-2066415" / "lease-…"; the canonical detail URL and our historical crxN ids use the
+// bare number. Shared by crexiExtract (this file) and the paid-path inline extractor in refresh-listings-multi.js.
+function normalizeCrexiId(raw) { return raw == null ? null : String(raw).replace(/^(?:sales|lease|auction)-/i, ""); }
+
// Crexi's verified extractor — its API matches genericExtract anyway, but we keep it explicit so the
// reference source is never silently changed by a heuristic tweak.
function crexiExtract(json) {
@@ -131,8 +135,7 @@ function crexiExtract(json) {
// v2 ids arrive as "sales-2066415" / "lease-…" but the canonical detail URL (and our historical crxN ids)
// use the bare number — /properties/2066415/<urlSlug>. Keeping the prefix 302s to a dead "brokerage search"
// page, forks the id namespace, and fails crcp-scope.js isCalifornia() closed (TK-12033).
- const rawId = a.id || a.assetId;
- const id = rawId == null ? null : String(rawId).replace(/^(?:sales|lease|auction)-/i, "");
+ const id = normalizeCrexiId(a.id || a.assetId);
const price = (a.propertyPrice && a.propertyPrice.total) || a.askingPrice || a.price;
const city = loc.city || loc.cityName;
const address = loc.streetAddress || loc.address || loc.fullAddress || a.propertyName || a.name || '';
@@ -296,4 +299,4 @@ function toListing(a, firm) {
// Apply the SFV + price-band + plausibility gate to a batch of intermediate assets.
const inBand = (a) => a && a.city && SFV.has(a.city.toLowerCase()) && a.price >= MINP && a.price <= MAXP && a.address;
-module.exports = { SFV, MINP, MAXP, TYPES, norm, today, FIRMS, byKey, genericExtract, toListing, inBand };
+module.exports = { SFV, MINP, MAXP, TYPES, norm, today, FIRMS, byKey, genericExtract, toListing, inBand, normalizeCrexiId };
← 0aa4c7e auto-data-snapshot: 2026-09-23T12:42:16 (8 data files) — dat
·
back to Commercialrealestate
·
afternoon CRE update 2026-09-23 0cc031f →