mcp-scraper 0.44.1 → 0.44.3

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.
@@ -24602,6 +24602,7 @@ function ensureLocalSourcebookSchema() {
24602
24602
  metadata_json TEXT NOT NULL DEFAULT '{}',
24603
24603
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
24604
24604
  )`);
24605
+ await publishEligibleEvidenceBackedLocalSourcebookRevisions(db);
24605
24606
  })().catch((error) => {
24606
24607
  schemaPromise3 = null;
24607
24608
  schemaDb3 = null;
@@ -24609,6 +24610,19 @@ function ensureLocalSourcebookSchema() {
24609
24610
  });
24610
24611
  return schemaPromise3;
24611
24612
  }
24613
+ async function publishEligibleEvidenceBackedLocalSourcebookRevisions(db = getDb()) {
24614
+ const result = await db.execute(`UPDATE local_sourcebook_submissions
24615
+ SET status = 'published', published_revision = draft_revision, updated_at = datetime('now')
24616
+ WHERE status = 'needs_review'
24617
+ AND EXISTS (
24618
+ SELECT 1 FROM local_sourcebook_revisions r
24619
+ WHERE r.submission_id = local_sourcebook_submissions.id
24620
+ AND r.revision = local_sourcebook_submissions.draft_revision
24621
+ AND r.actor_kind = 'system'
24622
+ AND r.actor_id = 'local-sourcebook-worker'
24623
+ )`);
24624
+ return Number(result.rowsAffected ?? 0);
24625
+ }
24612
24626
  function rowValue(row, key) {
24613
24627
  return row[key];
24614
24628
  }
@@ -24678,23 +24692,12 @@ async function getLocalSourcebookDraft(id, ownerUserId) {
24678
24692
  const result = await getDb().execute({ sql: `SELECT payload_json FROM local_sourcebook_revisions WHERE submission_id = ? AND revision = ?`, args: [id, submission.draftRevision] });
24679
24693
  return result.rows[0] ? parseJson2(result.rows[0].payload_json) : null;
24680
24694
  }
24681
- async function reviseLocalSourcebookDraft(id, ownerUserId, payload, baseRevision) {
24682
- const submission = await getLocalSourcebookSubmission(id, ownerUserId);
24683
- if (!submission) return null;
24684
- if (baseRevision !== void 0 && baseRevision !== submission.draftRevision) {
24685
- throw new Error(`Draft revision conflict: current revision is ${submission.draftRevision}, but the write targeted ${baseRevision}.`);
24686
- }
24687
- const revision = submission.draftRevision + 1;
24688
- await getDb().batch([
24689
- { sql: `INSERT INTO local_sourcebook_revisions (submission_id, revision, payload_json, actor_kind, actor_id) VALUES (?, ?, ?, 'owner', ?)`, args: [id, revision, JSON.stringify(payload), String(ownerUserId)] },
24690
- { sql: `UPDATE local_sourcebook_submissions SET draft_revision = ?, status = CASE WHEN status = 'published' THEN status ELSE 'needs_review' END, updated_at = datetime('now') WHERE id = ? AND owner_user_id = ?`, args: [revision, id, ownerUserId] }
24691
- ], "write");
24692
- await event(id, "draft.revised", "owner", String(ownerUserId), { revision });
24693
- return getLocalSourcebookSubmission(id, ownerUserId);
24694
- }
24695
24695
  async function queueLocalSourcebookRefresh(id, ownerUserId) {
24696
24696
  const existing = await getLocalSourcebookSubmission(id, ownerUserId);
24697
24697
  if (!existing) return null;
24698
+ if (existing.status === "rejected" || existing.status === "unpublished") {
24699
+ throw new Error(`A ${existing.status} Local Sourcebook listing cannot be refreshed by its owner.`);
24700
+ }
24698
24701
  const coverage = { ...existing.coverage, refreshRequestedAt: (/* @__PURE__ */ new Date()).toISOString() };
24699
24702
  await getDb().execute({ sql: `UPDATE local_sourcebook_submissions SET status = 'queued', coverage_json = ?, acquisition_claimed_at = NULL, acquisition_error = NULL, updated_at = datetime('now') WHERE id = ? AND owner_user_id = ?`, args: [JSON.stringify(coverage), id, ownerUserId] });
24700
24703
  await event(id, "enrichment.queued", "owner", String(ownerUserId));
@@ -24732,12 +24735,13 @@ async function completeLocalSourcebookAcquisition(id, payload, coverage, baseRev
24732
24735
  WHERE EXISTS (SELECT 1 FROM local_sourcebook_submissions WHERE id = ? AND status = 'enriching' AND draft_revision = ?)`,
24733
24736
  args: [id, revision, JSON.stringify(payload), id, expectedRevision]
24734
24737
  },
24735
- { sql: `UPDATE local_sourcebook_submissions SET draft_revision = ?, status = 'needs_review', coverage_json = ?, acquisition_claimed_at = NULL, acquisition_error = NULL, updated_at = datetime('now') WHERE id = ? AND status = 'enriching' AND draft_revision = ?`, args: [revision, JSON.stringify(coverage), id, expectedRevision] }
24738
+ { sql: `UPDATE local_sourcebook_submissions SET draft_revision = ?, published_revision = ?, status = 'published', coverage_json = ?, acquisition_claimed_at = NULL, acquisition_error = NULL, updated_at = datetime('now') WHERE id = ? AND status = 'enriching' AND draft_revision = ?`, args: [revision, revision, JSON.stringify(coverage), id, expectedRevision] }
24736
24739
  ], "write");
24737
24740
  if (Number(results[0]?.rowsAffected ?? 0) !== 1 || Number(results[1]?.rowsAffected ?? 0) !== 1) {
24738
24741
  throw new Error(`Local Sourcebook acquisition revision conflict: revision ${expectedRevision} changed before completion.`);
24739
24742
  }
24740
24743
  await event(id, "enrichment.completed", "system", "local-sourcebook-worker", { revision, coverage });
24744
+ await event(id, "publication.auto_published", "system", "local-sourcebook-worker", { revision });
24741
24745
  return getLocalSourcebookSubmission(id);
24742
24746
  }
24743
24747
  async function failLocalSourcebookAcquisition(id, message) {
@@ -24760,6 +24764,15 @@ async function listQueuedLocalSourcebookSubmissionIds(limit = 25) {
24760
24764
  async function publishLocalSourcebookSubmission(id) {
24761
24765
  const submission = await getLocalSourcebookSubmission(id);
24762
24766
  if (!submission) return null;
24767
+ const revision = await getDb().execute({
24768
+ sql: `SELECT actor_kind, actor_id FROM local_sourcebook_revisions WHERE submission_id = ? AND revision = ? LIMIT 1`,
24769
+ args: [id, submission.draftRevision]
24770
+ });
24771
+ const actorKind = revision.rows[0] ? String(revision.rows[0].actor_kind) : "";
24772
+ const actorId = revision.rows[0] ? String(revision.rows[0].actor_id) : "";
24773
+ if (actorKind !== "system" || actorId !== "local-sourcebook-worker") {
24774
+ throw new Error("Only a system-compiled Local Sourcebook revision can be published.");
24775
+ }
24763
24776
  await getDb().execute({ sql: `UPDATE local_sourcebook_submissions SET status = 'published', published_revision = draft_revision, updated_at = datetime('now') WHERE id = ?`, args: [id] });
24764
24777
  await event(id, "publication.published", "admin", "admin", { revision: submission.draftRevision });
24765
24778
  return getLocalSourcebookSubmission(id);
@@ -24776,6 +24789,14 @@ async function listPublicLocalSourcebook(category, state) {
24776
24789
  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] });
24777
24790
  return result.rows.map((row) => parseJson2(row.payload_json));
24778
24791
  }
24792
+ async function listAllPublicLocalSourcebook(category) {
24793
+ await ensureLocalSourcebookSchema();
24794
+ const result = category ? await getDb().execute({
24795
+ 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`,
24796
+ args: [category]
24797
+ }) : 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`);
24798
+ return result.rows.map((row) => parseJson2(row.payload_json));
24799
+ }
24779
24800
  async function getPublicLocalSourcebook(category, state, slug2) {
24780
24801
  await ensureLocalSourcebookSchema();
24781
24802
  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] });
@@ -25431,6 +25452,41 @@ var init_MapsExtractor = __esm({
25431
25452
  }
25432
25453
  });
25433
25454
 
25455
+ // src/api/local-sourcebook-public-urls.ts
25456
+ function rootDomain() {
25457
+ const configured = process.env.LOCAL_SOURCEBOOK_PUBLIC_ROOT_DOMAIN?.trim() || DEFAULT_ROOT_DOMAIN;
25458
+ return configured.replace(/^https?:\/\//i, "").replace(/^www\./i, "").replace(/\/.*$/, "").replace(/\.+$/, "").toLowerCase();
25459
+ }
25460
+ function localSourcebookPublicUrls(category, state, slug2) {
25461
+ const categoryUrl = `https://${category}.${rootDomain()}`;
25462
+ const statePath = `/${state.toLowerCase()}`;
25463
+ const profilePath = `${statePath}/${slug2}/`;
25464
+ const reviewsPath = `${statePath}/${slug2}/reviews`;
25465
+ return {
25466
+ categoryUrl,
25467
+ nationwideDirectoryUrl: `${categoryUrl}/directory`,
25468
+ stateUrl: `${categoryUrl}${statePath}`,
25469
+ profileUrl: `${categoryUrl}${profilePath}`,
25470
+ reviewsUrl: `${categoryUrl}${reviewsPath}`,
25471
+ profilePath,
25472
+ reviewsPath
25473
+ };
25474
+ }
25475
+ function localSourcebookPublicationLinks(submission) {
25476
+ return {
25477
+ ...localSourcebookPublicUrls(submission.category, submission.state, submission.slug),
25478
+ publicationStatus: submission.status,
25479
+ isLive: submission.status === "published" && submission.publishedRevision !== null
25480
+ };
25481
+ }
25482
+ var DEFAULT_ROOT_DOMAIN;
25483
+ var init_local_sourcebook_public_urls = __esm({
25484
+ "src/api/local-sourcebook-public-urls.ts"() {
25485
+ "use strict";
25486
+ DEFAULT_ROOT_DOMAIN = "localsourcebook.com";
25487
+ }
25488
+ });
25489
+
25434
25490
  // src/api/local-sourcebook-compiler.ts
25435
25491
  function digest(value) {
25436
25492
  return (0, import_node_crypto13.createHash)("sha256").update(value).digest("hex").slice(0, 20);
@@ -25706,6 +25762,7 @@ function compileLocalSourcebookListing(input) {
25706
25762
  evidenceIds: mapsEvidenceId ? [mapsEvidenceId] : []
25707
25763
  }
25708
25764
  ];
25765
+ const publicUrls = localSourcebookPublicUrls(input.submission.category, input.submission.state, input.submission.slug);
25709
25766
  const listing = {
25710
25767
  id: input.submission.id,
25711
25768
  publicationRevision: input.submission.draftRevision + 1,
@@ -25714,6 +25771,14 @@ function compileLocalSourcebookListing(input) {
25714
25771
  state: input.submission.state.toLowerCase(),
25715
25772
  stateName: STATE_NAMES[input.submission.state.toUpperCase()] ?? input.submission.state.toUpperCase(),
25716
25773
  slug: input.submission.slug,
25774
+ canonicalPaths: {
25775
+ profile: publicUrls.profilePath,
25776
+ reviews: publicUrls.reviewsPath
25777
+ },
25778
+ canonicalUrls: {
25779
+ profile: publicUrls.profileUrl,
25780
+ reviews: publicUrls.reviewsUrl
25781
+ },
25717
25782
  name: maps?.name || input.submission.businessName,
25718
25783
  summary,
25719
25784
  description,
@@ -25777,6 +25842,7 @@ var init_local_sourcebook_compiler = __esm({
25777
25842
  "src/api/local-sourcebook-compiler.ts"() {
25778
25843
  "use strict";
25779
25844
  import_node_crypto13 = require("crypto");
25845
+ init_local_sourcebook_public_urls();
25780
25846
  CATEGORY_LABELS = {
25781
25847
  home: "Home & property services",
25782
25848
  professional: "Professional services",
@@ -26016,11 +26082,12 @@ async function runLocalSourcebookAcquisition(submission, provider = createDefaul
26016
26082
  await logRequestEvent({ userId: submission.ownerUserId, source: "local_sourcebook_maps", status: "done", query: submission.businessName, location: submission.state.toUpperCase(), resultCount: maps.reviews.length, result: { submissionId: submission.id, placeUrl: maps.placeUrl, cid: maps.cidDecimal ?? maps.cid, reviewsStatus: maps.reviewsStatus, reviewsRetained: maps.reviews.length, services: maps.services.length, areasServed: maps.areasServed.length } });
26017
26083
  } catch (error) {
26018
26084
  mapsError = errorMessage2(error);
26085
+ maps = null;
26019
26086
  await creditMcIdempotent(submission.ownerUserId, MC_COSTS.maps_place, LedgerOperation.REFUND, `Local Sourcebook failed exact-place acquisition: ${submission.id}`, `${billingCycle}:maps-failure-refund`);
26020
26087
  mapsRefunded = true;
26021
26088
  await logRequestEvent({ userId: submission.ownerUserId, source: "local_sourcebook_maps", status: "failed", query: submission.businessName, location: submission.state.toUpperCase(), error: mapsError });
26022
26089
  }
26023
- if (!site && !maps) throw new Error(`Website and exact-place acquisition both failed. Website: ${siteError || "not available"}. Maps: ${mapsError || "not available"}.`);
26090
+ if (!maps) throw new Error(`Exact-place acquisition is required before publication. Maps: ${mapsError || "not available"}. Website: ${siteError || (site ? "captured" : "not available")}.`);
26024
26091
  const compiled = compileLocalSourcebookListing({
26025
26092
  submission,
26026
26093
  site,
@@ -36602,18 +36669,22 @@ async function resolveLocalSourcebookTags(candidates) {
36602
36669
  function getLocalSourcebookContract(category) {
36603
36670
  return {
36604
36671
  name: "Local Sourcebook listing",
36605
- version: "local_sourcebook_listing_v1",
36672
+ version: "local_sourcebook_listing_v2",
36606
36673
  purpose: "An owner-scoped, evidence-backed local business record with a separate public profile and complete captured-review archive.",
36607
36674
  categories: LOCAL_SOURCEBOOK_CATEGORIES,
36608
36675
  selectedCategory: category ?? null,
36609
36676
  categoryTag: category ? CATEGORY_TAG[category] : null,
36610
- canonicalRoutes: { profile: "/{state}/{business-slug}/", reviews: "/{state}/{business-slug}/reviews" },
36677
+ canonicalRoutes: {
36678
+ nationwideDirectory: "https://{category}.localsourcebook.com/directory",
36679
+ profile: "https://{category}.localsourcebook.com/{state}/{business-slug}/",
36680
+ reviews: "https://{category}.localsourcebook.com/{state}/{business-slug}/reviews"
36681
+ },
36611
36682
  requiredCreateFields: ["category", "state", "businessName", "websiteUrl", "tags", "idempotencyKey"],
36612
- requiredDraftSections: ["identity", "services/products", "service areas/locations", "genuine media", "reviews and theme counts", "evidence", "answered FAQ", "collection receipts"],
36683
+ systemCompiledSections: ["identity", "services/products", "service areas/locations", "genuine media", "reviews and theme counts", "evidence", "answered FAQ", "collection receipts"],
36613
36684
  workflow: ["list-local-sourcebook-tags", "get-local-sourcebook-contract", "prepare-local-sourcebook-write", "validate-local-sourcebook-write", "local-sourcebook-capture", "local_sourcebook_submission_status"],
36614
- ownership: "Only the MCP Scraper account that captures a listing can read or revise its draft.",
36685
+ ownership: "Only the MCP Scraper account that captures a listing can read it or request a paid evidence refresh.",
36615
36686
  acquisition: { websitePagesMaximum: 100, reviewsMaximum: 500, exactMapsIdentityRequired: true, partialResultsRequireStoppingReasons: true },
36616
- publication: { automatic: false, adminReviewRequired: true, lastPublishedRevisionRemainsPublicDuringRefresh: true },
36687
+ publication: { automatic: true, evidenceCompiledOnly: true, ownerAuthoredClaimsAccepted: false, adminReviewRequired: false, lastPublishedRevisionRemainsPublicDuringRefresh: true },
36617
36688
  tagPolicy: { inspectVocabularyFirst: true, minimum: 1, maximum: 20, newTagsRequire: ["central=true", "reusable=true", "description"], newTagsStartAs: "pending" }
36618
36689
  };
36619
36690
  }
@@ -36627,16 +36698,18 @@ async function prepareLocalSourcebookWrite(input) {
36627
36698
  ...parsed.tags.filter((tag) => tag !== categoryTag).map((tag) => ({ tag }))
36628
36699
  ];
36629
36700
  const tagResolutions = await resolveLocalSourcebookTags(candidates);
36701
+ const publicUrls = localSourcebookPublicUrls(parsed.category, parsed.state, slug2);
36630
36702
  return {
36631
36703
  ok: true,
36632
- route: { category: parsed.category, state: parsed.state, slug: slug2, profile: `/${parsed.state}/${slug2}/`, reviews: `/${parsed.state}/${slug2}/reviews` },
36704
+ route: { category: parsed.category, state: parsed.state, slug: slug2, ...publicUrls },
36633
36705
  proposedWrite: { ...parsed, slug: slug2, tags: tagResolutions.filter((item) => item.action === "reuse").map((item) => item.tag) },
36634
36706
  contract: getLocalSourcebookContract(parsed.category),
36635
36707
  tagResolutions,
36636
36708
  instructions: [
36637
36709
  "Resolve every review candidate before capture; do not silently create a near-duplicate tag.",
36638
36710
  "Call validate-local-sourcebook-write with the proposed identity, resolved tags, and any required tag decisions.",
36639
- "Call local-sourcebook-capture only after validation returns valid=true. Capture creates a private draft and queues paid acquisition; it does not publish."
36711
+ "Call local-sourcebook-capture only after validation returns valid=true. Capture queues paid acquisition and automatically publishes the resulting system-compiled evidence revision.",
36712
+ "Owners cannot supply public listing claims directly. Request local_sourcebook_refresh when source-backed public facts need to be reacquired."
36640
36713
  ]
36641
36714
  };
36642
36715
  }
@@ -36644,17 +36717,9 @@ async function validateLocalSourcebookWrite(input) {
36644
36717
  const errors = [];
36645
36718
  const warnings = [];
36646
36719
  let normalizedIdentity2;
36647
- let normalizedListing;
36648
- if (input.submissionId) {
36649
- if (!Number.isInteger(input.baseRevision) || Number(input.baseRevision) < 1) errors.push("baseRevision is required for an existing draft edit.");
36650
- const parsedListing = DirectoryListingDraftSchema.safeParse(input.listing);
36651
- if (!parsedListing.success) errors.push(...parsedListing.error.issues.map((issue) => `listing.${issue.path.join(".")}: ${issue.message}`));
36652
- else normalizedListing = parsedListing.data;
36653
- } else {
36654
- const parsedIdentity = DirectoryIdentitySchema.safeParse(input.identity);
36655
- if (!parsedIdentity.success) errors.push(...parsedIdentity.error.issues.map((issue) => `identity.${issue.path.join(".")}: ${issue.message}`));
36656
- else normalizedIdentity2 = parsedIdentity.data;
36657
- }
36720
+ const parsedIdentity = DirectoryIdentitySchema.safeParse(input.identity);
36721
+ if (!parsedIdentity.success) errors.push(...parsedIdentity.error.issues.map((issue) => `identity.${issue.path.join(".")}: ${issue.message}`));
36722
+ else normalizedIdentity2 = parsedIdentity.data;
36658
36723
  const candidates = input.tagCandidates ?? (normalizedIdentity2?.tags.map((tag) => ({ tag })) ?? []);
36659
36724
  const resolutions = await resolveLocalSourcebookTags(candidates);
36660
36725
  const decisions = new Map((input.tagDecisions ?? []).map((decision) => [normalizeTag(decision.tag), decision]));
@@ -36673,12 +36738,12 @@ async function validateLocalSourcebookWrite(input) {
36673
36738
  }
36674
36739
  if (resolution2.action === "omit") warnings.push(`Tag \u201C${resolution2.candidate}\u201D will be omitted: ${resolution2.reason}`);
36675
36740
  }
36676
- if (!input.submissionId && normalizedIdentity2) {
36741
+ if (normalizedIdentity2) {
36677
36742
  const categoryTag = CATEGORY_TAG[normalizedIdentity2.category];
36678
36743
  if (!normalizedTags.includes(categoryTag)) normalizedTags.unshift(categoryTag);
36679
36744
  }
36680
36745
  if (!normalizedTags.length) errors.push("At least one canonical directory tag is required.");
36681
- return { ok: true, valid: errors.length === 0, errors, warnings, normalizedIdentity: normalizedIdentity2, normalizedListing, normalizedTags: [...new Set(normalizedTags)], tagResolutions: resolutions };
36746
+ return { ok: true, valid: errors.length === 0, errors, warnings, normalizedIdentity: normalizedIdentity2, normalizedTags: [...new Set(normalizedTags)], tagResolutions: resolutions };
36682
36747
  }
36683
36748
  async function persistLocalSourcebookTags(submissionId, userId, tags, decisions = []) {
36684
36749
  await ensureLocalSourcebookTags();
@@ -36695,18 +36760,14 @@ async function persistLocalSourcebookTags(submissionId, userId, tags, decisions
36695
36760
  await db.execute({ sql: `INSERT OR IGNORE INTO local_sourcebook_submission_tags (submission_id, tag) VALUES (?, ?)`, args: [submissionId, tag] });
36696
36761
  }
36697
36762
  }
36698
- async function replaceLocalSourcebookTags(submissionId, userId, tags, decisions = []) {
36699
- await ensureLocalSourcebookTags();
36700
- await getDb().execute({ sql: `DELETE FROM local_sourcebook_submission_tags WHERE submission_id = ?`, args: [submissionId] });
36701
- await persistLocalSourcebookTags(submissionId, userId, tags, decisions);
36702
- }
36703
- var import_zod29, DIRECTORY_TAG_SEEDS, CATEGORY_TAG, DirectoryTagCandidateSchema, DirectoryTagDecisionSchema, DirectoryIdentitySchema, DirectoryListingDraftSchema;
36763
+ var import_zod29, DIRECTORY_TAG_SEEDS, CATEGORY_TAG, DirectoryTagCandidateSchema, DirectoryTagDecisionSchema, DirectoryIdentitySchema;
36704
36764
  var init_local_sourcebook_governance = __esm({
36705
36765
  "src/api/local-sourcebook-governance.ts"() {
36706
36766
  "use strict";
36707
36767
  import_zod29 = require("zod");
36708
36768
  init_db();
36709
36769
  init_local_sourcebook_repository();
36770
+ init_local_sourcebook_public_urls();
36710
36771
  DIRECTORY_TAG_SEEDS = [
36711
36772
  { tag: "home-services", description: "Businesses that maintain, repair, improve, or protect homes and property.", aliases: ["home service", "home and property services"] },
36712
36773
  { tag: "professional-services", description: "Local professional and business service providers.", aliases: ["professional service"] },
@@ -36753,23 +36814,6 @@ var init_local_sourcebook_governance = __esm({
36753
36814
  tags: import_zod29.z.array(import_zod29.z.string().trim().min(1).max(60)).max(20).default([]),
36754
36815
  idempotencyKey: import_zod29.z.string().trim().min(8).max(200)
36755
36816
  });
36756
- DirectoryListingDraftSchema = import_zod29.z.object({
36757
- id: import_zod29.z.string().min(1),
36758
- category: import_zod29.z.enum(LOCAL_SOURCEBOOK_CATEGORIES),
36759
- state: import_zod29.z.string().trim().length(2),
36760
- slug: import_zod29.z.string().trim().min(1),
36761
- name: import_zod29.z.string().trim().min(2),
36762
- summary: import_zod29.z.string().trim().min(20),
36763
- description: import_zod29.z.string().trim().min(20),
36764
- website: import_zod29.z.url(),
36765
- services: import_zod29.z.array(import_zod29.z.string()),
36766
- products: import_zod29.z.array(import_zod29.z.string()),
36767
- serviceAreas: import_zod29.z.array(import_zod29.z.string()),
36768
- media: import_zod29.z.array(import_zod29.z.record(import_zod29.z.string(), import_zod29.z.unknown())),
36769
- reviews: import_zod29.z.array(import_zod29.z.record(import_zod29.z.string(), import_zod29.z.unknown())),
36770
- evidence: import_zod29.z.array(import_zod29.z.record(import_zod29.z.string(), import_zod29.z.unknown())),
36771
- faq: import_zod29.z.array(import_zod29.z.object({ question: import_zod29.z.string().min(3), answer: import_zod29.z.string().min(12), evidenceIds: import_zod29.z.array(import_zod29.z.string()) }))
36772
- }).passthrough();
36773
36817
  }
36774
36818
  });
36775
36819
 
@@ -36779,10 +36823,10 @@ function acquisitionPlan(websiteUrl) {
36779
36823
  website: { startUrl: websiteUrl, mode: "broad_site_crawl", capture: ["homepage", "services", "products", "locations", "service_areas", "about", "team_staff", "contact", "policies"] },
36780
36824
  media: { requirement: "genuine_business_images_only", sources: ["business_website", "business_team_pages", "verified_business_profiles"] },
36781
36825
  reviews: { mode: "exhaust_accessible_continuation", requirement: "retain_each_review_and_source", disclosure: "report captured count, reported available count, and exact stopping reason" },
36782
- publication: { automatic: false, adminReviewRequired: true }
36826
+ publication: { automatic: true, evidenceCompiledOnly: true, adminReviewRequired: false }
36783
36827
  };
36784
36828
  }
36785
- var import_hono17, import_zod30, slug, SubmitSchema, DraftSchema, PrepareWriteSchema, ValidateWriteSchema, CaptureWriteSchema, localSourcebookApp, publicLocalSourcebookApp, adminLocalSourcebookApp;
36829
+ var import_hono17, import_zod30, slug, SubmitSchema, PrepareWriteSchema, ValidateWriteSchema, CaptureWriteSchema, localSourcebookApp, publicLocalSourcebookApp, adminLocalSourcebookApp;
36786
36830
  var init_local_sourcebook_routes = __esm({
36787
36831
  "src/api/local-sourcebook-routes.ts"() {
36788
36832
  "use strict";
@@ -36793,6 +36837,7 @@ var init_local_sourcebook_routes = __esm({
36793
36837
  init_local_sourcebook_dispatch();
36794
36838
  init_local_sourcebook_governance();
36795
36839
  init_local_sourcebook_repository();
36840
+ init_local_sourcebook_public_urls();
36796
36841
  slug = (value) => value.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 100);
36797
36842
  SubmitSchema = import_zod30.z.object({
36798
36843
  category: import_zod30.z.enum(LOCAL_SOURCEBOOK_CATEGORIES),
@@ -36802,13 +36847,9 @@ var init_local_sourcebook_routes = __esm({
36802
36847
  slug: import_zod30.z.string().trim().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).max(100).optional(),
36803
36848
  idempotencyKey: import_zod30.z.string().trim().min(8).max(200).optional()
36804
36849
  }).strict();
36805
- DraftSchema = import_zod30.z.object({ payload: import_zod30.z.record(import_zod30.z.string(), import_zod30.z.unknown()) }).strict();
36806
36850
  PrepareWriteSchema = DirectoryIdentitySchema.extend({ tagCandidates: import_zod30.z.array(DirectoryTagCandidateSchema).max(20).optional() });
36807
36851
  ValidateWriteSchema = import_zod30.z.object({
36808
36852
  identity: DirectoryIdentitySchema.optional(),
36809
- listing: import_zod30.z.record(import_zod30.z.string(), import_zod30.z.unknown()).optional(),
36810
- submissionId: import_zod30.z.string().trim().min(1).optional(),
36811
- baseRevision: import_zod30.z.number().int().min(1).optional(),
36812
36853
  tagCandidates: import_zod30.z.array(DirectoryTagCandidateSchema).max(20).optional(),
36813
36854
  tagDecisions: import_zod30.z.array(DirectoryTagDecisionSchema).max(20).optional()
36814
36855
  }).strict();
@@ -36840,18 +36881,12 @@ var init_local_sourcebook_routes = __esm({
36840
36881
  const validation = await validateLocalSourcebookWrite(parsed.data);
36841
36882
  if (!validation.valid) return c.json({ error: "invalid_directory_write", ...validation }, 400);
36842
36883
  try {
36843
- if (parsed.data.submissionId) {
36844
- const submission2 = await getLocalSourcebookSubmission(parsed.data.submissionId, Number(user.id));
36845
- if (!submission2) return c.json({ error: "not_found" }, 404);
36846
- const updated = await reviseLocalSourcebookDraft(submission2.id, Number(user.id), validation.normalizedListing, parsed.data.baseRevision);
36847
- await replaceLocalSourcebookTags(submission2.id, Number(user.id), validation.normalizedTags, parsed.data.tagDecisions);
36848
- return c.json({ ok: true, valid: true, submission: updated, normalizedTags: validation.normalizedTags, captured: "draft_revision", acquisitionQueued: false });
36849
- }
36850
36884
  const identity = validation.normalizedIdentity;
36851
36885
  if (!parsed.data.idempotencyKey && !identity.idempotencyKey) {
36852
36886
  return c.json({ error: "idempotency_key_required", message: "A stable idempotencyKey is required for a new Local Sourcebook capture." }, 400);
36853
36887
  }
36854
36888
  const listingSlug = identity.slug ?? slug(identity.businessName);
36889
+ const publicUrls = localSourcebookPublicUrls(identity.category, identity.state, listingSlug);
36855
36890
  const submission = await createLocalSourcebookSubmission({
36856
36891
  ownerUserId: Number(user.id),
36857
36892
  category: identity.category,
@@ -36868,7 +36903,8 @@ var init_local_sourcebook_routes = __esm({
36868
36903
  name: identity.businessName,
36869
36904
  websiteUrl: identity.websiteUrl,
36870
36905
  tags: validation.normalizedTags,
36871
- canonicalPaths: { profile: `/${identity.state}/${listingSlug}`, reviews: `/${identity.state}/${listingSlug}/reviews` },
36906
+ canonicalPaths: { profile: publicUrls.profilePath, reviews: publicUrls.reviewsPath },
36907
+ canonicalUrls: { profile: publicUrls.profileUrl, reviews: publicUrls.reviewsUrl },
36872
36908
  verificationState: "submitted",
36873
36909
  acquisitionPlan: acquisitionPlan(identity.websiteUrl),
36874
36910
  evidence: [],
@@ -36878,7 +36914,7 @@ var init_local_sourcebook_routes = __esm({
36878
36914
  });
36879
36915
  await persistLocalSourcebookTags(submission.id, Number(user.id), validation.normalizedTags, parsed.data.tagDecisions);
36880
36916
  const dispatched = await dispatchLocalSourcebookAcquisition(submission.id).catch(() => false);
36881
- return c.json({ ok: true, valid: true, submission, normalizedTags: validation.normalizedTags, acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(identity.websiteUrl) }, 202);
36917
+ return c.json({ ok: true, valid: true, submission, publicUrls: localSourcebookPublicationLinks(submission), normalizedTags: validation.normalizedTags, acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(identity.websiteUrl) }, 202);
36882
36918
  } catch (error) {
36883
36919
  const message = error instanceof Error ? error.message : String(error);
36884
36920
  const conflict = message.includes("revision conflict") ? "revision_conflict" : message.includes("idempotency key conflicts") ? "idempotency_conflict" : null;
@@ -36892,6 +36928,7 @@ var init_local_sourcebook_routes = __esm({
36892
36928
  if (!parsed.success) return c.json({ error: "invalid_submission", issues: parsed.error.issues }, 400);
36893
36929
  const input = parsed.data;
36894
36930
  const listingSlug = input.slug ?? slug(input.businessName);
36931
+ const publicUrls = localSourcebookPublicUrls(input.category, input.state, listingSlug);
36895
36932
  try {
36896
36933
  const submission = await createLocalSourcebookSubmission({
36897
36934
  ownerUserId: Number(user.id),
@@ -36904,7 +36941,8 @@ var init_local_sourcebook_routes = __esm({
36904
36941
  slug: listingSlug,
36905
36942
  name: input.businessName,
36906
36943
  websiteUrl: input.websiteUrl,
36907
- canonicalPaths: { profile: `/${input.state}/${listingSlug}`, reviews: `/${input.state}/${listingSlug}/reviews` },
36944
+ canonicalPaths: { profile: publicUrls.profilePath, reviews: publicUrls.reviewsPath },
36945
+ canonicalUrls: { profile: publicUrls.profileUrl, reviews: publicUrls.reviewsUrl },
36908
36946
  verificationState: "submitted",
36909
36947
  acquisitionPlan: acquisitionPlan(input.websiteUrl),
36910
36948
  evidence: [],
@@ -36913,7 +36951,7 @@ var init_local_sourcebook_routes = __esm({
36913
36951
  }
36914
36952
  });
36915
36953
  const dispatched = await dispatchLocalSourcebookAcquisition(submission.id).catch(() => false);
36916
- return c.json({ ok: true, submission, acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(input.websiteUrl) }, 202);
36954
+ return c.json({ ok: true, submission, publicUrls: localSourcebookPublicationLinks(submission), acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(input.websiteUrl) }, 202);
36917
36955
  } catch (error) {
36918
36956
  return c.json({ error: "submission_conflict", message: error instanceof Error ? error.message : String(error) }, 409);
36919
36957
  }
@@ -36922,26 +36960,27 @@ var init_local_sourcebook_routes = __esm({
36922
36960
  const userId = Number(c.get("user").id);
36923
36961
  const submission = await getLocalSourcebookSubmission(c.req.param("id"), userId);
36924
36962
  if (!submission) return c.json({ error: "not_found" }, 404);
36925
- return c.json({ ok: true, submission, draft: await getLocalSourcebookDraft(submission.id, userId) });
36926
- });
36927
- localSourcebookApp.on(["PATCH", "POST"], "/submissions/:id/draft", createApiKeyAuth(), async (c) => {
36928
- const user = c.get("user");
36929
- if (!user.subscription_tier) return c.json({ error: "subscription_required" }, 402);
36930
- const parsed = DraftSchema.safeParse(await c.req.json().catch(() => null));
36931
- if (!parsed.success) return c.json({ error: "invalid_draft", issues: parsed.error.issues }, 400);
36932
- const submission = await reviseLocalSourcebookDraft(c.req.param("id"), Number(user.id), parsed.data.payload);
36933
- if (!submission) return c.json({ error: "not_found" }, 404);
36934
- return c.json({ ok: true, submission });
36963
+ return c.json({ ok: true, submission, publicUrls: localSourcebookPublicationLinks(submission), draft: await getLocalSourcebookDraft(submission.id, userId) });
36935
36964
  });
36965
+ localSourcebookApp.on(["PATCH", "POST"], "/submissions/:id/draft", createApiKeyAuth(), (c) => c.json({
36966
+ error: "evidence_refresh_required",
36967
+ message: "Owner-authored listing payloads are not accepted. Request a refresh so MCP Scraper can reacquire and compile the public evidence."
36968
+ }, 409));
36936
36969
  localSourcebookApp.post("/submissions/:id/refresh", createApiKeyAuth(), async (c) => {
36937
36970
  const user = c.get("user");
36938
36971
  if (!user.subscription_tier) return c.json({ error: "subscription_required" }, 402);
36939
- const submission = await queueLocalSourcebookRefresh(c.req.param("id"), Number(user.id));
36940
- if (!submission) return c.json({ error: "not_found" }, 404);
36941
- const dispatched = await dispatchLocalSourcebookAcquisition(submission.id).catch(() => false);
36942
- return c.json({ ok: true, submission, acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(submission.websiteUrl) }, 202);
36972
+ try {
36973
+ const submission = await queueLocalSourcebookRefresh(c.req.param("id"), Number(user.id));
36974
+ if (!submission) return c.json({ error: "not_found" }, 404);
36975
+ const dispatched = await dispatchLocalSourcebookAcquisition(submission.id).catch(() => false);
36976
+ return c.json({ ok: true, submission, publicUrls: localSourcebookPublicationLinks(submission), acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(submission.websiteUrl) }, 202);
36977
+ } catch (error) {
36978
+ return c.json({ error: "moderated_listing", message: error instanceof Error ? error.message : String(error) }, 409);
36979
+ }
36943
36980
  });
36944
36981
  publicLocalSourcebookApp = new import_hono17.Hono();
36982
+ publicLocalSourcebookApp.get("/", async (c) => c.json({ ok: true, listings: await listAllPublicLocalSourcebook() }));
36983
+ publicLocalSourcebookApp.get("/:category", async (c) => c.json({ ok: true, listings: await listAllPublicLocalSourcebook(c.req.param("category")) }));
36945
36984
  publicLocalSourcebookApp.get("/:category/:state", async (c) => c.json({ ok: true, listings: await listPublicLocalSourcebook(c.req.param("category"), c.req.param("state").toLowerCase()) }));
36946
36985
  publicLocalSourcebookApp.get("/:category/:state/:slug", async (c) => {
36947
36986
  const listing = await getPublicLocalSourcebook(c.req.param("category"), c.req.param("state").toLowerCase(), c.req.param("slug"));
@@ -40959,7 +40998,7 @@ var PACKAGE_VERSION;
40959
40998
  var init_version = __esm({
40960
40999
  "src/version.ts"() {
40961
41000
  "use strict";
40962
- PACKAGE_VERSION = "0.44.1";
41001
+ PACKAGE_VERSION = "0.44.3";
40963
41002
  }
40964
41003
  });
40965
41004
 
@@ -41125,13 +41164,15 @@ Multi-step orchestrations \u2014 prefer these over hand-chaining primitives when
41125
41164
  **get-local-sourcebook-contract**, then **prepare-local-sourcebook-write**, inspect every tag resolution,
41126
41165
  and call **validate-local-sourcebook-write**. Call **local-sourcebook-capture** only when validation returns
41127
41166
  \`valid:true\`.
41128
- - A new capture creates an owner-scoped private draft and queues paid broad website, exact Maps place,
41129
- maximum-accessible review, service-area, staff, and genuine-media acquisition. It does not publish.
41130
- - Read progress and the compiled draft with **local_sourcebook_submission_status**. Revise an existing draft
41131
- through **validate-local-sourcebook-write** and **local-sourcebook-capture** with its current \`baseRevision\`.
41132
- Use **local_sourcebook_refresh** only when the owner intentionally wants to pay for a new acquisition pass.
41133
- - The last approved revision remains public during refresh. Only an administrator can publish, reject, or
41134
- unpublish a listing.
41167
+ - A new capture queues paid broad website, exact Maps place, maximum-accessible review, service-area, staff,
41168
+ and genuine-media acquisition. When compilation succeeds, that exact system-authored evidence revision
41169
+ publishes automatically. Never supply owner-authored services, reviews, images, or other public claims.
41170
+ - Read progress and the compiled record with **local_sourcebook_submission_status**. Use
41171
+ **local_sourcebook_refresh** only when the owner intentionally wants to pay for a new acquisition pass.
41172
+ - Capture and status responses return \`publicUrls.profileUrl\` and \`publicUrls.reviewsUrl\`. Always give those
41173
+ exact links to the user; do not report a listing as live without including its clickable profile URL.
41174
+ - The last published revision remains public during refresh. Administrators can reject or unpublish an
41175
+ exceptional record, but routine subscriber publication does not require administrator review.
41135
41176
 
41136
41177
  ## Notes
41137
41178
  - For current prices, balances, or limits, call \`credits_info\`. The public machine-readable rate contract is
@@ -41755,7 +41796,7 @@ var init_contracts = __esm({
41755
41796
  });
41756
41797
 
41757
41798
  // src/mcp/mcp-tool-schemas.ts
41758
- var import_zod41, WEBSITE_URL_OR_DOMAIN_ERROR, WebsiteUrlOrDomainSchema, HarvestPaaInputSchema, ExtractUrlBaseInputSchema, ExtractUrlInputSchema, ExtractUrlLocalInputSchema, DiffPageBaseInputSchema, DiffPageInputSchema, DiffPageLocalInputSchema, MapSiteUrlsInputSchema, MapWaybackSnapshotsInputSchema, ExtractSiteInputSchema, AuditSiteInputSchema, CheckSiteExportInputSchema, ArchiveReadInputSchema, YoutubeHarvestInputSchema, YoutubeTranscribeInputSchema, FacebookPageIntelInputSchema, FacebookAdSearchInputSchema, RedditThreadInputSchema, RedditTrendingInputSchema, VideoFrameAnalysisInputSchema, VideoFrameAnalysisStatusInputSchema, FacebookAdTranscribeInputSchema, FacebookVideoTranscribeInputSchema, GoogleAdsSearchInputSchema, GoogleAdsPageIntelInputSchema, GoogleAdsTranscribeInputSchema, InstagramProfileContentInputSchema, InstagramMediaDownloadInputSchema, MapsPlaceIntelInputSchema, TrustpilotReviewsInputSchema, G2ReviewsInputSchema, ReviewCardSchema, MapsSearchInputSchema, DirectoryWorkflowInputSchema, LocationMarketsInputSchema, CommonsSearchEntitiesInputSchema, CommonsGetEntityInputSchema, CommonsFeaturedImageInputSchema, CommonsMediaInputSchema, CommonsCitationInputSchema, CommonsSourceInputSchema, CommonsRelatedLinkInputSchema, CommonsPrepareEntityInputSchema, CommonsSubmitEntityInputSchema, CommonsValidateEntityInputSchema, CommonsGetEntityLedgerInputSchema, CommonsSaveFilterInputSchema, CommonsListFiltersInputSchema, CommonsListNeedsLinksInputSchema, CommonsGenericOutputSchema, DirectoryWorkflowStatusInputSchema, LocalSourcebookSubmitInputSchema, LocalSourcebookCategorySchema, LocalSourcebookTagCandidateObjectSchema, LocalSourcebookTagDecisionObjectSchema, LocalSourcebookIdentityObjectSchema, GetLocalSourcebookContractInputSchema, ListLocalSourcebookTagsInputSchema, ResolveLocalSourcebookTagsInputSchema, PrepareLocalSourcebookWriteInputSchema, ValidateLocalSourcebookWriteInputSchema, LocalSourcebookCaptureInputSchema, LocalSourcebookSubmissionStatusInputSchema, LocalSourcebookUpdateDraftInputSchema, LocalSourcebookRefreshInputSchema, LocalSourcebookOutputSchema, ArtifactPointerOutputSchema, EditorialReadingRoomSiteSchema, EditorialReadingRoomArticleSchema, EditorialReadingRoomGuideInputSchema, EditorialReadingRoomGuideOutputSchema, CreateEditorialReadingRoomInputSchema, EditorialReadingRoomArtifactSchema, CreateEditorialReadingRoomOutputSchema, RenewEditorialReadingRoomDownloadInputSchema, RenewEditorialReadingRoomDownloadOutputSchema, RankTrackerModeSchema, RankTrackerBlueprintInputSchema, NullableString, MapsSearchAttemptOutput, MapsSearchOutputSchema, DirectoryMapsBusinessOutput, DirectoryCsvArtifactOutput, DirectoryWorkflowOutputSchema, LocationDatasetProvenanceOutput, LocationMarketsOutputSchema, RankTrackerToolPlanOutput, RankTrackerTableOutput, RankTrackerCronJobOutput, RankTrackerBlueprintOutputSchema, OrganicResultOutput, AiOverviewOutput, EntityIdsOutput, HarvestPaaOutputSchema, SearchSerpOutputSchema, ExtractUrlOutputSchema, DiffPageOutputSchema, ExtractSiteOutputSchema, AuditSiteOutputSchema, CheckSiteExportOutputSchema, ArchiveEntryOutputSchema, ArchiveReadOutputSchema, MapsPlaceIntelOutputSchema, TrustpilotReviewsOutputSchema, G2ReviewsOutputSchema, CreditsInfoOutputSchema, MapSiteUrlsOutputSchema, WaybackCaptureOutputSchema, MapWaybackSnapshotsOutputSchema, YoutubeHarvestOutputSchema, FacebookAdSearchOutputSchema, VideoFrameAnalysisOutputSchema, VideoFrameAnalysisStatusOutputSchema, RedditThreadOutputSchema, RedditTrendingOutputSchema, FacebookPageIntelOutputSchema, GoogleAdsSearchOutputSchema, GoogleAdsPageIntelOutputSchema, TranscriptSignalOutput, FacebookVideoTranscribeOutputSchema, TranscriptChunkOutput, InstagramBrowserOutput, InstagramPaginationOutput, InstagramProfileContentOutputSchema, InstagramMediaTrackOutput, InstagramDownloadOutput, InstagramMediaDownloadOutputSchema, YoutubeTranscribeOutputSchema, FacebookAdTranscribeOutputSchema, GoogleAdsTranscribeOutputSchema, CaptureSerpSnapshotOutputSchema, CaptureSerpPageSnapshotsOutputSchema, CreditsInfoInputSchema, WorkflowIdSchema2, WorkflowListInputSchema, WorkflowSuggestInputSchema, WorkflowRunInputSchema, WorkflowStepInputSchema, WorkflowStatusInputSchema, WorkflowArtifactReadInputSchema, WorkflowRecipeOutput, WorkflowDefinitionOutput, WorkflowArtifactOutput, WorkflowListOutputSchema, WorkflowSuggestOutputSchema, WorkflowRunOutputSchema, WorkflowStepOutputSchema, WorkflowStatusOutputSchema, WorkflowArtifactReadOutputSchema, SearchSerpInputSchema, CaptureSerpSnapshotInputSchema, ScreenshotInputSchema, CaptureSerpPageSnapshotsInputSchema, ReportArtifactReadInputSchema, ReportArtifactReadOutputSchema, ListServiceConnectionsInputSchema, ListServiceConnectionsOutputSchema, TestServiceConnectionInputSchema, TestServiceConnectionOutputSchema, ReadServiceConnectionInputSchema, ReadServiceConnectionOutputSchema, MetaAdCreativeMediaInputSchema, MetaAdCreativeMediaOutputSchema, ImportServiceConnectionToMemoryInputSchema, ImportServiceConnectionToMemoryOutputSchema, DescribeServiceConnectionToolInputSchema, DescribeServiceConnectionToolOutputSchema, ConnectedDataContinuationSchema, ExportConnectedServiceDataInputSchema, ConnectedDataArtifactSchema, ExportConnectedServiceDataOutputSchema, SearchConsoleTableColumnSchema, SearchConsoleTableFilterSchema, ExportSearchConsoleTableDataInputSchema, ExportSearchConsoleTableDataOutputSchema, RenewConnectedDataExportDownloadInputSchema, RenewConnectedDataExportDownloadOutputSchema, CallServiceConnectionActionInputSchema, CallServiceConnectionActionOutputSchema, SetScheduledActionConnectionsInputSchema, SetScheduledActionConnectionsOutputSchema, SlackSendMessageInputSchema, SlackSendMessageOutputSchema, GmailSendMessageInputSchema, GmailSendMessageOutputSchema, GmailSearchContactsInputSchema, GmailSearchContactsOutputSchema, GoogleCalendarCreateEventInputSchema, GoogleCalendarCreateEventOutputSchema, ZoomCreateMeetingInputSchema, ZoomCreateMeetingOutputSchema;
41799
+ var import_zod41, WEBSITE_URL_OR_DOMAIN_ERROR, WebsiteUrlOrDomainSchema, HarvestPaaInputSchema, ExtractUrlBaseInputSchema, ExtractUrlInputSchema, ExtractUrlLocalInputSchema, DiffPageBaseInputSchema, DiffPageInputSchema, DiffPageLocalInputSchema, MapSiteUrlsInputSchema, MapWaybackSnapshotsInputSchema, ExtractSiteInputSchema, AuditSiteInputSchema, CheckSiteExportInputSchema, ArchiveReadInputSchema, YoutubeHarvestInputSchema, YoutubeTranscribeInputSchema, FacebookPageIntelInputSchema, FacebookAdSearchInputSchema, RedditThreadInputSchema, RedditTrendingInputSchema, VideoFrameAnalysisInputSchema, VideoFrameAnalysisStatusInputSchema, FacebookAdTranscribeInputSchema, FacebookVideoTranscribeInputSchema, GoogleAdsSearchInputSchema, GoogleAdsPageIntelInputSchema, GoogleAdsTranscribeInputSchema, InstagramProfileContentInputSchema, InstagramMediaDownloadInputSchema, MapsPlaceIntelInputSchema, TrustpilotReviewsInputSchema, G2ReviewsInputSchema, ReviewCardSchema, MapsSearchInputSchema, DirectoryWorkflowInputSchema, LocationMarketsInputSchema, CommonsSearchEntitiesInputSchema, CommonsGetEntityInputSchema, CommonsFeaturedImageInputSchema, CommonsMediaInputSchema, CommonsCitationInputSchema, CommonsSourceInputSchema, CommonsRelatedLinkInputSchema, CommonsPrepareEntityInputSchema, CommonsSubmitEntityInputSchema, CommonsValidateEntityInputSchema, CommonsGetEntityLedgerInputSchema, CommonsSaveFilterInputSchema, CommonsListFiltersInputSchema, CommonsListNeedsLinksInputSchema, CommonsGenericOutputSchema, DirectoryWorkflowStatusInputSchema, LocalSourcebookSubmitInputSchema, LocalSourcebookCategorySchema, LocalSourcebookTagCandidateObjectSchema, LocalSourcebookTagDecisionObjectSchema, LocalSourcebookIdentityObjectSchema, GetLocalSourcebookContractInputSchema, ListLocalSourcebookTagsInputSchema, ResolveLocalSourcebookTagsInputSchema, PrepareLocalSourcebookWriteInputSchema, ValidateLocalSourcebookWriteInputSchema, LocalSourcebookCaptureInputSchema, LocalSourcebookSubmissionStatusInputSchema, LocalSourcebookRefreshInputSchema, LocalSourcebookOutputSchema, ArtifactPointerOutputSchema, EditorialReadingRoomSiteSchema, EditorialReadingRoomArticleSchema, EditorialReadingRoomGuideInputSchema, EditorialReadingRoomGuideOutputSchema, CreateEditorialReadingRoomInputSchema, EditorialReadingRoomArtifactSchema, CreateEditorialReadingRoomOutputSchema, RenewEditorialReadingRoomDownloadInputSchema, RenewEditorialReadingRoomDownloadOutputSchema, RankTrackerModeSchema, RankTrackerBlueprintInputSchema, NullableString, MapsSearchAttemptOutput, MapsSearchOutputSchema, DirectoryMapsBusinessOutput, DirectoryCsvArtifactOutput, DirectoryWorkflowOutputSchema, LocationDatasetProvenanceOutput, LocationMarketsOutputSchema, RankTrackerToolPlanOutput, RankTrackerTableOutput, RankTrackerCronJobOutput, RankTrackerBlueprintOutputSchema, OrganicResultOutput, AiOverviewOutput, EntityIdsOutput, HarvestPaaOutputSchema, SearchSerpOutputSchema, ExtractUrlOutputSchema, DiffPageOutputSchema, ExtractSiteOutputSchema, AuditSiteOutputSchema, CheckSiteExportOutputSchema, ArchiveEntryOutputSchema, ArchiveReadOutputSchema, MapsPlaceIntelOutputSchema, TrustpilotReviewsOutputSchema, G2ReviewsOutputSchema, CreditsInfoOutputSchema, MapSiteUrlsOutputSchema, WaybackCaptureOutputSchema, MapWaybackSnapshotsOutputSchema, YoutubeHarvestOutputSchema, FacebookAdSearchOutputSchema, VideoFrameAnalysisOutputSchema, VideoFrameAnalysisStatusOutputSchema, RedditThreadOutputSchema, RedditTrendingOutputSchema, FacebookPageIntelOutputSchema, GoogleAdsSearchOutputSchema, GoogleAdsPageIntelOutputSchema, TranscriptSignalOutput, FacebookVideoTranscribeOutputSchema, TranscriptChunkOutput, InstagramBrowserOutput, InstagramPaginationOutput, InstagramProfileContentOutputSchema, InstagramMediaTrackOutput, InstagramDownloadOutput, InstagramMediaDownloadOutputSchema, YoutubeTranscribeOutputSchema, FacebookAdTranscribeOutputSchema, GoogleAdsTranscribeOutputSchema, CaptureSerpSnapshotOutputSchema, CaptureSerpPageSnapshotsOutputSchema, CreditsInfoInputSchema, WorkflowIdSchema2, WorkflowListInputSchema, WorkflowSuggestInputSchema, WorkflowRunInputSchema, WorkflowStepInputSchema, WorkflowStatusInputSchema, WorkflowArtifactReadInputSchema, WorkflowRecipeOutput, WorkflowDefinitionOutput, WorkflowArtifactOutput, WorkflowListOutputSchema, WorkflowSuggestOutputSchema, WorkflowRunOutputSchema, WorkflowStepOutputSchema, WorkflowStatusOutputSchema, WorkflowArtifactReadOutputSchema, SearchSerpInputSchema, CaptureSerpSnapshotInputSchema, ScreenshotInputSchema, CaptureSerpPageSnapshotsInputSchema, ReportArtifactReadInputSchema, ReportArtifactReadOutputSchema, ListServiceConnectionsInputSchema, ListServiceConnectionsOutputSchema, TestServiceConnectionInputSchema, TestServiceConnectionOutputSchema, ReadServiceConnectionInputSchema, ReadServiceConnectionOutputSchema, MetaAdCreativeMediaInputSchema, MetaAdCreativeMediaOutputSchema, ImportServiceConnectionToMemoryInputSchema, ImportServiceConnectionToMemoryOutputSchema, DescribeServiceConnectionToolInputSchema, DescribeServiceConnectionToolOutputSchema, ConnectedDataContinuationSchema, ExportConnectedServiceDataInputSchema, ConnectedDataArtifactSchema, ExportConnectedServiceDataOutputSchema, SearchConsoleTableColumnSchema, SearchConsoleTableFilterSchema, ExportSearchConsoleTableDataInputSchema, ExportSearchConsoleTableDataOutputSchema, RenewConnectedDataExportDownloadInputSchema, RenewConnectedDataExportDownloadOutputSchema, CallServiceConnectionActionInputSchema, CallServiceConnectionActionOutputSchema, SetScheduledActionConnectionsInputSchema, SetScheduledActionConnectionsOutputSchema, SlackSendMessageInputSchema, SlackSendMessageOutputSchema, GmailSendMessageInputSchema, GmailSendMessageOutputSchema, GmailSearchContactsInputSchema, GmailSearchContactsOutputSchema, GoogleCalendarCreateEventInputSchema, GoogleCalendarCreateEventOutputSchema, ZoomCreateMeetingInputSchema, ZoomCreateMeetingOutputSchema;
41759
41800
  var init_mcp_tool_schemas = __esm({
41760
41801
  "src/mcp/mcp-tool-schemas.ts"() {
41761
41802
  "use strict";
@@ -42276,24 +42317,17 @@ var init_mcp_tool_schemas = __esm({
42276
42317
  tagCandidates: import_zod41.z.array(LocalSourcebookTagCandidateObjectSchema).max(20).optional()
42277
42318
  };
42278
42319
  ValidateLocalSourcebookWriteInputSchema = {
42279
- identity: LocalSourcebookIdentityObjectSchema.optional().describe("New-listing identity returned by prepare-local-sourcebook-write."),
42280
- listing: import_zod41.z.record(import_zod41.z.string(), import_zod41.z.unknown()).optional().describe("Complete replacement listing draft for an existing owner-scoped submission."),
42281
- submissionId: import_zod41.z.string().trim().min(1).optional().describe("Existing owner-scoped submission being revised. Omit for a new capture."),
42282
- baseRevision: import_zod41.z.number().int().min(1).optional().describe("Required current draft revision for an edit, preventing silent overwrites."),
42320
+ identity: LocalSourcebookIdentityObjectSchema.describe("New-listing identity returned by prepare-local-sourcebook-write. Evidence-bearing public fields are compiled by MCP Scraper and cannot be supplied here."),
42283
42321
  tagCandidates: import_zod41.z.array(LocalSourcebookTagCandidateObjectSchema).max(20).optional(),
42284
42322
  tagDecisions: import_zod41.z.array(LocalSourcebookTagDecisionObjectSchema).max(20).optional()
42285
42323
  };
42286
42324
  LocalSourcebookCaptureInputSchema = {
42287
42325
  ...ValidateLocalSourcebookWriteInputSchema,
42288
- idempotencyKey: import_zod41.z.string().trim().min(8).max(200).optional().describe("Stable retry key for a new capture. Required for new listings; omit only when revising an existing submissionId.")
42326
+ idempotencyKey: import_zod41.z.string().trim().min(8).max(200).optional().describe("Stable retry key for a new capture. Required either here or in identity.")
42289
42327
  };
42290
42328
  LocalSourcebookSubmissionStatusInputSchema = {
42291
42329
  submissionId: import_zod41.z.string().trim().min(1).describe("The owner-scoped submission ID returned by local-sourcebook-capture.")
42292
42330
  };
42293
- LocalSourcebookUpdateDraftInputSchema = {
42294
- submissionId: import_zod41.z.string().trim().min(1),
42295
- payload: import_zod41.z.record(import_zod41.z.string(), import_zod41.z.unknown()).describe("Complete replacement draft. The previous revision remains immutable in the audit history.")
42296
- };
42297
42331
  LocalSourcebookRefreshInputSchema = {
42298
42332
  submissionId: import_zod41.z.string().trim().min(1).describe("Owner-scoped listing submission to re-crawl and refresh.")
42299
42333
  };
@@ -45216,7 +45250,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
45216
45250
  }, async (input) => formatDirectoryWorkflow(await executor.directoryWorkflowStatus(input), input, ctx));
45217
45251
  server.registerTool("get-local-sourcebook-contract", {
45218
45252
  title: "Get Local Sourcebook Contract",
45219
- description: "Read the governed listing purpose, supported categories, canonical profile/review routes, required sections, acquisition limits, tag policy, ownership boundary, and admin-only publication rule. Call this before composing a listing when its required shape is uncertain.",
45253
+ description: "Read the governed listing purpose, supported categories, exact LocalSourcebook.com profile/review URLs, nationwide directory URL, required sections, acquisition limits, tag policy, ownership boundary, and automatic evidence-publication rule. Call this before composing a listing when its required shape is uncertain.",
45220
45254
  inputSchema: GetLocalSourcebookContractInputSchema,
45221
45255
  outputSchema: recordOutputSchema("get-local-sourcebook-contract", LocalSourcebookOutputSchema),
45222
45256
  annotations: localPlanningToolAnnotations("Get Local Sourcebook Contract")
@@ -45244,28 +45278,28 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
45244
45278
  }, async (input) => executor.prepareLocalSourcebookWrite(input));
45245
45279
  server.registerTool("validate-local-sourcebook-write", {
45246
45280
  title: "Validate Local Sourcebook Write",
45247
- description: "Validate a proposed new listing or complete owner draft revision without writing it. Checks identity or listing completeness, canonical tags, tag decisions, and baseRevision requirements. Capture only when valid is true.",
45281
+ description: "Validate a proposed new listing identity without writing it. Checks business identity, canonical tags, and explicit tag decisions. Public facts are compiled from MCP Scraper evidence rather than accepted from the owner. Capture only when valid is true.",
45248
45282
  inputSchema: ValidateLocalSourcebookWriteInputSchema,
45249
45283
  outputSchema: recordOutputSchema("validate-local-sourcebook-write", LocalSourcebookOutputSchema),
45250
45284
  annotations: localPlanningToolAnnotations("Validate Local Sourcebook Write")
45251
45285
  }, async (input) => executor.validateLocalSourcebookWrite(input));
45252
45286
  server.registerTool("local-sourcebook-capture", {
45253
45287
  title: "Capture Governed Local Sourcebook Listing",
45254
- description: "Strict owner-scoped write path after list, contract, prepare, and validate. A new capture registers canonical tags and queues paid website, exact-place, review, service-area, staff, and genuine-media acquisition. An edit requires the current baseRevision. Capture never publishes; admin review remains required.",
45288
+ description: "Strict owner-scoped write path after list, contract, prepare, and validate. Capture registers canonical tags, returns the exact LocalSourcebook.com profile and reviews URLs, and queues paid website, exact-place, review, service-area, staff, and genuine-media acquisition. A successful system-compiled evidence revision publishes automatically; owner-authored public claims are not accepted.",
45255
45289
  inputSchema: LocalSourcebookCaptureInputSchema,
45256
45290
  outputSchema: recordOutputSchema("local-sourcebook-capture", LocalSourcebookOutputSchema),
45257
45291
  annotations: liveWebToolAnnotations("Capture Governed Local Sourcebook Listing")
45258
45292
  }, async (input) => executor.localSourcebookCapture(input));
45259
45293
  server.registerTool("local_sourcebook_submission_status", {
45260
45294
  title: "Local Sourcebook Submission Status",
45261
- description: "Read the authenticated caller\u2019s listing draft, enrichment coverage, immutable revision number, and publication state.",
45295
+ description: "Read the authenticated caller\u2019s listing draft, enrichment coverage, immutable revision number, publication state, and exact live LocalSourcebook.com profile and reviews URLs.",
45262
45296
  inputSchema: LocalSourcebookSubmissionStatusInputSchema,
45263
45297
  outputSchema: recordOutputSchema("local_sourcebook_submission_status", LocalSourcebookOutputSchema),
45264
45298
  annotations: localPlanningToolAnnotations("Local Sourcebook Submission Status")
45265
45299
  }, async (input) => executor.localSourcebookSubmissionStatus(input));
45266
45300
  server.registerTool("local_sourcebook_refresh", {
45267
45301
  title: "Refresh a Local Sourcebook Listing",
45268
- description: "Queue a new broad crawl and review/media acquisition pass for a listing owned by the authenticated MCP Scraper account.",
45302
+ description: "Queue a new broad crawl and review/media acquisition pass for a listing owned by the authenticated MCP Scraper account. The last published revision remains public until the refreshed evidence revision completes and auto-publishes.",
45269
45303
  inputSchema: LocalSourcebookRefreshInputSchema,
45270
45304
  outputSchema: recordOutputSchema("local_sourcebook_refresh", LocalSourcebookOutputSchema),
45271
45305
  annotations: liveWebToolAnnotations("Refresh a Local Sourcebook Listing")
@@ -45891,9 +45925,6 @@ var init_http_mcp_tool_executor = __esm({
45891
45925
  localSourcebookSubmissionStatus(input) {
45892
45926
  return this.getJson(`/local-sourcebook/submissions/${encodeURIComponent(input.submissionId)}`);
45893
45927
  }
45894
- localSourcebookUpdateDraft(input) {
45895
- return this.call(`/local-sourcebook/submissions/${encodeURIComponent(input.submissionId)}/draft`, { payload: input.payload });
45896
- }
45897
45928
  localSourcebookRefresh(input) {
45898
45929
  return this.call(`/local-sourcebook/submissions/${encodeURIComponent(input.submissionId)}/refresh`, {});
45899
45930
  }