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.
- package/README.md +2 -2
- package/dist/bin/api-server.cjs +103 -14
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +1 -1
- package/dist/bin/mcp-scraper-cli.cjs +1 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-install.cjs +1 -1
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.cjs +6 -4
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +2 -2
- package/dist/chunk-HFCIHZHA.js +7 -0
- package/dist/chunk-HFCIHZHA.js.map +1 -0
- package/dist/{chunk-M27QGXUM.js → chunk-ZVOVPXDL.js} +7 -5
- package/dist/chunk-ZVOVPXDL.js.map +1 -0
- package/dist/{server-RTQUTQZE.js → server-W4JLSNKW.js} +93 -13
- package/dist/server-W4JLSNKW.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-M27QGXUM.js.map +0 -1
- package/dist/chunk-OEW4VBS2.js +0 -7
- package/dist/chunk-OEW4VBS2.js.map +0 -1
- package/dist/server-RTQUTQZE.js.map +0 -1
|
@@ -86,7 +86,7 @@ import {
|
|
|
86
86
|
renewDirectoryArtifactDownload,
|
|
87
87
|
resolveDeploymentProfile,
|
|
88
88
|
transcribeMediaUrl
|
|
89
|
-
} from "./chunk-
|
|
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-
|
|
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: {
|
|
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,
|
|
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:
|
|
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:
|
|
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("
|
|
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-
|
|
41042
|
+
//# sourceMappingURL=server-W4JLSNKW.js.map
|