open-local-audit 0.76.0 → 0.78.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 (50) hide show
  1. package/CHANGELOG.md +518 -497
  2. package/LICENSE +21 -21
  3. package/README.md +543 -538
  4. package/dist/audit.d.ts +2 -0
  5. package/dist/audit.js +13 -0
  6. package/dist/audit.js.map +1 -1
  7. package/dist/cli.js +37 -12
  8. package/dist/cli.js.map +1 -1
  9. package/dist/compare.d.ts +17 -1
  10. package/dist/compare.js +170 -6
  11. package/dist/compare.js.map +1 -1
  12. package/dist/contact.d.ts +7 -0
  13. package/dist/contact.js +106 -2
  14. package/dist/contact.js.map +1 -1
  15. package/dist/discovery.d.ts +1 -0
  16. package/dist/discovery.js +92 -6
  17. package/dist/discovery.js.map +1 -1
  18. package/dist/index.d.ts +4 -2
  19. package/dist/index.js +2 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/local-business-types.d.ts +16 -0
  22. package/dist/local-business-types.js +324 -0
  23. package/dist/local-business-types.js.map +1 -0
  24. package/dist/overture.js +28 -28
  25. package/dist/pdf.js +2 -1
  26. package/dist/pdf.js.map +1 -1
  27. package/dist/pitch-brief.d.ts +33 -0
  28. package/dist/pitch-brief.js +160 -0
  29. package/dist/pitch-brief.js.map +1 -0
  30. package/dist/report-pack.js +2 -1
  31. package/dist/report-pack.js.map +1 -1
  32. package/dist/reporters.js +4 -2
  33. package/dist/reporters.js.map +1 -1
  34. package/dist/rules.js +165 -14
  35. package/dist/rules.js.map +1 -1
  36. package/dist/shortlist-runner.d.ts +4 -0
  37. package/dist/shortlist-runner.js +10 -0
  38. package/dist/shortlist-runner.js.map +1 -1
  39. package/dist/tls-probe.d.ts +2 -0
  40. package/dist/tls-probe.js +46 -0
  41. package/dist/tls-probe.js.map +1 -0
  42. package/dist/types.d.ts +9 -0
  43. package/dist/website-enrichment.d.ts +3 -0
  44. package/dist/website-enrichment.js +27 -1
  45. package/dist/website-enrichment.js.map +1 -1
  46. package/dist/workflow.d.ts +1 -1
  47. package/dist/workflow.js +2 -2
  48. package/dist/workflow.js.map +1 -1
  49. package/docs/guides/free-discovery.md +151 -151
  50. package/package.json +1 -1
package/dist/compare.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { readFile, stat } from "node:fs/promises";
2
- import { join } from "node:path";
2
+ import { dirname, isAbsolute, join, relative, resolve } from "node:path";
3
3
  import { brandName, escapeCell, escapeHtml, overallScore, severityRank } from "./reporters.js";
4
4
  function siteHost(url) {
5
5
  return new URL(url).hostname.toLowerCase().replace(/^www\./, "");
@@ -27,7 +27,7 @@ export async function readComparisonReport(path) {
27
27
  }
28
28
  let report;
29
29
  try {
30
- report = JSON.parse(content.replace(/^/, ""));
30
+ report = JSON.parse(content.replace(/^\uFEFF/, ""));
31
31
  }
32
32
  catch (error) {
33
33
  if (error instanceof SyntaxError) {
@@ -44,7 +44,51 @@ export async function readComparisonReport(path) {
44
44
  !Array.isArray(report.findings)) {
45
45
  throw new Error(`${reportPath} is not an Open Local Audit JSON report`);
46
46
  }
47
- return report;
47
+ // Screenshot paths are written relative to the report directory. Only files inside that directory are used, so a
48
+ // report from elsewhere cannot pull unrelated local images into a customer-facing comparison.
49
+ const reportDir = dirname(reportPath);
50
+ const inside = (path) => {
51
+ if (typeof path !== "string" || !path.trim()) {
52
+ return undefined;
53
+ }
54
+ const resolved = resolve(reportDir, path);
55
+ const fromReport = relative(reportDir, resolved);
56
+ return fromReport && !fromReport.startsWith("..") && !isAbsolute(fromReport) ? resolved : undefined;
57
+ };
58
+ const visualEvidence = Array.isArray(report.visualEvidence)
59
+ ? report.visualEvidence.flatMap((item) => {
60
+ const path = inside(item?.path);
61
+ const screenshot = inside(item?.screenshotPath);
62
+ return path ? [{ ...item, path, ...(screenshot ? { screenshotPath: screenshot } : { screenshotPath: undefined }) }] : [];
63
+ })
64
+ : undefined;
65
+ return { ...report, visualEvidence };
66
+ }
67
+ function screenshotPath(report) {
68
+ return report.visualEvidence?.find((item) => item.screenshotPath)?.screenshotPath;
69
+ }
70
+ const pngSignature = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
71
+ async function readScreenshot(path) {
72
+ if (!path) {
73
+ return undefined;
74
+ }
75
+ let data;
76
+ try {
77
+ data = await readFile(path);
78
+ }
79
+ catch {
80
+ return undefined;
81
+ }
82
+ if (data.subarray(0, 8).equals(pngSignature)) {
83
+ return { data, type: "png" };
84
+ }
85
+ return data[0] === 0xff && data[1] === 0xd8 ? { data, type: "jpeg" } : undefined;
86
+ }
87
+ export async function loadComparisonScreenshots(comparison) {
88
+ return {
89
+ before: await readScreenshot(comparison.screenshots.before),
90
+ after: await readScreenshot(comparison.screenshots.after)
91
+ };
48
92
  }
49
93
  export function compareReports(before, after) {
50
94
  if (siteHost(before.finalUrl) !== siteHost(after.finalUrl)) {
@@ -84,7 +128,8 @@ export function compareReports(before, after) {
84
128
  scores,
85
129
  fixed: bySeverity(before.findings.filter((finding) => !afterIds.has(finding.id))),
86
130
  introduced: bySeverity(after.findings.filter((finding) => !beforeIds.has(finding.id))),
87
- remaining: bySeverity(after.findings.filter((finding) => beforeIds.has(finding.id)))
131
+ remaining: bySeverity(after.findings.filter((finding) => beforeIds.has(finding.id))),
132
+ screenshots: { before: screenshotPath(before), after: screenshotPath(after) }
88
133
  };
89
134
  }
90
135
  export function renderComparisonJson(comparison) {
@@ -123,7 +168,18 @@ export function renderComparisonMarkdown(comparison, options = {}) {
123
168
  "",
124
169
  ...section("Fixed Issues", "No issues from the earlier audit were fixed.", ["Severity", "Finding"], comparison.fixed.map((finding) => [finding.severity, finding.title])),
125
170
  ...section("Still Open", "No issues from the earlier audit are still open.", ["Severity", "Finding", "Recommendation"], comparison.remaining.map((finding) => [finding.severity, finding.title, finding.recommendation])),
126
- ...section("New Issues", "No new issues were found.", ["Severity", "Finding", "Evidence", "Recommendation"], comparison.introduced.map((finding) => [finding.severity, finding.title, evidence(finding), finding.recommendation]))
171
+ ...section("New Issues", "No new issues were found.", ["Severity", "Finding", "Evidence", "Recommendation"], comparison.introduced.map((finding) => [finding.severity, finding.title, evidence(finding), finding.recommendation])),
172
+ ...(comparison.screenshots.before || comparison.screenshots.after
173
+ ? [
174
+ "## Screenshots",
175
+ "",
176
+ `- Before: ${comparison.screenshots.before ? "Captured" : "Not captured"}`,
177
+ `- After: ${comparison.screenshots.after ? "Captured" : "Not captured"}`,
178
+ "",
179
+ "Use the HTML or PDF format to see them side by side.",
180
+ ""
181
+ ]
182
+ : [])
127
183
  ];
128
184
  return `${lines.join("\n")}\n`;
129
185
  }
@@ -148,6 +204,19 @@ ${rows.map((row) => `<tr>${row.map((cell) => `<td>${escapeHtml(cell)}</td>`).joi
148
204
  const footer = brand?.footerText || brand?.contact
149
205
  ? `<footer class="meta">${escapeHtml([brand.footerText, brand.contact].filter(Boolean).join(" | "))}</footer>\n`
150
206
  : "";
207
+ const figure = (label, scannedAt, screenshot) => {
208
+ const image = screenshot
209
+ ? `<img src="data:image/${screenshot.type};base64,${screenshot.data.toString("base64")}" alt="${escapeHtml(label)} screenshot">`
210
+ : "<p>Not captured</p>";
211
+ return `<figure>${image}<figcaption>${escapeHtml(label)} (${escapeHtml(scannedAt)})</figcaption></figure>`;
212
+ };
213
+ const screenshots = options.screenshots?.before || options.screenshots?.after
214
+ ? ` <section>
215
+ <h2>Before and After</h2>
216
+ <div class="shots">${figure("Before", comparison.beforeScannedAt, options.screenshots.before)}${figure("After", comparison.afterScannedAt, options.screenshots.after)}</div>
217
+ </section>
218
+ `
219
+ : "";
151
220
  return `<!doctype html>
152
221
  <html lang="en">
153
222
  <head>
@@ -171,6 +240,10 @@ ${rows.map((row) => `<tr>${row.map((cell) => `<td>${escapeHtml(cell)}</td>`).joi
171
240
  th, td { border-bottom: 1px solid var(--line); padding: 0.65rem; text-align: left; vertical-align: top; }
172
241
  th { background: var(--panel); color: var(--muted); font-size: 0.82rem; text-transform: uppercase; }
173
242
  tr:last-child td { border-bottom: 0; }
243
+ .shots { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
244
+ figure { margin: 0; }
245
+ figure img { border: 1px solid var(--line); border-radius: 8px; display: block; max-height: 900px; object-fit: cover; object-position: top; width: 100%; }
246
+ figcaption { color: var(--muted); margin-top: 0.4rem; }
174
247
  </style>
175
248
  </head>
176
249
  <body>
@@ -202,9 +275,100 @@ ${rows.map((row) => `<tr>${row.map((cell) => `<td>${escapeHtml(cell)}</td>`).joi
202
275
  <h2>New Issues</h2>
203
276
  ${table("No new issues were found.", ["Severity", "Finding", "Evidence", "Recommendation"], comparison.introduced.map((finding) => [finding.severity, finding.title, evidence(finding), finding.recommendation]))}
204
277
  </section>
205
- ${footer} </main>
278
+ ${screenshots}${footer} </main>
206
279
  </body>
207
280
  </html>
208
281
  `;
209
282
  }
283
+ export async function renderComparisonPdf(comparison, options = {}) {
284
+ const brand = options.brand;
285
+ const name = brandName(brand);
286
+ const primaryColor = brand?.primaryColor ?? "#145a73";
287
+ const accentColor = brand?.accentColor ?? "#2f7d5f";
288
+ // pdfkit is loaded on demand so the CLI does not pay for it on every start.
289
+ const { default: PDFDocument } = await import("pdfkit");
290
+ const doc = new PDFDocument({ size: "A4", margin: 48, info: { Title: `${name} Progress Report`, Author: name } });
291
+ const chunks = [];
292
+ doc.on("data", (chunk) => chunks.push(chunk));
293
+ const finished = new Promise((resolveBuffer, reject) => {
294
+ doc.on("end", () => resolveBuffer(Buffer.concat(chunks)));
295
+ doc.on("error", reject);
296
+ });
297
+ const sectionTitle = (title) => {
298
+ doc.moveDown(1);
299
+ doc.font("Helvetica-Bold").fontSize(14).fillColor(primaryColor).text(title);
300
+ doc.moveDown(0.3);
301
+ doc.font("Helvetica").fontSize(10).fillColor("#172026");
302
+ };
303
+ const findingList = (findings, empty, withRecommendation) => {
304
+ if (findings.length === 0) {
305
+ doc.text(empty);
306
+ return;
307
+ }
308
+ for (const finding of findings) {
309
+ doc.font("Helvetica-Bold").text(`${finding.severity.toUpperCase()} - ${finding.title}`);
310
+ if (withRecommendation) {
311
+ doc.font("Helvetica").text(finding.recommendation);
312
+ }
313
+ doc.font("Helvetica").moveDown(0.3);
314
+ }
315
+ };
316
+ doc.rect(0, 0, doc.page.width, 92).fill(primaryColor);
317
+ doc.fillColor("#ffffff").font("Helvetica-Bold").fontSize(22).text(`${name} Progress Report`, 48, 32);
318
+ doc.font("Helvetica").fontSize(10).text(comparison.url, 48, 60);
319
+ doc.fillColor("#172026").fontSize(10).text("", 48, 118);
320
+ doc.text(`Before: ${comparison.beforeScannedAt}`);
321
+ doc.text(`After: ${comparison.afterScannedAt}`);
322
+ doc.text(`Profile: ${comparison.profile}`);
323
+ doc.moveDown(0.8);
324
+ doc
325
+ .font("Helvetica-Bold")
326
+ .fontSize(18)
327
+ .fillColor(accentColor)
328
+ .text(`Overall Health: ${comparison.overall.before} -> ${comparison.overall.after} (${signed(comparison.overall.change)})`);
329
+ doc
330
+ .font("Helvetica")
331
+ .fontSize(10)
332
+ .fillColor("#172026")
333
+ .text(`Fixed: ${comparison.fixed.length} Still open: ${comparison.remaining.length} New: ${comparison.introduced.length}`);
334
+ sectionTitle("Score Changes");
335
+ for (const score of Object.values(comparison.scores)) {
336
+ doc.text(`${score.label}: ${score.before}/${score.max} -> ${score.after}/${score.max} (${signed(score.change)})`);
337
+ }
338
+ sectionTitle("Fixed Issues");
339
+ findingList(comparison.fixed, "No issues from the earlier audit were fixed.", false);
340
+ sectionTitle("Still Open");
341
+ findingList(comparison.remaining, "No issues from the earlier audit are still open.", true);
342
+ sectionTitle("New Issues");
343
+ findingList(comparison.introduced, "No new issues were found.", true);
344
+ const shots = [
345
+ ["Before", comparison.beforeScannedAt, options.screenshots?.before],
346
+ ["After", comparison.afterScannedAt, options.screenshots?.after]
347
+ ];
348
+ if (shots.some(([, , shot]) => shot)) {
349
+ doc.addPage();
350
+ doc.font("Helvetica-Bold").fontSize(14).fillColor(primaryColor).text("Before and After");
351
+ const top = doc.y + 8;
352
+ const width = (doc.page.width - 48 * 2 - 16) / 2;
353
+ shots.forEach(([label, scannedAt, shot], index) => {
354
+ const x = 48 + index * (width + 16);
355
+ doc.font("Helvetica").fontSize(9).fillColor("#5f6b75").text(`${label} (${scannedAt})`, x, top, { width });
356
+ if (shot) {
357
+ doc.image(shot.data, x, top + 16, { fit: [width, doc.page.height - top - 96], align: "center" });
358
+ }
359
+ else {
360
+ doc.text("Not captured", x, top + 16, { width });
361
+ }
362
+ });
363
+ }
364
+ if (brand?.footerText || brand?.contact) {
365
+ doc
366
+ .font("Helvetica")
367
+ .fontSize(8)
368
+ .fillColor("#5f6b75")
369
+ .text([brand.footerText, brand.contact].filter(Boolean).join(" | "), 48, doc.page.height - 64, { width: doc.page.width - 96 });
370
+ }
371
+ doc.end();
372
+ return await finished;
373
+ }
210
374
  //# sourceMappingURL=compare.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"compare.js","sourceRoot":"","sources":["../src/compare.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compare.js","sourceRoot":"","sources":["../src/compare.ts"],"names":[],"mappings":"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"}
package/dist/contact.d.ts CHANGED
@@ -1,2 +1,9 @@
1
+ import { type CheerioAPI } from "cheerio";
1
2
  import type { PublicContact } from "./types.js";
3
+ export declare function hasContactOrBookingLink($: CheerioAPI, pageUrl: string): boolean;
4
+ export interface PageForms {
5
+ enquiryForm: boolean;
6
+ newsletterForm: boolean;
7
+ }
8
+ export declare function detectPageForms($: CheerioAPI, pageUrl: string): PageForms;
2
9
  export declare function extractPublicContact(html: string, finalUrl: string): PublicContact;
package/dist/contact.js CHANGED
@@ -1,6 +1,19 @@
1
1
  import { load } from "cheerio";
2
2
  const emailPattern = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi;
3
- const contactPathPattern = /(?:^|\/)(contact|contact-us|iletisim|reach-us|booking|appointment)(?:\/|$)/i;
3
+ // Contact extraction keeps its narrow patterns because a contact page link raises contact confidence and picks the
4
+ // outreach channel; the broader link patterns below only decide whether a visitor can reach the business.
5
+ const contactPagePathPattern = /(?:^|\/)(contact|contact-us|iletisim|reach-us|booking|appointment)(?:\/|$)/i;
6
+ const contactPageTextPattern = /contact|iletisim|appointment|booking/i;
7
+ const contactPathPattern = /(?:^|\/)(contact|contact-us|get-in-touch|enquir(?:e|y|ies)|iletisim|reach-us|book|booking|appointments?)(?:\.[a-z]+)?(?:\/|$)/i;
8
+ const contactTextPattern = /contact|get in touch|enquir|iletisim|iletişim|appointment|\bbook(?:ings?)?\b/i;
9
+ const bookingPathPattern = /(?:^|[/._-])(book|booking|bookings|appointments?|reserve|reservations?)(?:[/._-]|$)/i;
10
+ const bookingTextPattern = /\b(?:book(?:ings?)?|appointments?|reserve|reservations?)\b/i;
11
+ const bookingHostPattern = /dentally|setmore|calendly|fresha|treatwell|booksy|simplybook|acuityscheduling|mindbody|resdiary|opentable|zocdoc|vagaro|gettimely|phorest|youcanbook/i;
12
+ const embeddedFormPattern = /forms\.gle|docs\.google\.com\/forms|typeform\.com|jotform|formstack|hsforms|wufoo|cognitoforms|tally\.so/i;
13
+ const textInputTypes = new Set(["", "text", "email", "tel"]);
14
+ const ignoredInputTypes = new Set(["hidden", "submit", "button", "reset", "image", "checkbox", "radio"]);
15
+ const enquiryFieldPattern = /name|phone|e-?mail|message/i;
16
+ const newsletterCuePattern = /newsletter|subscri|mailchimp|list-manage/i;
4
17
  const socialHosts = ["facebook.com", "instagram.com", "linkedin.com", "x.com", "twitter.com", "tiktok.com", "youtube.com"];
5
18
  const placeholderSocialPattern = /\/(yourbusiness|example|placeholder|your-company|yourcompany)(?:\/?$)/i;
6
19
  function unique(values) {
@@ -55,6 +68,96 @@ function isPlaceholderSocial(url) {
55
68
  return true;
56
69
  }
57
70
  }
71
+ function isContactLink(url, text) {
72
+ return contactPathPattern.test(new URL(url).pathname) || contactTextPattern.test(text);
73
+ }
74
+ function siteHost(url) {
75
+ return new URL(url).hostname.replace(/^www\./, "").toLowerCase();
76
+ }
77
+ function isBookingLink(url, text) {
78
+ const parsed = new URL(url);
79
+ return bookingHostPattern.test(parsed.hostname) || bookingPathPattern.test(parsed.pathname) || bookingTextPattern.test(text);
80
+ }
81
+ // Links to another page of the same site (or a subdomain) that look like a contact or booking page, or
82
+ // off-site links to a booking page. An off-site link that only says "contact" (such as a web agency footer) does not count.
83
+ // Anchors back to the audited page itself are skipped: that page's own forms and email links are checked directly.
84
+ export function hasContactOrBookingLink($, pageUrl) {
85
+ const page = normalizeUrl(pageUrl, pageUrl);
86
+ if (!page) {
87
+ return false;
88
+ }
89
+ const host = siteHost(page);
90
+ return $("a[href]")
91
+ .toArray()
92
+ .some((element) => {
93
+ const url = normalizeUrl($(element).attr("href")?.trim() ?? "", page);
94
+ if (!url || url === page) {
95
+ return false;
96
+ }
97
+ const linkHost = siteHost(url);
98
+ const text = $(element).text().trim();
99
+ return linkHost === host || linkHost.endsWith(`.${host}`) ? isContactLink(url, text) : isBookingLink(url, text);
100
+ });
101
+ }
102
+ // An enquiry form has a message box, or at least two text-like fields that look like contact details.
103
+ // Search forms and newsletter signups are not enquiry forms; embedded form providers count as one.
104
+ export function detectPageForms($, pageUrl) {
105
+ let enquiryForm = false;
106
+ let newsletterForm = false;
107
+ for (const form of $("form").toArray()) {
108
+ const $form = $(form);
109
+ const fields = $form
110
+ .find("input")
111
+ .toArray()
112
+ .map((input) => ({
113
+ type: ($(input).attr("type") ?? "").trim().toLowerCase(),
114
+ name: $(input).attr("name") ?? "",
115
+ label: `${$(input).attr("name") ?? ""} ${$(input).attr("id") ?? ""}`
116
+ }))
117
+ .filter((input) => !ignoredInputTypes.has(input.type));
118
+ const textFields = fields.filter((input) => textInputTypes.has(input.type));
119
+ // reCAPTCHA/hCaptcha inject a hidden response textarea into rendered pages; it is not a message box.
120
+ const hasTextarea = $form.find("textarea").not('[name*="captcha"], [id*="captcha"]').length > 0;
121
+ const isEmail = (input) => input.type === "email" || /e-?mail/i.test(input.label);
122
+ const isSearch = $form.closest('[role="search"]').length > 0 ||
123
+ /search/i.test($form.attr("action") ?? "") ||
124
+ (fields.length === 1 && (fields[0].type === "search" || /^(q|s|search)$/i.test(fields[0].name)));
125
+ if (isSearch) {
126
+ continue;
127
+ }
128
+ const newsletterCue = [
129
+ $form.attr("action"),
130
+ $form.attr("id"),
131
+ $form.attr("class"),
132
+ ...$form
133
+ .find('button, input[type="submit"]')
134
+ .toArray()
135
+ .map((button) => `${$(button).text()} ${$(button).attr("value") ?? ""}`)
136
+ ].join(" ");
137
+ const isNewsletter = !hasTextarea &&
138
+ ((fields.length === 1 && isEmail(fields[0])) || (newsletterCuePattern.test(newsletterCue) && textFields.some(isEmail)));
139
+ if (isNewsletter) {
140
+ newsletterForm = true;
141
+ continue;
142
+ }
143
+ if (hasTextarea ||
144
+ (textFields.length >= 2 &&
145
+ textFields.some((input) => input.type === "email" || input.type === "tel" || enquiryFieldPattern.test(input.label)))) {
146
+ enquiryForm = true;
147
+ }
148
+ }
149
+ const embeddedForm = $("iframe[src], script[src]")
150
+ .toArray()
151
+ .some((element) => {
152
+ const src = normalizeUrl($(element).attr("src")?.trim() ?? "", pageUrl);
153
+ if (!src) {
154
+ return false;
155
+ }
156
+ const url = new URL(src);
157
+ return embeddedFormPattern.test(`${url.hostname}${url.pathname}`);
158
+ });
159
+ return { enquiryForm: enquiryForm || embeddedForm, newsletterForm };
160
+ }
58
161
  function confidenceFor(contact, sourceCount) {
59
162
  if (sourceCount >= 3 || (contact.publicEmail && contact.publicPhone)) {
60
163
  return "High";
@@ -108,7 +211,7 @@ export function extractPublicContact(html, finalUrl) {
108
211
  continue;
109
212
  }
110
213
  const text = $(element).text().trim();
111
- if (contactPathPattern.test(new URL(url).pathname) || /contact|iletisim|appointment|booking/i.test(text)) {
214
+ if (contactPagePathPattern.test(new URL(url).pathname) || contactPageTextPattern.test(text)) {
112
215
  contactPageUrls.push(url);
113
216
  sources.push("contact-page");
114
217
  }
@@ -125,6 +228,7 @@ export function extractPublicContact(html, finalUrl) {
125
228
  publicPhone: unique(phones)[0],
126
229
  whatsappUrl: unique(whatsappUrls)[0],
127
230
  contactPageUrl: unique(contactPageUrls)[0],
231
+ contactFormUrl: detectPageForms($, finalUrl).enquiryForm ? finalUrl : undefined,
128
232
  socialProfiles: unique(socialProfiles)
129
233
  };
130
234
  const uniqueSources = unique(sources);
@@ -1 +1 @@
1
- {"version":3,"file":"contact.js","sourceRoot":"","sources":["../src/contact.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG/B,MAAM,YAAY,GAAG,yCAAyC,CAAC;AAC/D,MAAM,kBAAkB,GAAG,6EAA6E,CAAC;AACzG,MAAM,WAAW,GAAG,CAAC,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC;AAC3H,MAAM,wBAAwB,GAAG,wEAAwE,CAAC;AAE1G,SAAS,MAAM,CAAC,MAAgB;IAC9B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,YAAY,CAAC,GAAW,EAAE,OAAe;IAChD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAClC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC;QACd,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACvF,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,YAAY,CAAC,SAAS,GAAG,CAAC,CAAC;QAC3B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,YAAY,CAAC,SAAS,GAAG,CAAC,CAAC;IAC3B,IAAI,kCAAkC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,gCAAgC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACnG,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACxE,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC;IACnD,OAAO,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7C,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QACjE,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,UAAU,EAAE,CAAC,CAAC,CAAC;IAClG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,GAAW;IACtC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,OAAO,wBAAwB,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,OAAmE,EAAE,WAAmB;IAC7G,IAAI,WAAW,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACrE,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;QACpB,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAY,EAAE,QAAgB;IACjE,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;IACrB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,OAAO,IAAI,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;QAC7C,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC;QAC7C,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,SAAS;QACX,CAAC;QAED,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;YACnC,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACnB,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACzB,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;YACnC,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACnB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;YACD,SAAS;QACX,CAAC;QAED,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACzC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,SAAS;QACX,CAAC;QAED,IAAI,yCAAyC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACxD,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACzB,SAAS;QACX,CAAC;QAED,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC;YAClD,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACzB,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACvB,SAAS;QACX,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;QACtC,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,uCAAuC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACzG,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC1B,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5G,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG;QACX,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC9B,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC9B,WAAW,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACpC,cAAc,EAAE,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAC1C,cAAc,EAAE,MAAM,CAAC,cAAc,CAAC;KACvC,CAAC;IACF,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAEtC,OAAO;QACL,GAAG,IAAI;QACP,iBAAiB,EAAE,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC;QAC5D,aAAa,EAAE,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;KACxC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"contact.js","sourceRoot":"","sources":["../src/contact.ts"],"names":[],"mappings":"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"}
@@ -72,6 +72,7 @@ export interface ProspectExportRow {
72
72
  error?: string;
73
73
  dotnetStack?: DotnetStack["stack"];
74
74
  dotnetLegacyFramework?: boolean;
75
+ chainReason?: string;
75
76
  address?: string;
76
77
  country?: string;
77
78
  locality?: string;
package/dist/discovery.js CHANGED
@@ -802,18 +802,101 @@ function areaCodeMismatches(inputs) {
802
802
  }
803
803
  return mismatches;
804
804
  }
805
+ const publicSectorDomains = ["nhs.uk", "gov.uk", "gov", "police.uk", "ac.uk", "sch.uk"];
806
+ // Social, link-in-bio, directory, site-builder, and booking hosts give each business its own page on a shared host,
807
+ // so sharing the host or having a deep path says nothing about being a chain. Such leads usually lack a real website.
808
+ const hostedPageDomains = [
809
+ ...sharedProfileHostnames,
810
+ "facebook.com",
811
+ "instagram.com",
812
+ "linkedin.com",
813
+ "x.com",
814
+ "twitter.com",
815
+ "tiktok.com",
816
+ "youtube.com",
817
+ "sites.google.com",
818
+ "google.com",
819
+ "yell.com",
820
+ "tripadvisor.com",
821
+ "tripadvisor.co.uk",
822
+ "booking.com",
823
+ "treatwell.co.uk",
824
+ "fresha.com",
825
+ "booksy.com",
826
+ "setmore.com",
827
+ "calendly.com",
828
+ "opentable.com",
829
+ "opentable.co.uk",
830
+ "resdiary.com"
831
+ ];
832
+ function isHostedPage(host) {
833
+ return hostedPageDomains.some((domain) => host === domain || host.endsWith(`.${domain}`));
834
+ }
835
+ function websiteUrlOf(input) {
836
+ if (!input.resolution.hasWebsite || !input.resolution.websiteUrl)
837
+ return undefined;
838
+ try {
839
+ return new URL(input.resolution.websiteUrl);
840
+ }
841
+ catch {
842
+ return undefined;
843
+ }
844
+ }
845
+ // Chain branches and public bodies rarely buy small-business website work. The strongest signal wins: a
846
+ // public-sector domain, then one website host shared by several leads in this search, then a deep branch page.
847
+ function chainReasons(inputs) {
848
+ const leads = inputs.flatMap((input) => {
849
+ const url = websiteUrlOf(input);
850
+ return url ? [{ input, url, host: url.hostname.toLowerCase().replace(/^www\./, "") }] : [];
851
+ });
852
+ // Count distinct business names over distinct leads per host, so one record listed twice or two source records
853
+ // for the same business do not look like a chain.
854
+ const namesByHost = new Map();
855
+ for (const { input, host } of leads) {
856
+ const key = stableLeadKey(input);
857
+ const names = namesByHost.get(host) ?? new Map();
858
+ if (!names.has(key))
859
+ names.set(key, normalizeLabel(input.candidate.label) ?? key);
860
+ namesByHost.set(host, names);
861
+ }
862
+ const reasons = new Map();
863
+ for (const { input, url, host } of leads) {
864
+ const publicDomain = publicSectorDomains.find((domain) => host === domain || host.endsWith(`.${domain}`));
865
+ const hosted = isHostedPage(host);
866
+ const sharedCount = hosted ? 0 : new Set(namesByHost.get(host)?.values()).size;
867
+ const segments = url.pathname.split("/").filter(Boolean);
868
+ if (/^[a-z]{2}(-[a-z]{2})?$/i.test(segments[0] ?? ""))
869
+ segments.shift();
870
+ if (/^index\.(html|php)$/i.test(segments.at(-1) ?? ""))
871
+ segments.pop();
872
+ const reason = publicDomain
873
+ ? `Website is on a public-sector domain (${publicDomain}); this is not a small-business lead`
874
+ : sharedCount >= 2
875
+ ? `${sharedCount} leads in this search share ${host}; this looks like a multi-location brand`
876
+ : !hosted && segments.length >= 2
877
+ ? `Website URL is a branch page on a larger site (/${segments[0]}/…)`
878
+ : undefined;
879
+ if (reason)
880
+ reasons.set(input, reason);
881
+ }
882
+ return reasons;
883
+ }
805
884
  export function buildProspectRows(inputs) {
806
885
  const locationMismatches = areaCodeMismatches(inputs);
886
+ const chains = chainReasons(inputs);
807
887
  return inputs.map((input) => {
808
888
  const locationMismatch = locationMismatches.get(input);
889
+ const chainReason = chains.get(input);
809
890
  if (input.audit?.identity?.status === "conflict") {
810
891
  input = { ...input, audit: { ...input.audit, status: "failed", contact: undefined, dotnetStack: undefined, score: undefined, topFinding: undefined, reportPath: undefined, error: input.audit.error ?? "Website identity conflicts with the source; manual review is required." } };
811
892
  }
812
893
  const audit = input.audit ?? { status: "not-audited" };
813
894
  const basePriority = priorityFor(input);
814
- const priority = locationMismatch
815
- ? { priority: basePriority.priority === "low" ? "low" : "medium", nextAction: "Confirm the business location before outreach; its phone area code does not match this search." }
816
- : basePriority;
895
+ const priority = chainReason
896
+ ? { priority: "low", nextAction: "Skip unless you are targeting the head office; this lead looks like a chain branch or public body." }
897
+ : locationMismatch
898
+ ? { priority: basePriority.priority === "low" ? "low" : "medium", nextAction: "Confirm the business location before outreach; its phone area code does not match this search." }
899
+ : basePriority;
817
900
  const enrichment = enrichmentFor(input);
818
901
  const handoff = contactHandoffFor(input);
819
902
  const contact = prospectContact(input);
@@ -831,8 +914,8 @@ export function buildProspectRows(inputs) {
831
914
  auditStatus: audit.status,
832
915
  score: audit.score,
833
916
  topFinding: audit.topFinding,
834
- opportunityScore: opportunityScoreFor(input),
835
- opportunityReasons: locationMismatch ? [...opportunityReasonsFor(input), locationMismatch] : opportunityReasonsFor(input),
917
+ opportunityScore: chainReason ? Math.min(opportunityScoreFor(input), 20) : opportunityScoreFor(input),
918
+ opportunityReasons: [...opportunityReasonsFor(input), ...[locationMismatch, chainReason].filter((reason) => reason !== undefined)],
836
919
  ...enrichment,
837
920
  ...details,
838
921
  ...(input.candidate.source === "overture" ? {
@@ -856,7 +939,8 @@ export function buildProspectRows(inputs) {
856
939
  reportPath: audit.reportPath,
857
940
  error: audit.error ?? input.resolution.reason,
858
941
  dotnetStack: audit.dotnetStack?.stack,
859
- dotnetLegacyFramework: audit.dotnetStack?.legacyFramework
942
+ dotnetLegacyFramework: audit.dotnetStack?.legacyFramework,
943
+ chainReason
860
944
  };
861
945
  });
862
946
  }
@@ -980,6 +1064,7 @@ export function renderProspectRowsCsv(rows, preset = "standard") {
980
1064
  "error",
981
1065
  "dotnetStack",
982
1066
  "dotnetLegacyFramework",
1067
+ "chainReason",
983
1068
  ...detailColumns
984
1069
  ];
985
1070
  const body = rows.map((row) => [
@@ -1019,6 +1104,7 @@ export function renderProspectRowsCsv(rows, preset = "standard") {
1019
1104
  row.error ?? "",
1020
1105
  row.dotnetStack ?? "",
1021
1106
  row.dotnetLegacyFramework === undefined ? "" : row.dotnetLegacyFramework ? "yes" : "no",
1107
+ row.chainReason ?? "",
1022
1108
  ...detailColumns.map((key) => key === "sourceProvenance" || key === "identityReasons" || key === "identityEvidence" ? JSON.stringify(row[key] ?? []) : String(row[key] ?? ""))
1023
1109
  ]
1024
1110
  .map(escapeCsvCell)