mcp-scraper 0.44.0 → 0.44.2

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.
@@ -0,0 +1,7 @@
1
+ // src/version.ts
2
+ var PACKAGE_VERSION = "0.44.2";
3
+
4
+ export {
5
+ PACKAGE_VERSION
6
+ };
7
+ //# sourceMappingURL=chunk-OEW4VBS2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/version.ts"],"sourcesContent":["export const PACKAGE_VERSION = '0.44.2'\n"],"mappings":";AAAO,IAAM,kBAAkB;","names":[]}
@@ -86,7 +86,7 @@ import {
86
86
  renewDirectoryArtifactDownload,
87
87
  resolveDeploymentProfile,
88
88
  transcribeMediaUrl
89
- } from "./chunk-HH5CE5LP.js";
89
+ } from "./chunk-M27QGXUM.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-RUDXFPKE.js";
145
+ } from "./chunk-OEW4VBS2.js";
146
146
  import {
147
147
  abandonExtractSettlement,
148
148
  countSuccessfulPages,
@@ -11972,6 +11972,7 @@ function ensureLocalSourcebookSchema() {
11972
11972
  metadata_json TEXT NOT NULL DEFAULT '{}',
11973
11973
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
11974
11974
  )`);
11975
+ await publishEligibleEvidenceBackedLocalSourcebookRevisions(db);
11975
11976
  })().catch((error) => {
11976
11977
  schemaPromise2 = null;
11977
11978
  schemaDb2 = null;
@@ -11979,6 +11980,19 @@ function ensureLocalSourcebookSchema() {
11979
11980
  });
11980
11981
  return schemaPromise2;
11981
11982
  }
11983
+ async function publishEligibleEvidenceBackedLocalSourcebookRevisions(db = getDb()) {
11984
+ const result = await db.execute(`UPDATE local_sourcebook_submissions
11985
+ SET status = 'published', published_revision = draft_revision, updated_at = datetime('now')
11986
+ WHERE status = 'needs_review'
11987
+ AND EXISTS (
11988
+ SELECT 1 FROM local_sourcebook_revisions r
11989
+ WHERE r.submission_id = local_sourcebook_submissions.id
11990
+ AND r.revision = local_sourcebook_submissions.draft_revision
11991
+ AND r.actor_kind = 'system'
11992
+ AND r.actor_id = 'local-sourcebook-worker'
11993
+ )`);
11994
+ return Number(result.rowsAffected ?? 0);
11995
+ }
11982
11996
  function rowValue(row, key) {
11983
11997
  return row[key];
11984
11998
  }
@@ -12048,23 +12062,12 @@ async function getLocalSourcebookDraft(id, ownerUserId) {
12048
12062
  const result = await getDb().execute({ sql: `SELECT payload_json FROM local_sourcebook_revisions WHERE submission_id = ? AND revision = ?`, args: [id, submission.draftRevision] });
12049
12063
  return result.rows[0] ? parseJson2(result.rows[0].payload_json) : null;
12050
12064
  }
12051
- async function reviseLocalSourcebookDraft(id, ownerUserId, payload, baseRevision) {
12052
- const submission = await getLocalSourcebookSubmission(id, ownerUserId);
12053
- if (!submission) return null;
12054
- if (baseRevision !== void 0 && baseRevision !== submission.draftRevision) {
12055
- throw new Error(`Draft revision conflict: current revision is ${submission.draftRevision}, but the write targeted ${baseRevision}.`);
12056
- }
12057
- const revision = submission.draftRevision + 1;
12058
- await getDb().batch([
12059
- { 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)] },
12060
- { 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] }
12061
- ], "write");
12062
- await event(id, "draft.revised", "owner", String(ownerUserId), { revision });
12063
- return getLocalSourcebookSubmission(id, ownerUserId);
12064
- }
12065
12065
  async function queueLocalSourcebookRefresh(id, ownerUserId) {
12066
12066
  const existing = await getLocalSourcebookSubmission(id, ownerUserId);
12067
12067
  if (!existing) return null;
12068
+ if (existing.status === "rejected" || existing.status === "unpublished") {
12069
+ throw new Error(`A ${existing.status} Local Sourcebook listing cannot be refreshed by its owner.`);
12070
+ }
12068
12071
  const coverage = { ...existing.coverage, refreshRequestedAt: (/* @__PURE__ */ new Date()).toISOString() };
12069
12072
  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] });
12070
12073
  await event(id, "enrichment.queued", "owner", String(ownerUserId));
@@ -12102,12 +12105,13 @@ async function completeLocalSourcebookAcquisition(id, payload, coverage, baseRev
12102
12105
  WHERE EXISTS (SELECT 1 FROM local_sourcebook_submissions WHERE id = ? AND status = 'enriching' AND draft_revision = ?)`,
12103
12106
  args: [id, revision, JSON.stringify(payload), id, expectedRevision]
12104
12107
  },
12105
- { 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] }
12108
+ { 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] }
12106
12109
  ], "write");
12107
12110
  if (Number(results[0]?.rowsAffected ?? 0) !== 1 || Number(results[1]?.rowsAffected ?? 0) !== 1) {
12108
12111
  throw new Error(`Local Sourcebook acquisition revision conflict: revision ${expectedRevision} changed before completion.`);
12109
12112
  }
12110
12113
  await event(id, "enrichment.completed", "system", "local-sourcebook-worker", { revision, coverage });
12114
+ await event(id, "publication.auto_published", "system", "local-sourcebook-worker", { revision });
12111
12115
  return getLocalSourcebookSubmission(id);
12112
12116
  }
12113
12117
  async function failLocalSourcebookAcquisition(id, message) {
@@ -12130,6 +12134,15 @@ async function listQueuedLocalSourcebookSubmissionIds(limit = 25) {
12130
12134
  async function publishLocalSourcebookSubmission(id) {
12131
12135
  const submission = await getLocalSourcebookSubmission(id);
12132
12136
  if (!submission) return null;
12137
+ const revision = await getDb().execute({
12138
+ sql: `SELECT actor_kind, actor_id FROM local_sourcebook_revisions WHERE submission_id = ? AND revision = ? LIMIT 1`,
12139
+ args: [id, submission.draftRevision]
12140
+ });
12141
+ const actorKind = revision.rows[0] ? String(revision.rows[0].actor_kind) : "";
12142
+ const actorId = revision.rows[0] ? String(revision.rows[0].actor_id) : "";
12143
+ if (actorKind !== "system" || actorId !== "local-sourcebook-worker") {
12144
+ throw new Error("Only a system-compiled Local Sourcebook revision can be published.");
12145
+ }
12133
12146
  await getDb().execute({ sql: `UPDATE local_sourcebook_submissions SET status = 'published', published_revision = draft_revision, updated_at = datetime('now') WHERE id = ?`, args: [id] });
12134
12147
  await event(id, "publication.published", "admin", "admin", { revision: submission.draftRevision });
12135
12148
  return getLocalSourcebookSubmission(id);
@@ -13328,11 +13341,12 @@ async function runLocalSourcebookAcquisition(submission, provider = createDefaul
13328
13341
  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 } });
13329
13342
  } catch (error) {
13330
13343
  mapsError = errorMessage2(error);
13344
+ maps = null;
13331
13345
  await creditMcIdempotent(submission.ownerUserId, MC_COSTS.maps_place, LedgerOperation.REFUND, `Local Sourcebook failed exact-place acquisition: ${submission.id}`, `${billingCycle}:maps-failure-refund`);
13332
13346
  mapsRefunded = true;
13333
13347
  await logRequestEvent({ userId: submission.ownerUserId, source: "local_sourcebook_maps", status: "failed", query: submission.businessName, location: submission.state.toUpperCase(), error: mapsError });
13334
13348
  }
13335
- if (!site && !maps) throw new Error(`Website and exact-place acquisition both failed. Website: ${siteError || "not available"}. Maps: ${mapsError || "not available"}.`);
13349
+ if (!maps) throw new Error(`Exact-place acquisition is required before publication. Maps: ${mapsError || "not available"}. Website: ${siteError || (site ? "captured" : "not available")}.`);
13336
13350
  const compiled = compileLocalSourcebookListing({
13337
13351
  submission,
13338
13352
  site,
@@ -21255,23 +21269,6 @@ var DirectoryIdentitySchema = z25.object({
21255
21269
  tags: z25.array(z25.string().trim().min(1).max(60)).max(20).default([]),
21256
21270
  idempotencyKey: z25.string().trim().min(8).max(200)
21257
21271
  });
21258
- var DirectoryListingDraftSchema = z25.object({
21259
- id: z25.string().min(1),
21260
- category: z25.enum(LOCAL_SOURCEBOOK_CATEGORIES),
21261
- state: z25.string().trim().length(2),
21262
- slug: z25.string().trim().min(1),
21263
- name: z25.string().trim().min(2),
21264
- summary: z25.string().trim().min(20),
21265
- description: z25.string().trim().min(20),
21266
- website: z25.url(),
21267
- services: z25.array(z25.string()),
21268
- products: z25.array(z25.string()),
21269
- serviceAreas: z25.array(z25.string()),
21270
- media: z25.array(z25.record(z25.string(), z25.unknown())),
21271
- reviews: z25.array(z25.record(z25.string(), z25.unknown())),
21272
- evidence: z25.array(z25.record(z25.string(), z25.unknown())),
21273
- faq: z25.array(z25.object({ question: z25.string().min(3), answer: z25.string().min(12), evidenceIds: z25.array(z25.string()) }))
21274
- }).passthrough();
21275
21272
  function normalizeTag(value) {
21276
21273
  return value.toLowerCase().trim().replace(/&/g, " and ").replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
21277
21274
  }
@@ -21352,18 +21349,18 @@ async function resolveLocalSourcebookTags(candidates) {
21352
21349
  function getLocalSourcebookContract(category) {
21353
21350
  return {
21354
21351
  name: "Local Sourcebook listing",
21355
- version: "local_sourcebook_listing_v1",
21352
+ version: "local_sourcebook_listing_v2",
21356
21353
  purpose: "An owner-scoped, evidence-backed local business record with a separate public profile and complete captured-review archive.",
21357
21354
  categories: LOCAL_SOURCEBOOK_CATEGORIES,
21358
21355
  selectedCategory: category ?? null,
21359
21356
  categoryTag: category ? CATEGORY_TAG[category] : null,
21360
21357
  canonicalRoutes: { profile: "/{state}/{business-slug}/", reviews: "/{state}/{business-slug}/reviews" },
21361
21358
  requiredCreateFields: ["category", "state", "businessName", "websiteUrl", "tags", "idempotencyKey"],
21362
- requiredDraftSections: ["identity", "services/products", "service areas/locations", "genuine media", "reviews and theme counts", "evidence", "answered FAQ", "collection receipts"],
21359
+ systemCompiledSections: ["identity", "services/products", "service areas/locations", "genuine media", "reviews and theme counts", "evidence", "answered FAQ", "collection receipts"],
21363
21360
  workflow: ["list-local-sourcebook-tags", "get-local-sourcebook-contract", "prepare-local-sourcebook-write", "validate-local-sourcebook-write", "local-sourcebook-capture", "local_sourcebook_submission_status"],
21364
- ownership: "Only the MCP Scraper account that captures a listing can read or revise its draft.",
21361
+ ownership: "Only the MCP Scraper account that captures a listing can read it or request a paid evidence refresh.",
21365
21362
  acquisition: { websitePagesMaximum: 100, reviewsMaximum: 500, exactMapsIdentityRequired: true, partialResultsRequireStoppingReasons: true },
21366
- publication: { automatic: false, adminReviewRequired: true, lastPublishedRevisionRemainsPublicDuringRefresh: true },
21363
+ publication: { automatic: true, evidenceCompiledOnly: true, ownerAuthoredClaimsAccepted: false, adminReviewRequired: false, lastPublishedRevisionRemainsPublicDuringRefresh: true },
21367
21364
  tagPolicy: { inspectVocabularyFirst: true, minimum: 1, maximum: 20, newTagsRequire: ["central=true", "reusable=true", "description"], newTagsStartAs: "pending" }
21368
21365
  };
21369
21366
  }
@@ -21386,7 +21383,8 @@ async function prepareLocalSourcebookWrite(input) {
21386
21383
  instructions: [
21387
21384
  "Resolve every review candidate before capture; do not silently create a near-duplicate tag.",
21388
21385
  "Call validate-local-sourcebook-write with the proposed identity, resolved tags, and any required tag decisions.",
21389
- "Call local-sourcebook-capture only after validation returns valid=true. Capture creates a private draft and queues paid acquisition; it does not publish."
21386
+ "Call local-sourcebook-capture only after validation returns valid=true. Capture queues paid acquisition and automatically publishes the resulting system-compiled evidence revision.",
21387
+ "Owners cannot supply public listing claims directly. Request local_sourcebook_refresh when source-backed public facts need to be reacquired."
21390
21388
  ]
21391
21389
  };
21392
21390
  }
@@ -21394,17 +21392,9 @@ async function validateLocalSourcebookWrite(input) {
21394
21392
  const errors = [];
21395
21393
  const warnings = [];
21396
21394
  let normalizedIdentity2;
21397
- let normalizedListing;
21398
- if (input.submissionId) {
21399
- if (!Number.isInteger(input.baseRevision) || Number(input.baseRevision) < 1) errors.push("baseRevision is required for an existing draft edit.");
21400
- const parsedListing = DirectoryListingDraftSchema.safeParse(input.listing);
21401
- if (!parsedListing.success) errors.push(...parsedListing.error.issues.map((issue) => `listing.${issue.path.join(".")}: ${issue.message}`));
21402
- else normalizedListing = parsedListing.data;
21403
- } else {
21404
- const parsedIdentity = DirectoryIdentitySchema.safeParse(input.identity);
21405
- if (!parsedIdentity.success) errors.push(...parsedIdentity.error.issues.map((issue) => `identity.${issue.path.join(".")}: ${issue.message}`));
21406
- else normalizedIdentity2 = parsedIdentity.data;
21407
- }
21395
+ const parsedIdentity = DirectoryIdentitySchema.safeParse(input.identity);
21396
+ if (!parsedIdentity.success) errors.push(...parsedIdentity.error.issues.map((issue) => `identity.${issue.path.join(".")}: ${issue.message}`));
21397
+ else normalizedIdentity2 = parsedIdentity.data;
21408
21398
  const candidates = input.tagCandidates ?? (normalizedIdentity2?.tags.map((tag) => ({ tag })) ?? []);
21409
21399
  const resolutions = await resolveLocalSourcebookTags(candidates);
21410
21400
  const decisions = new Map((input.tagDecisions ?? []).map((decision) => [normalizeTag(decision.tag), decision]));
@@ -21423,12 +21413,12 @@ async function validateLocalSourcebookWrite(input) {
21423
21413
  }
21424
21414
  if (resolution.action === "omit") warnings.push(`Tag \u201C${resolution.candidate}\u201D will be omitted: ${resolution.reason}`);
21425
21415
  }
21426
- if (!input.submissionId && normalizedIdentity2) {
21416
+ if (normalizedIdentity2) {
21427
21417
  const categoryTag = CATEGORY_TAG[normalizedIdentity2.category];
21428
21418
  if (!normalizedTags.includes(categoryTag)) normalizedTags.unshift(categoryTag);
21429
21419
  }
21430
21420
  if (!normalizedTags.length) errors.push("At least one canonical directory tag is required.");
21431
- return { ok: true, valid: errors.length === 0, errors, warnings, normalizedIdentity: normalizedIdentity2, normalizedListing, normalizedTags: [...new Set(normalizedTags)], tagResolutions: resolutions };
21421
+ return { ok: true, valid: errors.length === 0, errors, warnings, normalizedIdentity: normalizedIdentity2, normalizedTags: [...new Set(normalizedTags)], tagResolutions: resolutions };
21432
21422
  }
21433
21423
  async function persistLocalSourcebookTags(submissionId, userId, tags, decisions = []) {
21434
21424
  await ensureLocalSourcebookTags();
@@ -21445,11 +21435,6 @@ async function persistLocalSourcebookTags(submissionId, userId, tags, decisions
21445
21435
  await db.execute({ sql: `INSERT OR IGNORE INTO local_sourcebook_submission_tags (submission_id, tag) VALUES (?, ?)`, args: [submissionId, tag] });
21446
21436
  }
21447
21437
  }
21448
- async function replaceLocalSourcebookTags(submissionId, userId, tags, decisions = []) {
21449
- await ensureLocalSourcebookTags();
21450
- await getDb().execute({ sql: `DELETE FROM local_sourcebook_submission_tags WHERE submission_id = ?`, args: [submissionId] });
21451
- await persistLocalSourcebookTags(submissionId, userId, tags, decisions);
21452
- }
21453
21438
 
21454
21439
  // src/api/local-sourcebook-routes.ts
21455
21440
  var slug = (value) => value.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 100);
@@ -21461,13 +21446,9 @@ var SubmitSchema = z26.object({
21461
21446
  slug: z26.string().trim().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).max(100).optional(),
21462
21447
  idempotencyKey: z26.string().trim().min(8).max(200).optional()
21463
21448
  }).strict();
21464
- var DraftSchema = z26.object({ payload: z26.record(z26.string(), z26.unknown()) }).strict();
21465
21449
  var PrepareWriteSchema = DirectoryIdentitySchema.extend({ tagCandidates: z26.array(DirectoryTagCandidateSchema).max(20).optional() });
21466
21450
  var ValidateWriteSchema = z26.object({
21467
21451
  identity: DirectoryIdentitySchema.optional(),
21468
- listing: z26.record(z26.string(), z26.unknown()).optional(),
21469
- submissionId: z26.string().trim().min(1).optional(),
21470
- baseRevision: z26.number().int().min(1).optional(),
21471
21452
  tagCandidates: z26.array(DirectoryTagCandidateSchema).max(20).optional(),
21472
21453
  tagDecisions: z26.array(DirectoryTagDecisionSchema).max(20).optional()
21473
21454
  }).strict();
@@ -21477,7 +21458,7 @@ function acquisitionPlan(websiteUrl) {
21477
21458
  website: { startUrl: websiteUrl, mode: "broad_site_crawl", capture: ["homepage", "services", "products", "locations", "service_areas", "about", "team_staff", "contact", "policies"] },
21478
21459
  media: { requirement: "genuine_business_images_only", sources: ["business_website", "business_team_pages", "verified_business_profiles"] },
21479
21460
  reviews: { mode: "exhaust_accessible_continuation", requirement: "retain_each_review_and_source", disclosure: "report captured count, reported available count, and exact stopping reason" },
21480
- publication: { automatic: false, adminReviewRequired: true }
21461
+ publication: { automatic: true, evidenceCompiledOnly: true, adminReviewRequired: false }
21481
21462
  };
21482
21463
  }
21483
21464
  var localSourcebookApp = new Hono17();
@@ -21507,13 +21488,6 @@ localSourcebookApp.post("/capture", createApiKeyAuth(), async (c) => {
21507
21488
  const validation = await validateLocalSourcebookWrite(parsed.data);
21508
21489
  if (!validation.valid) return c.json({ error: "invalid_directory_write", ...validation }, 400);
21509
21490
  try {
21510
- if (parsed.data.submissionId) {
21511
- const submission2 = await getLocalSourcebookSubmission(parsed.data.submissionId, Number(user.id));
21512
- if (!submission2) return c.json({ error: "not_found" }, 404);
21513
- const updated = await reviseLocalSourcebookDraft(submission2.id, Number(user.id), validation.normalizedListing, parsed.data.baseRevision);
21514
- await replaceLocalSourcebookTags(submission2.id, Number(user.id), validation.normalizedTags, parsed.data.tagDecisions);
21515
- return c.json({ ok: true, valid: true, submission: updated, normalizedTags: validation.normalizedTags, captured: "draft_revision", acquisitionQueued: false });
21516
- }
21517
21491
  const identity = validation.normalizedIdentity;
21518
21492
  if (!parsed.data.idempotencyKey && !identity.idempotencyKey) {
21519
21493
  return c.json({ error: "idempotency_key_required", message: "A stable idempotencyKey is required for a new Local Sourcebook capture." }, 400);
@@ -21591,22 +21565,21 @@ localSourcebookApp.get("/submissions/:id", createApiKeyAuth(), async (c) => {
21591
21565
  if (!submission) return c.json({ error: "not_found" }, 404);
21592
21566
  return c.json({ ok: true, submission, draft: await getLocalSourcebookDraft(submission.id, userId) });
21593
21567
  });
21594
- localSourcebookApp.on(["PATCH", "POST"], "/submissions/:id/draft", createApiKeyAuth(), async (c) => {
21595
- const user = c.get("user");
21596
- if (!user.subscription_tier) return c.json({ error: "subscription_required" }, 402);
21597
- const parsed = DraftSchema.safeParse(await c.req.json().catch(() => null));
21598
- if (!parsed.success) return c.json({ error: "invalid_draft", issues: parsed.error.issues }, 400);
21599
- const submission = await reviseLocalSourcebookDraft(c.req.param("id"), Number(user.id), parsed.data.payload);
21600
- if (!submission) return c.json({ error: "not_found" }, 404);
21601
- return c.json({ ok: true, submission });
21602
- });
21568
+ localSourcebookApp.on(["PATCH", "POST"], "/submissions/:id/draft", createApiKeyAuth(), (c) => c.json({
21569
+ error: "evidence_refresh_required",
21570
+ message: "Owner-authored listing payloads are not accepted. Request a refresh so MCP Scraper can reacquire and compile the public evidence."
21571
+ }, 409));
21603
21572
  localSourcebookApp.post("/submissions/:id/refresh", createApiKeyAuth(), async (c) => {
21604
21573
  const user = c.get("user");
21605
21574
  if (!user.subscription_tier) return c.json({ error: "subscription_required" }, 402);
21606
- const submission = await queueLocalSourcebookRefresh(c.req.param("id"), Number(user.id));
21607
- if (!submission) return c.json({ error: "not_found" }, 404);
21608
- const dispatched = await dispatchLocalSourcebookAcquisition(submission.id).catch(() => false);
21609
- return c.json({ ok: true, submission, acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(submission.websiteUrl) }, 202);
21575
+ try {
21576
+ const submission = await queueLocalSourcebookRefresh(c.req.param("id"), Number(user.id));
21577
+ if (!submission) return c.json({ error: "not_found" }, 404);
21578
+ const dispatched = await dispatchLocalSourcebookAcquisition(submission.id).catch(() => false);
21579
+ return c.json({ ok: true, submission, acquisition: { queued: true, dispatched }, acquisitionPlan: acquisitionPlan(submission.websiteUrl) }, 202);
21580
+ } catch (error) {
21581
+ return c.json({ error: "moderated_listing", message: error instanceof Error ? error.message : String(error) }, 409);
21582
+ }
21610
21583
  });
21611
21584
  var publicLocalSourcebookApp = new Hono17();
21612
21585
  publicLocalSourcebookApp.get("/:category/:state", async (c) => c.json({ ok: true, listings: await listPublicLocalSourcebook(c.req.param("category"), c.req.param("state").toLowerCase()) }));
@@ -40986,4 +40959,4 @@ app.get("/blog/:slug/", (c) => {
40986
40959
  export {
40987
40960
  app
40988
40961
  };
40989
- //# sourceMappingURL=server-75YGJWSI.js.map
40962
+ //# sourceMappingURL=server-RTQUTQZE.js.map