mcp-scraper 0.44.2 → 0.44.4

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.
@@ -86,7 +86,7 @@ import {
86
86
  renewDirectoryArtifactDownload,
87
87
  resolveDeploymentProfile,
88
88
  transcribeMediaUrl
89
- } from "./chunk-M27QGXUM.js";
89
+ } from "./chunk-ZVOVPXDL.js";
90
90
  import {
91
91
  auditImageUrls,
92
92
  auditImages,
@@ -142,7 +142,7 @@ import {
142
142
  } from "./chunk-3ZUBQQPQ.js";
143
143
  import {
144
144
  PACKAGE_VERSION
145
- } from "./chunk-OEW4VBS2.js";
145
+ } from "./chunk-HFCIHZHA.js";
146
146
  import {
147
147
  abandonExtractSettlement,
148
148
  countSuccessfulPages,
@@ -12159,6 +12159,14 @@ async function listPublicLocalSourcebook(category, state) {
12159
12159
  const result = await getDb().execute({ sql: `SELECT r.payload_json FROM local_sourcebook_submissions s JOIN local_sourcebook_revisions r ON r.submission_id = s.id AND r.revision = s.published_revision WHERE s.category = ? AND s.state = ? AND s.published_revision IS NOT NULL AND s.status NOT IN ('unpublished', 'rejected') ORDER BY s.business_name`, args: [category, state] });
12160
12160
  return result.rows.map((row) => parseJson2(row.payload_json));
12161
12161
  }
12162
+ async function listAllPublicLocalSourcebook(category) {
12163
+ await ensureLocalSourcebookSchema();
12164
+ const result = category ? await getDb().execute({
12165
+ sql: `SELECT r.payload_json FROM local_sourcebook_submissions s JOIN local_sourcebook_revisions r ON r.submission_id = s.id AND r.revision = s.published_revision WHERE s.category = ? AND s.published_revision IS NOT NULL AND s.status NOT IN ('unpublished', 'rejected') ORDER BY s.state, s.business_name`,
12166
+ args: [category]
12167
+ }) : await getDb().execute(`SELECT r.payload_json FROM local_sourcebook_submissions s JOIN local_sourcebook_revisions r ON r.submission_id = s.id AND r.revision = s.published_revision WHERE s.published_revision IS NOT NULL AND s.status NOT IN ('unpublished', 'rejected') ORDER BY s.category, s.state, s.business_name`);
12168
+ return result.rows.map((row) => parseJson2(row.payload_json));
12169
+ }
12162
12170
  async function getPublicLocalSourcebook(category, state, slug2) {
12163
12171
  await ensureLocalSourcebookSchema();
12164
12172
  const result = await getDb().execute({ sql: `SELECT r.payload_json FROM local_sourcebook_submissions s JOIN local_sourcebook_revisions r ON r.submission_id = s.id AND r.revision = s.published_revision WHERE s.category = ? AND s.state = ? AND s.slug = ? AND s.published_revision IS NOT NULL AND s.status NOT IN ('unpublished', 'rejected') LIMIT 1`, args: [category, state, slug2] });
@@ -12768,6 +12776,46 @@ var MapsExtractor = class {
12768
12776
 
12769
12777
  // src/api/local-sourcebook-compiler.ts
12770
12778
  import { createHash as createHash3 } from "crypto";
12779
+
12780
+ // src/api/local-sourcebook-public-urls.ts
12781
+ var DEFAULT_ROOT_DOMAIN = "localsourcebook.com";
12782
+ var CATEGORY_PUBLIC_SLUGS = {
12783
+ home: "home-services",
12784
+ professional: "professional",
12785
+ restaurants: "restaurants",
12786
+ financial: "financial",
12787
+ realestate: "realestate",
12788
+ auto: "auto",
12789
+ wellness: "wellness"
12790
+ };
12791
+ function rootDomain() {
12792
+ const configured = process.env.LOCAL_SOURCEBOOK_PUBLIC_ROOT_DOMAIN?.trim() || DEFAULT_ROOT_DOMAIN;
12793
+ return configured.replace(/^https?:\/\//i, "").replace(/^www\./i, "").replace(/\/.*$/, "").replace(/\.+$/, "").toLowerCase();
12794
+ }
12795
+ function localSourcebookPublicUrls(category, state, slug2) {
12796
+ const categoryUrl = `https://${CATEGORY_PUBLIC_SLUGS[category]}.${rootDomain()}`;
12797
+ const statePath = `/${state.toLowerCase()}`;
12798
+ const profilePath = `${statePath}/${slug2}/`;
12799
+ const reviewsPath = `${statePath}/${slug2}/reviews`;
12800
+ return {
12801
+ categoryUrl,
12802
+ nationwideDirectoryUrl: `${categoryUrl}/directory`,
12803
+ stateUrl: `${categoryUrl}${statePath}`,
12804
+ profileUrl: `${categoryUrl}${profilePath}`,
12805
+ reviewsUrl: `${categoryUrl}${reviewsPath}`,
12806
+ profilePath,
12807
+ reviewsPath
12808
+ };
12809
+ }
12810
+ function localSourcebookPublicationLinks(submission) {
12811
+ return {
12812
+ ...localSourcebookPublicUrls(submission.category, submission.state, submission.slug),
12813
+ publicationStatus: submission.status,
12814
+ isLive: submission.status === "published" && submission.publishedRevision !== null
12815
+ };
12816
+ }
12817
+
12818
+ // src/api/local-sourcebook-compiler.ts
12771
12819
  var CATEGORY_LABELS = {
12772
12820
  home: "Home & property services",
12773
12821
  professional: "Professional services",
@@ -13120,6 +13168,7 @@ function compileLocalSourcebookListing(input) {
13120
13168
  evidenceIds: mapsEvidenceId ? [mapsEvidenceId] : []
13121
13169
  }
13122
13170
  ];
13171
+ const publicUrls = localSourcebookPublicUrls(input.submission.category, input.submission.state, input.submission.slug);
13123
13172
  const listing = {
13124
13173
  id: input.submission.id,
13125
13174
  publicationRevision: input.submission.draftRevision + 1,
@@ -13128,6 +13177,14 @@ function compileLocalSourcebookListing(input) {
13128
13177
  state: input.submission.state.toLowerCase(),
13129
13178
  stateName: STATE_NAMES[input.submission.state.toUpperCase()] ?? input.submission.state.toUpperCase(),
13130
13179
  slug: input.submission.slug,
13180
+ canonicalPaths: {
13181
+ profile: publicUrls.profilePath,
13182
+ reviews: publicUrls.reviewsPath
13183
+ },
13184
+ canonicalUrls: {
13185
+ profile: publicUrls.profileUrl,
13186
+ reviews: publicUrls.reviewsUrl
13187
+ },
13131
13188
  name: maps?.name || input.submission.businessName,
13132
13189
  summary,
13133
13190
  description,
@@ -21354,7 +21411,11 @@ function getLocalSourcebookContract(category) {
21354
21411
  categories: LOCAL_SOURCEBOOK_CATEGORIES,
21355
21412
  selectedCategory: category ?? null,
21356
21413
  categoryTag: category ? CATEGORY_TAG[category] : null,
21357
- canonicalRoutes: { profile: "/{state}/{business-slug}/", reviews: "/{state}/{business-slug}/reviews" },
21414
+ canonicalRoutes: {
21415
+ nationwideDirectory: "https://{category}.localsourcebook.com/directory",
21416
+ profile: "https://{category}.localsourcebook.com/{state}/{business-slug}/",
21417
+ reviews: "https://{category}.localsourcebook.com/{state}/{business-slug}/reviews"
21418
+ },
21358
21419
  requiredCreateFields: ["category", "state", "businessName", "websiteUrl", "tags", "idempotencyKey"],
21359
21420
  systemCompiledSections: ["identity", "services/products", "service areas/locations", "genuine media", "reviews and theme counts", "evidence", "answered FAQ", "collection receipts"],
21360
21421
  workflow: ["list-local-sourcebook-tags", "get-local-sourcebook-contract", "prepare-local-sourcebook-write", "validate-local-sourcebook-write", "local-sourcebook-capture", "local_sourcebook_submission_status"],
@@ -21374,9 +21435,10 @@ async function prepareLocalSourcebookWrite(input) {
21374
21435
  ...parsed.tags.filter((tag) => tag !== categoryTag).map((tag) => ({ tag }))
21375
21436
  ];
21376
21437
  const tagResolutions = await resolveLocalSourcebookTags(candidates);
21438
+ const publicUrls = localSourcebookPublicUrls(parsed.category, parsed.state, slug2);
21377
21439
  return {
21378
21440
  ok: true,
21379
- route: { category: parsed.category, state: parsed.state, slug: slug2, profile: `/${parsed.state}/${slug2}/`, reviews: `/${parsed.state}/${slug2}/reviews` },
21441
+ route: { category: parsed.category, state: parsed.state, slug: slug2, ...publicUrls },
21380
21442
  proposedWrite: { ...parsed, slug: slug2, tags: tagResolutions.filter((item) => item.action === "reuse").map((item) => item.tag) },
21381
21443
  contract: getLocalSourcebookContract(parsed.category),
21382
21444
  tagResolutions,
@@ -21453,6 +21515,18 @@ var ValidateWriteSchema = z26.object({
21453
21515
  tagDecisions: z26.array(DirectoryTagDecisionSchema).max(20).optional()
21454
21516
  }).strict();
21455
21517
  var CaptureWriteSchema = ValidateWriteSchema.extend({ idempotencyKey: z26.string().trim().min(8).max(200).optional() });
21518
+ function withCanonicalLocalSourcebookUrls(listing) {
21519
+ const category = z26.enum(LOCAL_SOURCEBOOK_CATEGORIES).safeParse(listing.category);
21520
+ const state = typeof listing.state === "string" ? listing.state : "";
21521
+ const listingSlug = typeof listing.slug === "string" ? listing.slug : "";
21522
+ if (!category.success || !state || !listingSlug) return listing;
21523
+ const publicUrls = localSourcebookPublicUrls(category.data, state, listingSlug);
21524
+ return {
21525
+ ...listing,
21526
+ canonicalPaths: { profile: publicUrls.profilePath, reviews: publicUrls.reviewsPath },
21527
+ canonicalUrls: { profile: publicUrls.profileUrl, reviews: publicUrls.reviewsUrl }
21528
+ };
21529
+ }
21456
21530
  function acquisitionPlan(websiteUrl) {
21457
21531
  return {
21458
21532
  website: { startUrl: websiteUrl, mode: "broad_site_crawl", capture: ["homepage", "services", "products", "locations", "service_areas", "about", "team_staff", "contact", "policies"] },
@@ -21493,6 +21567,7 @@ localSourcebookApp.post("/capture", createApiKeyAuth(), async (c) => {
21493
21567
  return c.json({ error: "idempotency_key_required", message: "A stable idempotencyKey is required for a new Local Sourcebook capture." }, 400);
21494
21568
  }
21495
21569
  const listingSlug = identity.slug ?? slug(identity.businessName);
21570
+ const publicUrls = localSourcebookPublicUrls(identity.category, identity.state, listingSlug);
21496
21571
  const submission = await createLocalSourcebookSubmission({
21497
21572
  ownerUserId: Number(user.id),
21498
21573
  category: identity.category,
@@ -21509,7 +21584,8 @@ localSourcebookApp.post("/capture", createApiKeyAuth(), async (c) => {
21509
21584
  name: identity.businessName,
21510
21585
  websiteUrl: identity.websiteUrl,
21511
21586
  tags: validation.normalizedTags,
21512
- canonicalPaths: { profile: `/${identity.state}/${listingSlug}`, reviews: `/${identity.state}/${listingSlug}/reviews` },
21587
+ canonicalPaths: { profile: publicUrls.profilePath, reviews: publicUrls.reviewsPath },
21588
+ canonicalUrls: { profile: publicUrls.profileUrl, reviews: publicUrls.reviewsUrl },
21513
21589
  verificationState: "submitted",
21514
21590
  acquisitionPlan: acquisitionPlan(identity.websiteUrl),
21515
21591
  evidence: [],
@@ -21519,7 +21595,7 @@ localSourcebookApp.post("/capture", createApiKeyAuth(), async (c) => {
21519
21595
  });
21520
21596
  await persistLocalSourcebookTags(submission.id, Number(user.id), validation.normalizedTags, parsed.data.tagDecisions);
21521
21597
  const dispatched = await dispatchLocalSourcebookAcquisition(submission.id).catch(() => false);
21522
- return c.json({ ok: true, valid: true, submission, normalizedTags: validation.normalizedTags, acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(identity.websiteUrl) }, 202);
21598
+ return c.json({ ok: true, valid: true, submission, publicUrls: localSourcebookPublicationLinks(submission), normalizedTags: validation.normalizedTags, acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(identity.websiteUrl) }, 202);
21523
21599
  } catch (error) {
21524
21600
  const message = error instanceof Error ? error.message : String(error);
21525
21601
  const conflict = message.includes("revision conflict") ? "revision_conflict" : message.includes("idempotency key conflicts") ? "idempotency_conflict" : null;
@@ -21533,6 +21609,7 @@ localSourcebookApp.post("/submissions", createApiKeyAuth(), async (c) => {
21533
21609
  if (!parsed.success) return c.json({ error: "invalid_submission", issues: parsed.error.issues }, 400);
21534
21610
  const input = parsed.data;
21535
21611
  const listingSlug = input.slug ?? slug(input.businessName);
21612
+ const publicUrls = localSourcebookPublicUrls(input.category, input.state, listingSlug);
21536
21613
  try {
21537
21614
  const submission = await createLocalSourcebookSubmission({
21538
21615
  ownerUserId: Number(user.id),
@@ -21545,7 +21622,8 @@ localSourcebookApp.post("/submissions", createApiKeyAuth(), async (c) => {
21545
21622
  slug: listingSlug,
21546
21623
  name: input.businessName,
21547
21624
  websiteUrl: input.websiteUrl,
21548
- canonicalPaths: { profile: `/${input.state}/${listingSlug}`, reviews: `/${input.state}/${listingSlug}/reviews` },
21625
+ canonicalPaths: { profile: publicUrls.profilePath, reviews: publicUrls.reviewsPath },
21626
+ canonicalUrls: { profile: publicUrls.profileUrl, reviews: publicUrls.reviewsUrl },
21549
21627
  verificationState: "submitted",
21550
21628
  acquisitionPlan: acquisitionPlan(input.websiteUrl),
21551
21629
  evidence: [],
@@ -21554,7 +21632,7 @@ localSourcebookApp.post("/submissions", createApiKeyAuth(), async (c) => {
21554
21632
  }
21555
21633
  });
21556
21634
  const dispatched = await dispatchLocalSourcebookAcquisition(submission.id).catch(() => false);
21557
- return c.json({ ok: true, submission, acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(input.websiteUrl) }, 202);
21635
+ return c.json({ ok: true, submission, publicUrls: localSourcebookPublicationLinks(submission), acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(input.websiteUrl) }, 202);
21558
21636
  } catch (error) {
21559
21637
  return c.json({ error: "submission_conflict", message: error instanceof Error ? error.message : String(error) }, 409);
21560
21638
  }
@@ -21563,7 +21641,7 @@ localSourcebookApp.get("/submissions/:id", createApiKeyAuth(), async (c) => {
21563
21641
  const userId = Number(c.get("user").id);
21564
21642
  const submission = await getLocalSourcebookSubmission(c.req.param("id"), userId);
21565
21643
  if (!submission) return c.json({ error: "not_found" }, 404);
21566
- return c.json({ ok: true, submission, draft: await getLocalSourcebookDraft(submission.id, userId) });
21644
+ return c.json({ ok: true, submission, publicUrls: localSourcebookPublicationLinks(submission), draft: await getLocalSourcebookDraft(submission.id, userId) });
21567
21645
  });
21568
21646
  localSourcebookApp.on(["PATCH", "POST"], "/submissions/:id/draft", createApiKeyAuth(), (c) => c.json({
21569
21647
  error: "evidence_refresh_required",
@@ -21576,16 +21654,18 @@ localSourcebookApp.post("/submissions/:id/refresh", createApiKeyAuth(), async (c
21576
21654
  const submission = await queueLocalSourcebookRefresh(c.req.param("id"), Number(user.id));
21577
21655
  if (!submission) return c.json({ error: "not_found" }, 404);
21578
21656
  const dispatched = await dispatchLocalSourcebookAcquisition(submission.id).catch(() => false);
21579
- return c.json({ ok: true, submission, acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(submission.websiteUrl) }, 202);
21657
+ return c.json({ ok: true, submission, publicUrls: localSourcebookPublicationLinks(submission), acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(submission.websiteUrl) }, 202);
21580
21658
  } catch (error) {
21581
21659
  return c.json({ error: "moderated_listing", message: error instanceof Error ? error.message : String(error) }, 409);
21582
21660
  }
21583
21661
  });
21584
21662
  var publicLocalSourcebookApp = new Hono17();
21585
- publicLocalSourcebookApp.get("/:category/:state", async (c) => c.json({ ok: true, listings: await listPublicLocalSourcebook(c.req.param("category"), c.req.param("state").toLowerCase()) }));
21663
+ publicLocalSourcebookApp.get("/", async (c) => c.json({ ok: true, listings: (await listAllPublicLocalSourcebook()).map(withCanonicalLocalSourcebookUrls) }));
21664
+ publicLocalSourcebookApp.get("/:category", async (c) => c.json({ ok: true, listings: (await listAllPublicLocalSourcebook(c.req.param("category"))).map(withCanonicalLocalSourcebookUrls) }));
21665
+ publicLocalSourcebookApp.get("/:category/:state", async (c) => c.json({ ok: true, listings: (await listPublicLocalSourcebook(c.req.param("category"), c.req.param("state").toLowerCase())).map(withCanonicalLocalSourcebookUrls) }));
21586
21666
  publicLocalSourcebookApp.get("/:category/:state/:slug", async (c) => {
21587
21667
  const listing = await getPublicLocalSourcebook(c.req.param("category"), c.req.param("state").toLowerCase(), c.req.param("slug"));
21588
- return listing ? c.json({ ok: true, listing }) : c.json({ error: "not_found" }, 404);
21668
+ return listing ? c.json({ ok: true, listing: withCanonicalLocalSourcebookUrls(listing) }) : c.json({ error: "not_found" }, 404);
21589
21669
  });
21590
21670
  var adminLocalSourcebookApp = new Hono17();
21591
21671
  adminLocalSourcebookApp.use("*", adminAuth);
@@ -40959,4 +41039,4 @@ app.get("/blog/:slug/", (c) => {
40959
41039
  export {
40960
41040
  app
40961
41041
  };
40962
- //# sourceMappingURL=server-RTQUTQZE.js.map
41042
+ //# sourceMappingURL=server-W4JLSNKW.js.map