mcp-scraper 0.66.7 → 0.67.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/README.md +1 -1
  3. package/dist/bin/api-server.cjs +260 -43
  4. package/dist/bin/api-server.js +3 -3
  5. package/dist/bin/mcp-scraper-cli.cjs +1 -1
  6. package/dist/bin/mcp-scraper-cli.js +1 -1
  7. package/dist/bin/mcp-scraper-install.cjs +2 -2
  8. package/dist/bin/mcp-scraper-install.js +2 -2
  9. package/dist/bin/mcp-stdio-server.cjs +70 -14
  10. package/dist/bin/mcp-stdio-server.js +6 -6
  11. package/dist/bin/paa-harvest.cjs +6 -0
  12. package/dist/bin/paa-harvest.js +3 -3
  13. package/dist/{chunk-F434YJPV.js → chunk-2L4C4DAZ.js} +1 -1
  14. package/dist/{chunk-LVXRWJJJ.js → chunk-2LXTOAKS.js} +1 -1
  15. package/dist/{chunk-CGOMGGOF.js → chunk-62LEXS5O.js} +2 -2
  16. package/dist/{chunk-HZDJ5UZ4.js → chunk-65FTMB7G.js} +25 -1
  17. package/dist/{chunk-U2UHJWFW.js → chunk-ES25GP6C.js} +1 -1
  18. package/dist/{chunk-O7ZC5Y3Z.js → chunk-HUNXSVKU.js} +1 -1
  19. package/dist/{chunk-HWGQVP3Q.js → chunk-LCGTNWOT.js} +1 -1
  20. package/dist/{chunk-EVOBJYBE.js → chunk-LN6N3YLK.js} +1 -1
  21. package/dist/{chunk-Z5QQEWXA.js → chunk-STQQOEHC.js} +47 -15
  22. package/dist/{chunk-JZPSG4NR.js → chunk-UL4ZKAWZ.js} +1 -1
  23. package/dist/{chunk-7KB5QTHP.js → chunk-VES63X4Q.js} +1 -1
  24. package/dist/{chunk-HBZENASD.js → chunk-Y46YNQMM.js} +1 -1
  25. package/dist/{db-MNNNIWVS.js → db-ZGZAKYBW.js} +1 -1
  26. package/dist/{extract-bundle-RW7CVIRF.js → extract-bundle-QQIYJSBW.js} +3 -3
  27. package/dist/index.cjs +6 -0
  28. package/dist/index.js +3 -3
  29. package/dist/{lead-list-enrichment-repository-PZYE6TDP.js → lead-list-enrichment-repository-CXLVIV3R.js} +2 -2
  30. package/dist/{location-data-repository-EPCNGMOM.js → location-data-repository-G72M7DTN.js} +2 -2
  31. package/dist/{server-KSVJ4X4V.js → server-ROIJWWJG.js} +206 -48
  32. package/dist/{site-extract-repository-CZ7SVT3Z.js → site-extract-repository-7EP6UX6I.js} +2 -2
  33. package/dist/{worker-IBLGV272.js → worker-JGWV2LID.js} +5 -5
  34. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@ All notable changes to MCP Scraper are documented here. The format is based on [
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.67.1] - 2026-08-26
8
+
9
+ ### Fixed
10
+
11
+ - `commons_host_image` now returns its complete success payload through both readable JSON text and MCP `structuredContent`, so typed clients can consume permanent image provenance without reparsing text.
12
+
13
+ ## [0.67.0] - 2026-08-26
14
+
15
+ ### Added
16
+
17
+ - `commons_host_image` now accepts pasted or AI-generated bytes, owner-scoped image artifacts, direct image URLs, and webpage URLs through one workflow. Webpage inputs try Open Graph, Twitter, JSON-LD, and meaningful content images, return source-selection provenance, and omit temporary URL query credentials from durable image metadata.
18
+ - `mcpscraper.dev` now publishes its complete generated LLM discovery profile and bounded semantic authority-retrieval endpoints from the site-owned Next.js authority layer.
19
+
7
20
  ## [0.66.7] - 2026-08-26
8
21
 
9
22
  ### Fixed
@@ -1128,7 +1141,9 @@ All notable changes to MCP Scraper are documented here. The format is based on [
1128
1141
  - Write actions remain unavailable until the account owner explicitly enables them.
1129
1142
  - Provider-specific connection data is normalized into one agent-facing contract.
1130
1143
 
1131
- [Unreleased]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.66.7...HEAD
1144
+ [Unreleased]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.67.1...HEAD
1145
+ [0.67.1]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.67.0...v0.67.1
1146
+ [0.67.0]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.66.7...v0.67.0
1132
1147
  [0.66.7]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.66.6...v0.66.7
1133
1148
  [0.66.6]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.66.5...v0.66.6
1134
1149
  [0.66.5]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.66.4...v0.66.5
package/README.md CHANGED
@@ -159,7 +159,7 @@ Build the branded one-click bundle:
159
159
  npm run build:mcpb
160
160
  ```
161
161
 
162
- The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.66.7`, SHA-256 `6afb48b628861b97ac6f28ac21549225a513d34de62892f2c4ac66f1928972c1`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, API-key configuration field, and manually curated current-release message from the bundle manifest.
162
+ The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.67.1`, SHA-256 `257eb19b72d228cc4aec4973778036cfc7c13419da6de35391ea7179ce629a03`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, API-key configuration field, and manually curated current-release message from the bundle manifest.
163
163
 
164
164
  The MCPB install exposes every tool — web-intelligence plus all `browser_*` tools — through the one `mcp-scraper` server.
165
165
 
@@ -174,6 +174,12 @@ function publicErrorType(code) {
174
174
  case "image_redirect_limit":
175
175
  case "image_base64_invalid":
176
176
  case "image_source_missing":
177
+ case "image_source_ambiguous":
178
+ case "image_source_type_invalid":
179
+ case "image_artifact_not_found":
180
+ case "image_page_too_large":
181
+ case "page_image_not_found":
182
+ case "page_image_candidates_unusable":
177
183
  case "image_format_unsupported":
178
184
  case "image_storage_unconfigured":
179
185
  case "featured_image_unhostable":
@@ -270,7 +276,19 @@ function publicErrorMessage(code) {
270
276
  case "image_base64_invalid":
271
277
  return "The supplied inline image bytes are invalid.";
272
278
  case "image_source_missing":
273
- return "Provide either a stable public image URL or inline image bytes.";
279
+ return "Provide exactly one of a public image or webpage URL, inline image bytes, or an owner-scoped image artifact.";
280
+ case "image_source_ambiguous":
281
+ return "Provide only one image source: sourceUrl, imageBase64, or artifactId.";
282
+ case "image_source_type_invalid":
283
+ return "Use sourceType only with inline image bytes or an owner-scoped image artifact.";
284
+ case "image_artifact_not_found":
285
+ return "The image artifact was not found, expired, or does not belong to this account.";
286
+ case "image_page_too_large":
287
+ return "The webpage is too large for bounded Commons image discovery.";
288
+ case "page_image_not_found":
289
+ return "The webpage did not expose a usable featured or content image.";
290
+ case "page_image_candidates_unusable":
291
+ return "The webpage exposed image candidates, but none returned supported public image bytes.";
274
292
  case "image_format_unsupported":
275
293
  return "Commons accepts JPEG, PNG, GIF, or WebP image bytes.";
276
294
  case "image_storage_unconfigured":
@@ -350,6 +368,12 @@ var init_errors = __esm({
350
368
  "image_redirect_limit",
351
369
  "image_base64_invalid",
352
370
  "image_source_missing",
371
+ "image_source_ambiguous",
372
+ "image_source_type_invalid",
373
+ "image_artifact_not_found",
374
+ "image_page_too_large",
375
+ "page_image_not_found",
376
+ "page_image_candidates_unusable",
353
377
  "image_format_unsupported",
354
378
  "image_storage_unconfigured",
355
379
  "featured_image_unhostable"
@@ -11394,7 +11418,8 @@ function firstJsonLdImage(value) {
11394
11418
  }
11395
11419
  return null;
11396
11420
  }
11397
- function firstContentImage(html) {
11421
+ function contentImages(html) {
11422
+ const images = [];
11398
11423
  for (const match of html.matchAll(/<img\b[^>]*>/gi)) {
11399
11424
  const tag = match[0];
11400
11425
  const attr = (name) => tag.match(new RegExp(`\\b${name}\\s*=\\s*(?:"([^"]+)"|'([^']+)'|([^\\s>]+))`, "i"))?.slice(1).find(Boolean) ?? null;
@@ -11405,30 +11430,36 @@ function firstContentImage(html) {
11405
11430
  const width = Number(attr("width") ?? 0);
11406
11431
  const height = Number(attr("height") ?? 0);
11407
11432
  if (width > 0 && width < 200 || height > 0 && height < 120) continue;
11408
- return candidate;
11433
+ images.push(candidate);
11409
11434
  }
11410
- return null;
11435
+ return images;
11411
11436
  }
11412
- function resolveFeaturedImage(input) {
11437
+ function resolveFeaturedImageCandidates(input) {
11413
11438
  const replay = parseWaybackReplayUrl(input.pageUrl);
11414
11439
  const baseUrl = replay?.originalUrl ?? input.pageUrl;
11415
11440
  const candidates = [
11416
11441
  { value: input.meta["og:image"] ?? input.meta["og:image:url"] ?? input.meta["og:image:secure_url"], source: "og:image" },
11417
11442
  { value: input.meta["twitter:image"] ?? input.meta["twitter:image:src"], source: "twitter:image" },
11418
11443
  { value: firstJsonLdImage(input.schema), source: "json-ld" },
11419
- { value: firstContentImage(input.html), source: "content-image" }
11444
+ ...contentImages(input.html).map((value) => ({ value, source: "content-image" }))
11420
11445
  ];
11446
+ const seen = /* @__PURE__ */ new Set();
11447
+ const resolved = [];
11421
11448
  for (const candidate of candidates) {
11422
11449
  if (!candidate.value) continue;
11423
11450
  const url = safeHttpUrl2(candidate.value, baseUrl);
11424
- if (!url) continue;
11425
- return {
11451
+ if (!url || seen.has(url)) continue;
11452
+ seen.add(url);
11453
+ resolved.push({
11426
11454
  url,
11427
11455
  archivedUrl: replay ? buildWaybackReplayUrl(replay.timestamp, url, "im_") : null,
11428
11456
  source: candidate.source
11429
- };
11457
+ });
11430
11458
  }
11431
- return null;
11459
+ return resolved;
11460
+ }
11461
+ function resolveFeaturedImage(input) {
11462
+ return resolveFeaturedImageCandidates(input)[0] ?? null;
11432
11463
  }
11433
11464
  var import_p_limit, WAYBACK_HOSTS, MAX_CDX_RESPONSE_BYTES, MAX_CDX_ROWS, MAX_ARCHIVE_URL_CHARS, MAX_SELECTED_TIMELINE_CELLS, TIMELINE_CDX_CONCURRENCY;
11434
11465
  var init_wayback = __esm({
@@ -50207,7 +50238,7 @@ var PACKAGE_VERSION;
50207
50238
  var init_version = __esm({
50208
50239
  "src/version.ts"() {
50209
50240
  "use strict";
50210
- PACKAGE_VERSION = "0.66.7";
50241
+ PACKAGE_VERSION = "0.67.1";
50211
50242
  }
50212
50243
  });
50213
50244
 
@@ -50278,9 +50309,10 @@ seam is noted so you can chain them.
50278
50309
  guidance, recommended sections, optional sections, and heading guidance before any write occurs.
50279
50310
  - Host a featured image -> **commons_host_image**. The normal write sequence is **commons_prepare_entity ->
50280
50311
  compose the payload -> commons_host_image -> commons_validate_entity -> commons_submit_entity**. Put the
50281
- permanent returned URL in featuredImage.url. Use imageBase64 for available attachment bytes within the request
50282
- bound, or a stable direct public HTTPS image URL; never use a caller-local path, opaque chat attachment reference,
50283
- HTML page, private URL, or temporary/signed URL.
50312
+ permanent returned URL in featuredImage.url. Use imageBase64 for pasted or AI-generated bytes, artifactId for an
50313
+ owner-scoped MCP Scraper image artifact, or sourceUrl for either a public HTTPS image or a webpage containing one.
50314
+ Webpage discovery tries Open Graph, Twitter, JSON-LD, then meaningful content images. Never pass a caller-local
50315
+ path, opaque chat attachment reference, or private/authenticated URL.
50284
50316
  - Validate a composed entity without writing -> **commons_validate_entity**. Use it after image hosting and before
50285
50317
  submit. Validation does not fetch or store image bytes; an external/unregistered featured image is reported in
50286
50318
  imageDiagnostics as not publishable until commons_host_image returns its permanent Commons URL. Validation also
@@ -52031,7 +52063,7 @@ var init_contracts = __esm({
52031
52063
  });
52032
52064
 
52033
52065
  // src/mcp/mcp-tool-schemas.ts
52034
- var import_zod45, WEBSITE_URL_OR_DOMAIN_ERROR, WebsiteUrlOrDomainSchema, HarvestPaaInputSchema, HarvestPaaHostedInputSchema, ExtractUrlBaseInputSchema, ExtractUrlInputSchema, ExtractUrlLocalInputSchema, DiffPageBaseInputSchema, DiffPageInputSchema, DiffPageLocalInputSchema, MapSiteUrlsInputSchema, MapWaybackSnapshotsInputSchema, ExtractSiteInputSchema, AnalyzeSiteSimilarityInputSchema, AuditSiteInputSchema, CheckSiteExportInputSchema, SiteExportReadInputSchema, SiteExportImageInputSchema, ArchiveReadInputSchema, YoutubeHarvestInputSchema, YoutubeTranscribeInputSchema, FacebookPageIntelInputSchema, FacebookAdSearchInputSchema, RedditThreadInputSchema, RedditTrendingInputSchema, VideoFrameAnalysisInputSchema, VideoFrameAnalysisStatusInputSchema, FacebookAdTranscribeInputSchema, FacebookVideoTranscribeInputSchema, GoogleAdsSearchInputSchema, GoogleAdsPageIntelInputSchema, GoogleAdsTranscribeInputSchema, InstagramProfileContentInputSchema, InstagramMediaDownloadInputSchema, MapsPlaceIntelInputSchema, TrustpilotReviewsInputSchema, G2ReviewsInputSchema, ReviewCardSchema, MapsSearchInputSchema, DirectoryWorkflowInputSchema, LeadScalarSchema2, LeadRowSchema, LeadColumnMapSchema2, LeadRowsImportSourceSchema, LeadCsvTextImportSourceSchema, LeadUploadImportSourceSchema, LeadListUploadStartInputSchema, LeadListImportInputSchema, LeadRowsEnrichmentSourceSchema, ImportedLeadListSourceSchema, LeadListEnrichInputSchema, LeadListEnrichStatusInputSchema, LocationMarketsInputSchema, CommonsSearchEntitiesInputSchema, CommonsGetEntityInputSchema, CommonsGetEntityLinksetInputSchema, CommonsFeaturedImageInputSchema, CommonsMediaInputSchema, CommonsCitationInputSchema, CommonsSourceInputSchema, CommonsRelatedLinkInputSchema, CommonsClaimInputSchema, CommonsPrepareEntityInputSchema, CommonsSubmitEntityInputSchema, CommonsValidateEntityInputSchema, CommonsGetEntityLedgerInputSchema, CommonsHostImageInputSchema, CommonsGetProposalInputSchema, CommonsSaveFilterInputSchema, CommonsListFiltersInputSchema, CommonsListNeedsLinksInputSchema, CommonsGenericOutputSchema, CommonsFeaturedImageDiagnosticsOutputSchema, CommonsValidateEntityOutputSchema, DirectoryWorkflowStatusInputSchema, LocalSourcebookSubmitInputSchema, LocalSourcebookCategorySchema, LocalSourcebookSchemaTypeInputSchema, LocalSourcebookTagCandidateObjectSchema, LocalSourcebookTagDecisionObjectSchema, LocalSourcebookIdentityObjectSchema, GetLocalSourcebookContractInputSchema, ListLocalSourcebookTagsInputSchema, ResolveLocalSourcebookTagsInputSchema, PrepareLocalSourcebookWriteInputSchema, ValidateLocalSourcebookWriteInputSchema, LocalSourcebookCaptureInputSchema, LocalSourcebookSubmissionStatusInputSchema, LocalSourcebookRefreshInputSchema, LocalSourcebookOutputSchema, ArtifactPointerOutputSchema, EditorialReadingRoomSiteSchema, EditorialReadingRoomImageSchema, EditorialReadingRoomArticleSchema, EditorialReadingRoomGuideInputSchema, EditorialReadingRoomGuideOutputSchema, CreateEditorialReadingRoomInputSchema, EditorialReadingRoomArtifactSchema, CreateEditorialReadingRoomOutputSchema, RenewEditorialReadingRoomDownloadInputSchema, RenewEditorialReadingRoomDownloadOutputSchema, CommonsPublicationSubdomainSchema, CommonsPreparePublicationInputSchema, CommonsValidatePublicationInputSchema, CommonsClaimPublicationInputSchema, CommonsPublishEditorialInputSchema, CommonsUpdateEditorialArticleInputSchema, CommonsGetPublicationInputSchema, RankTrackerModeSchema, RankTrackerBlueprintInputSchema, NullableString, MapsSearchAttemptOutput, MapsSearchOutputSchema, DirectoryMapsBusinessOutput, DirectoryCsvArtifactOutput, DirectoryWorkflowOutputSchema, LeadSuggestedColumnOutputSchema, LeadColumnMapSuggestionOutputSchema, LeadArtifactOutputSchema, LeadListUploadStartOutputSchema, LeadListImportOutputSchema, LeadCandidateOutputSchema, LeadProgressOutputSchema, LeadBillingOutputSchema, LeadAssociatedPersonSourceOutputSchema, LeadAssociatedPersonOutputSchema, LeadSampleRowOutputSchema, LeadListEnrichmentOutputSchema, LocationDatasetProvenanceOutput, LocationMarketsOutputSchema, RankTrackerToolPlanOutput, RankTrackerTableOutput, RankTrackerCronJobOutput, RankTrackerBlueprintOutputSchema, OrganicResultOutput, AiOverviewOutput, EntityIdsOutput, HarvestPaaOutputSchema, SearchSerpOutputSchema, PageMediaAssetOutput, PageMediaArtifactOutput, ExtractUrlOutputSchema, DiffPageOutputSchema, ExtractSiteOutputSchema, AuditSiteOutputSchema, CheckSiteExportOutputSchema, SiteExportReadOutputSchema, SiteExportImageOutputSchema, 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;
52066
+ var import_zod45, WEBSITE_URL_OR_DOMAIN_ERROR, WebsiteUrlOrDomainSchema, HarvestPaaInputSchema, HarvestPaaHostedInputSchema, ExtractUrlBaseInputSchema, ExtractUrlInputSchema, ExtractUrlLocalInputSchema, DiffPageBaseInputSchema, DiffPageInputSchema, DiffPageLocalInputSchema, MapSiteUrlsInputSchema, MapWaybackSnapshotsInputSchema, ExtractSiteInputSchema, AnalyzeSiteSimilarityInputSchema, AuditSiteInputSchema, CheckSiteExportInputSchema, SiteExportReadInputSchema, SiteExportImageInputSchema, ArchiveReadInputSchema, YoutubeHarvestInputSchema, YoutubeTranscribeInputSchema, FacebookPageIntelInputSchema, FacebookAdSearchInputSchema, RedditThreadInputSchema, RedditTrendingInputSchema, VideoFrameAnalysisInputSchema, VideoFrameAnalysisStatusInputSchema, FacebookAdTranscribeInputSchema, FacebookVideoTranscribeInputSchema, GoogleAdsSearchInputSchema, GoogleAdsPageIntelInputSchema, GoogleAdsTranscribeInputSchema, InstagramProfileContentInputSchema, InstagramMediaDownloadInputSchema, MapsPlaceIntelInputSchema, TrustpilotReviewsInputSchema, G2ReviewsInputSchema, ReviewCardSchema, MapsSearchInputSchema, DirectoryWorkflowInputSchema, LeadScalarSchema2, LeadRowSchema, LeadColumnMapSchema2, LeadRowsImportSourceSchema, LeadCsvTextImportSourceSchema, LeadUploadImportSourceSchema, LeadListUploadStartInputSchema, LeadListImportInputSchema, LeadRowsEnrichmentSourceSchema, ImportedLeadListSourceSchema, LeadListEnrichInputSchema, LeadListEnrichStatusInputSchema, LocationMarketsInputSchema, CommonsSearchEntitiesInputSchema, CommonsGetEntityInputSchema, CommonsGetEntityLinksetInputSchema, CommonsFeaturedImageInputSchema, CommonsMediaInputSchema, CommonsCitationInputSchema, CommonsSourceInputSchema, CommonsRelatedLinkInputSchema, CommonsClaimInputSchema, CommonsPrepareEntityInputSchema, CommonsSubmitEntityInputSchema, CommonsValidateEntityInputSchema, CommonsGetEntityLedgerInputSchema, CommonsHostImageInputSchema, CommonsHostImageOutputSchema, CommonsGetProposalInputSchema, CommonsSaveFilterInputSchema, CommonsListFiltersInputSchema, CommonsListNeedsLinksInputSchema, CommonsGenericOutputSchema, CommonsFeaturedImageDiagnosticsOutputSchema, CommonsValidateEntityOutputSchema, DirectoryWorkflowStatusInputSchema, LocalSourcebookSubmitInputSchema, LocalSourcebookCategorySchema, LocalSourcebookSchemaTypeInputSchema, LocalSourcebookTagCandidateObjectSchema, LocalSourcebookTagDecisionObjectSchema, LocalSourcebookIdentityObjectSchema, GetLocalSourcebookContractInputSchema, ListLocalSourcebookTagsInputSchema, ResolveLocalSourcebookTagsInputSchema, PrepareLocalSourcebookWriteInputSchema, ValidateLocalSourcebookWriteInputSchema, LocalSourcebookCaptureInputSchema, LocalSourcebookSubmissionStatusInputSchema, LocalSourcebookRefreshInputSchema, LocalSourcebookOutputSchema, ArtifactPointerOutputSchema, EditorialReadingRoomSiteSchema, EditorialReadingRoomImageSchema, EditorialReadingRoomArticleSchema, EditorialReadingRoomGuideInputSchema, EditorialReadingRoomGuideOutputSchema, CreateEditorialReadingRoomInputSchema, EditorialReadingRoomArtifactSchema, CreateEditorialReadingRoomOutputSchema, RenewEditorialReadingRoomDownloadInputSchema, RenewEditorialReadingRoomDownloadOutputSchema, CommonsPublicationSubdomainSchema, CommonsPreparePublicationInputSchema, CommonsValidatePublicationInputSchema, CommonsClaimPublicationInputSchema, CommonsPublishEditorialInputSchema, CommonsUpdateEditorialArticleInputSchema, CommonsGetPublicationInputSchema, RankTrackerModeSchema, RankTrackerBlueprintInputSchema, NullableString, MapsSearchAttemptOutput, MapsSearchOutputSchema, DirectoryMapsBusinessOutput, DirectoryCsvArtifactOutput, DirectoryWorkflowOutputSchema, LeadSuggestedColumnOutputSchema, LeadColumnMapSuggestionOutputSchema, LeadArtifactOutputSchema, LeadListUploadStartOutputSchema, LeadListImportOutputSchema, LeadCandidateOutputSchema, LeadProgressOutputSchema, LeadBillingOutputSchema, LeadAssociatedPersonSourceOutputSchema, LeadAssociatedPersonOutputSchema, LeadSampleRowOutputSchema, LeadListEnrichmentOutputSchema, LocationDatasetProvenanceOutput, LocationMarketsOutputSchema, RankTrackerToolPlanOutput, RankTrackerTableOutput, RankTrackerCronJobOutput, RankTrackerBlueprintOutputSchema, OrganicResultOutput, AiOverviewOutput, EntityIdsOutput, HarvestPaaOutputSchema, SearchSerpOutputSchema, PageMediaAssetOutput, PageMediaArtifactOutput, ExtractUrlOutputSchema, DiffPageOutputSchema, ExtractSiteOutputSchema, AuditSiteOutputSchema, CheckSiteExportOutputSchema, SiteExportReadOutputSchema, SiteExportImageOutputSchema, 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;
52035
52067
  var init_mcp_tool_schemas = __esm({
52036
52068
  "src/mcp/mcp-tool-schemas.ts"() {
52037
52069
  "use strict";
@@ -52444,7 +52476,7 @@ var init_mcp_tool_schemas = __esm({
52444
52476
  idOrSlug: import_zod45.z.string().trim().min(1).max(180).describe("Transparent Commons TPW-Q entity id or /wiki/ slug whose governed RFC 9264 linkset should be read.")
52445
52477
  };
52446
52478
  CommonsFeaturedImageInputSchema = import_zod45.z.object({
52447
- url: import_zod45.z.string().url().describe("For a publish-ready entity, use the permanent URL returned by commons_host_image. Submit can auto-host a stable direct public HTTPS image URL as a compatibility fallback, but validation reports any unregistered external URL as not ready. Do not use a chat attachment reference, caller-local path, temporary or signed URL, private URL, or HTML page URL."),
52479
+ url: import_zod45.z.string().url().describe("For a publish-ready entity, use the permanent URL returned by commons_host_image. Validation reports any unregistered external URL as not ready. Do not use a chat attachment reference, caller-local path, private URL, or HTML page URL here; pass the original image or webpage source to commons_host_image first."),
52448
52480
  alt: import_zod45.z.string().trim().max(500).optional(),
52449
52481
  caption: import_zod45.z.string().trim().max(1e3).optional(),
52450
52482
  sourceUrl: import_zod45.z.string().url().optional(),
@@ -52543,7 +52575,7 @@ var init_mcp_tool_schemas = __esm({
52543
52575
  entityId: import_zod45.z.string().trim().max(80).optional().describe("Existing Transparent Public Wiki entity id when proposing an edit. New entities normally omit this and receive a TPW-Q id."),
52544
52576
  entityType: import_zod45.z.string().trim().max(120).default("PublicArticle").describe("Backend Wikidata-style type. Prefer precise entity classes such as SoftwareApplication, Organization, Person, Event, Place, Taxon, ScienceConcept, MathConcept, TechArticle, or PublicArticle; the public article structure should match the selected type."),
52545
52577
  disambiguationName: import_zod45.z.string().trim().max(240).optional().describe("Clarifying name used when the concept could be confused with another entity."),
52546
- featuredImage: CommonsFeaturedImageInputSchema.optional().describe("Required for auto-published public entities. First call commons_host_image and place its returned permanent URL here; validation does not fetch external images and reports unregistered URLs as not publishable. Submit retains a compatibility fallback that auto-hosts a stable direct public HTTPS image URL. The image is also added to the media manifest if absent."),
52578
+ featuredImage: CommonsFeaturedImageInputSchema.optional().describe("Required for auto-published public entities. First call commons_host_image with attachment bytes, an image artifact, a direct image URL, or a webpage URL, then place its returned permanent URL here. Validation does not fetch external images and reports unregistered URLs as not publishable. Submit retains a compatibility fallback for public URLs. The image is also added to the media manifest if absent."),
52547
52579
  source: CommonsSourceInputSchema.optional().describe("Source provenance. Store original URL, source byline, and origin canonical here; canonical does not replace rights review."),
52548
52580
  tags: import_zod45.z.array(import_zod45.z.string().trim().min(1).max(80)).max(24).optional().describe("Standardized topic tags. Use existing/searchable concepts when possible."),
52549
52581
  keywords: import_zod45.z.array(import_zod45.z.string().trim().min(1).max(120)).max(50).optional().describe("SEO and retrieval keywords."),
@@ -52605,12 +52637,31 @@ var init_mcp_tool_schemas = __esm({
52605
52637
  idOrSlug: import_zod45.z.string().trim().min(1).max(180).describe("Published entity id or /wiki/ slug whose contribution ledger should be read.")
52606
52638
  };
52607
52639
  CommonsHostImageInputSchema = {
52608
- sourceUrl: import_zod45.z.string().url().optional().describe("Stable direct public HTTPS URL whose response is the image bytes to host. Do not pass an HTML webpage, chat attachment reference, caller-local path, temporary or signed URL, or private/authenticated URL."),
52609
- imageBase64: import_zod45.z.string().min(16).optional().describe("Base64 image bytes for an image you already hold, including forwarded chat attachment bytes. Prefer this over a temporary attachment URL when the serialized request remains under about 3 MB; larger files require a stable direct public HTTPS source URL."),
52640
+ sourceUrl: import_zod45.z.string().url().optional().describe("Public HTTPS direct image URL or webpage URL. A direct image is hosted as-is; an HTML page is inspected for Open Graph, Twitter, JSON-LD, and meaningful content images, then the first usable candidate is hosted. Temporary signed URLs are consumed immediately and query credentials are not retained as provenance."),
52641
+ imageBase64: import_zod45.z.string().min(16).optional().describe("Base64 image bytes for an image already available to the caller, including a pasted attachment or AI-generated image. Use sourceType to preserve whether it was uploaded or generated. Keep the complete serialized request within the client transport limit."),
52642
+ artifactId: import_zod45.z.string().trim().min(1).max(500).optional().describe("Owner-scoped image artifact returned by an MCP Scraper media or screenshot workflow. The server reauthorizes ownership and reads the bytes directly; do not construct an artifact ID."),
52643
+ sourceType: import_zod45.z.enum(["uploaded", "ai_generated"]).optional().describe("Provenance for imageBase64 or artifactId. Use ai_generated only when an image model created the supplied bytes; otherwise use uploaded or omit it."),
52610
52644
  alt: import_zod45.z.string().trim().max(500).optional().describe("Alt text describing the image for readers who cannot see it."),
52611
52645
  license: import_zod45.z.string().trim().max(240).optional().describe("License or usage terms of the original image, preserved with the hosted copy."),
52612
52646
  attribution: import_zod45.z.string().trim().max(500).optional().describe("Credit line for the original photographer, publication, or archive.")
52613
52647
  };
52648
+ CommonsHostImageOutputSchema = {
52649
+ ok: import_zod45.z.boolean(),
52650
+ data: import_zod45.z.object({
52651
+ id: import_zod45.z.string().describe("Stable Commons image ID."),
52652
+ url: import_zod45.z.string().url().describe("Permanent Commons URL to use as featuredImage.url."),
52653
+ contentType: import_zod45.z.enum(["image/jpeg", "image/png", "image/gif", "image/webp"]),
52654
+ bytes: import_zod45.z.number().int().positive(),
52655
+ digest: import_zod45.z.string(),
52656
+ sourceUrl: import_zod45.z.string().url().nullable().describe("Sanitized direct asset URL that supplied the hosted bytes, when applicable."),
52657
+ sourcePageUrl: import_zod45.z.string().url().nullable().describe("Sanitized webpage URL from which the image was discovered, when applicable."),
52658
+ sourceKind: import_zod45.z.enum(["uploaded", "ai_generated", "artifact", "direct_url", "webpage", "registered"]),
52659
+ selectionSource: import_zod45.z.enum(["provided_bytes", "artifact", "direct_url", "og:image", "twitter:image", "json-ld", "content-image", "registered"]),
52660
+ reused: import_zod45.z.boolean().describe("True when identical image bytes were already stored.")
52661
+ }).optional(),
52662
+ error: import_zod45.z.string().optional(),
52663
+ message: import_zod45.z.string().optional()
52664
+ };
52614
52665
  CommonsGetProposalInputSchema = {
52615
52666
  proposalId: import_zod45.z.string().trim().min(1).max(120).describe("Proposal id returned by commons_submit_entity, in the form commons-proposal-<uuid>.")
52616
52667
  };
@@ -56597,9 +56648,9 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
56597
56648
  }, async (input) => executor.commonsGetEntityLedger(input));
56598
56649
  server.registerTool("commons_host_image", {
56599
56650
  title: "Host a Transparent Commons Image",
56600
- description: "Normal prerequisite for any featured image whose URL was not already returned by commons_host_image. Host image bytes from imageBase64 when you already have an attachment and the serialized request stays under about 3 MB, or from a stable direct public HTTPS image URL; do not pass a webpage, caller-local path, private URL, or temporary/signed attachment URL. Returns the permanent Commons URL to place in featuredImage.url before commons_validate_entity and commons_submit_entity. Submit can still auto-host a stable public source as a compatibility fallback. JPEG, PNG, GIF, and WebP are accepted up to 10 MB; SVG is rejected. Identical bytes are stored once.",
56651
+ description: "Turn one supplied image source into a permanent Transparent Commons image before validation and submission. Provide exactly one of imageBase64 for a pasted or AI-generated image, artifactId for an owner-scoped MCP Scraper image artifact, or sourceUrl for either a direct public HTTPS image or a webpage containing the desired image. Webpages are inspected in deterministic order for Open Graph, Twitter, JSON-LD, and meaningful content images; unusable candidates fall through to the next candidate. Returns the permanent URL for featuredImage.url plus source and selection provenance. JPEG, PNG, GIF, and WebP are accepted up to 10 MB; SVG is rejected. Identical bytes are stored once. Never pass a caller-local path or private/authenticated URL.",
56601
56652
  inputSchema: CommonsHostImageInputSchema,
56602
- outputSchema: recordOutputSchema("commons_host_image", CommonsGenericOutputSchema),
56653
+ outputSchema: recordOutputSchema("commons_host_image", CommonsHostImageOutputSchema),
56603
56654
  annotations: {
56604
56655
  title: "Host a Transparent Commons Image",
56605
56656
  readOnlyHint: false,
@@ -57141,6 +57192,18 @@ async function readResponseData(res) {
57141
57192
  return text2;
57142
57193
  }
57143
57194
  }
57195
+ function attachJsonStructuredContent(result) {
57196
+ if (result.isError || result.structuredContent) return result;
57197
+ const text2 = result.content.find((part) => part.type === "text");
57198
+ if (!text2 || text2.type !== "text") return result;
57199
+ try {
57200
+ const parsed = JSON.parse(text2.text);
57201
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return result;
57202
+ return { ...result, structuredContent: parsed };
57203
+ } catch {
57204
+ return result;
57205
+ }
57206
+ }
57144
57207
  function httpErrorPayload(path6, res, data) {
57145
57208
  const objectData = data && typeof data === "object" && !Array.isArray(data) ? data : null;
57146
57209
  const rawCode = objectData?.code ?? objectData?.errorCode ?? objectData?.error_code;
@@ -57760,8 +57823,8 @@ var init_http_mcp_tool_executor = __esm({
57760
57823
  commonsGetProposal(input) {
57761
57824
  return this.getJson(`/commons/proposals/${encodeURIComponent(input.proposalId)}`);
57762
57825
  }
57763
- commonsHostImage(input) {
57764
- return this.call("/commons/images", input);
57826
+ async commonsHostImage(input) {
57827
+ return attachJsonStructuredContent(await this.call("/commons/images", input));
57765
57828
  }
57766
57829
  commonsUpdateEditorialArticle(input) {
57767
57830
  const { idempotencyKey: idempotencyKey4, ...body } = input;
@@ -72162,6 +72225,9 @@ async function assertPublicHttpsUrl(rawUrl) {
72162
72225
  if (url.protocol !== "https:") {
72163
72226
  throw new CommonsImageError("image_url_not_https", "Commons image sources must be https URLs.");
72164
72227
  }
72228
+ if (url.username || url.password) {
72229
+ throw new CommonsImageError("image_url_invalid", "Commons image source URLs cannot contain embedded credentials.");
72230
+ }
72165
72231
  const hostname = url.hostname.replace(/^\[|\]$/g, "");
72166
72232
  const addresses = (0, import_node_net2.isIP)(hostname) ? [{ address: hostname }] : await (0, import_promises16.lookup)(hostname, { all: true }).catch(() => []);
72167
72233
  if (!addresses.length) {
@@ -72172,7 +72238,28 @@ async function assertPublicHttpsUrl(rawUrl) {
72172
72238
  }
72173
72239
  return url;
72174
72240
  }
72175
- async function downloadImage(sourceUrl) {
72241
+ async function readResponseBytes(response, maxBytes) {
72242
+ const declaredLength = Number(response.headers.get("content-length") ?? "0");
72243
+ if (declaredLength > maxBytes) {
72244
+ throw new CommonsImageError("image_too_large", `Source exceeds the ${maxBytes} byte limit.`, 413);
72245
+ }
72246
+ if (!response.body) return Buffer.alloc(0);
72247
+ const reader = response.body.getReader();
72248
+ const chunks = [];
72249
+ let total = 0;
72250
+ while (true) {
72251
+ const { done, value } = await reader.read();
72252
+ if (done) break;
72253
+ total += value.byteLength;
72254
+ if (total > maxBytes) {
72255
+ await reader.cancel().catch(() => void 0);
72256
+ throw new CommonsImageError("image_too_large", `Source exceeds the ${maxBytes} byte limit.`, 413);
72257
+ }
72258
+ chunks.push(Buffer.from(value));
72259
+ }
72260
+ return Buffer.concat(chunks, total);
72261
+ }
72262
+ async function downloadPublicSource(sourceUrl) {
72176
72263
  let current = sourceUrl;
72177
72264
  for (let redirect = 0; redirect <= COMMONS_IMAGE_MAX_REDIRECTS; redirect += 1) {
72178
72265
  const url = await assertPublicHttpsUrl(current);
@@ -72207,15 +72294,11 @@ async function downloadImage(sourceUrl) {
72207
72294
  retryable
72208
72295
  );
72209
72296
  }
72210
- const declaredLength = Number(response.headers.get("content-length") ?? "0");
72211
- if (declaredLength > COMMONS_IMAGE_MAX_BYTES) {
72212
- throw new CommonsImageError("image_too_large", `Image exceeds the ${COMMONS_IMAGE_MAX_BYTES} byte limit.`, 413);
72213
- }
72214
- const bytes = Buffer.from(await response.arrayBuffer());
72215
- if (bytes.length > COMMONS_IMAGE_MAX_BYTES) {
72216
- throw new CommonsImageError("image_too_large", `Image exceeds the ${COMMONS_IMAGE_MAX_BYTES} byte limit.`, 413);
72217
- }
72218
- return bytes;
72297
+ return {
72298
+ bytes: await readResponseBytes(response, COMMONS_IMAGE_MAX_BYTES),
72299
+ finalUrl: url.toString(),
72300
+ contentType: (response.headers.get("content-type") ?? "").split(";")[0].trim().toLowerCase()
72301
+ };
72219
72302
  }
72220
72303
  throw new CommonsImageError("image_redirect_limit", "Image source exceeded the redirect limit.");
72221
72304
  }
@@ -72228,6 +72311,114 @@ function decodeBase64Image(value) {
72228
72311
  }
72229
72312
  return bytes;
72230
72313
  }
72314
+ function safeProvenanceUrl(rawUrl) {
72315
+ try {
72316
+ const url = new URL(rawUrl);
72317
+ url.username = "";
72318
+ url.password = "";
72319
+ url.search = "";
72320
+ url.hash = "";
72321
+ return url.toString();
72322
+ } catch {
72323
+ return null;
72324
+ }
72325
+ }
72326
+ function looksLikeHtml(bytes, declaredType) {
72327
+ if (declaredType === "text/html" || declaredType === "application/xhtml+xml") return true;
72328
+ const prefix = bytes.subarray(0, 512).toString("utf8").trimStart().toLowerCase();
72329
+ return prefix.startsWith("<!doctype html") || prefix.startsWith("<html") || prefix.startsWith("<head");
72330
+ }
72331
+ async function resolveCommonsImageSource(input) {
72332
+ const supplied = [input.sourceUrl, input.imageBase64, input.artifactId].filter((value) => Boolean(value)).length;
72333
+ if (supplied === 0) {
72334
+ throw new CommonsImageError("image_source_missing", "Provide exactly one of sourceUrl, imageBase64, or artifactId.");
72335
+ }
72336
+ if (supplied !== 1) {
72337
+ throw new CommonsImageError("image_source_ambiguous", "Provide only one image source: sourceUrl, imageBase64, or artifactId.");
72338
+ }
72339
+ if (input.sourceUrl && input.sourceType) {
72340
+ throw new CommonsImageError("image_source_type_invalid", "sourceType applies only to imageBase64 or artifactId, not sourceUrl.");
72341
+ }
72342
+ if (input.imageBase64) {
72343
+ return {
72344
+ bytes: decodeBase64Image(input.imageBase64),
72345
+ sourceUrl: null,
72346
+ sourcePageUrl: null,
72347
+ sourceKind: input.sourceType ?? "uploaded",
72348
+ selectionSource: "provided_bytes"
72349
+ };
72350
+ }
72351
+ if (input.artifactId) {
72352
+ const bytes = await readOwnedImageSourceArtifact({ artifactId: input.artifactId, ownerId: String(input.userId) });
72353
+ if (!bytes) {
72354
+ throw new CommonsImageError("image_artifact_not_found", "The image artifact was not found, expired, or is not owned by this account.", 422);
72355
+ }
72356
+ if (bytes.length > COMMONS_IMAGE_MAX_BYTES) {
72357
+ throw new CommonsImageError("image_too_large", `Image exceeds the ${COMMONS_IMAGE_MAX_BYTES} byte limit.`, 413);
72358
+ }
72359
+ return {
72360
+ bytes,
72361
+ sourceUrl: null,
72362
+ sourcePageUrl: null,
72363
+ sourceKind: input.sourceType ?? "artifact",
72364
+ selectionSource: "artifact"
72365
+ };
72366
+ }
72367
+ const requestedUrl = String(input.sourceUrl);
72368
+ const downloaded = await downloadPublicSource(requestedUrl);
72369
+ if (sniffImageFormat(downloaded.bytes)) {
72370
+ return {
72371
+ bytes: downloaded.bytes,
72372
+ sourceUrl: safeProvenanceUrl(downloaded.finalUrl),
72373
+ sourcePageUrl: null,
72374
+ sourceKind: "direct_url",
72375
+ selectionSource: "direct_url"
72376
+ };
72377
+ }
72378
+ if (!looksLikeHtml(downloaded.bytes, downloaded.contentType)) {
72379
+ throw new CommonsImageError(
72380
+ "image_format_unsupported",
72381
+ "The supplied URL returned neither a supported image nor an HTML webpage with a discoverable image.",
72382
+ 415
72383
+ );
72384
+ }
72385
+ if (downloaded.bytes.length > COMMONS_IMAGE_PAGE_MAX_BYTES) {
72386
+ throw new CommonsImageError("image_page_too_large", `Webpage exceeds the ${COMMONS_IMAGE_PAGE_MAX_BYTES} byte discovery limit.`, 413);
72387
+ }
72388
+ const html = downloaded.bytes.toString("utf8");
72389
+ const document2 = loadHtmlDocument(html);
72390
+ const candidates = resolveFeaturedImageCandidates({
72391
+ html,
72392
+ meta: document2.meta,
72393
+ schema: document2.schema,
72394
+ pageUrl: downloaded.finalUrl
72395
+ }).slice(0, COMMONS_IMAGE_MAX_PAGE_CANDIDATES);
72396
+ if (!candidates.length) {
72397
+ throw new CommonsImageError("page_image_not_found", "The webpage did not expose a usable featured or content image.", 422);
72398
+ }
72399
+ let sawRetryableFailure = false;
72400
+ for (const candidate of candidates) {
72401
+ try {
72402
+ const image = await downloadPublicSource(candidate.url);
72403
+ if (!sniffImageFormat(image.bytes)) continue;
72404
+ return {
72405
+ bytes: image.bytes,
72406
+ sourceUrl: safeProvenanceUrl(image.finalUrl),
72407
+ sourcePageUrl: safeProvenanceUrl(downloaded.finalUrl),
72408
+ sourceKind: "webpage",
72409
+ selectionSource: candidate.source
72410
+ };
72411
+ } catch (error) {
72412
+ if (error instanceof CommonsImageError && error.retryable) sawRetryableFailure = true;
72413
+ }
72414
+ }
72415
+ throw new CommonsImageError(
72416
+ "page_image_candidates_unusable",
72417
+ "The webpage exposed image candidates, but none returned supported public image bytes.",
72418
+ 422,
72419
+ sawRetryableFailure
72420
+ );
72421
+ }
72231
72422
  function commonsImageBlobStore() {
72232
72423
  const token6 = process.env.COMMONS_IMAGE_READ_WRITE_TOKEN?.trim() || process.env.COMMONS_IMAGE_BLOB_READ_WRITE_TOKEN?.trim() || process.env.BLOB_READ_WRITE_TOKEN?.trim();
72233
72424
  return token6 ? new VercelBlobStore(token6) : getBlobStore();
@@ -72259,16 +72450,21 @@ async function findCommonsHostedImageByUrl(rawUrl) {
72259
72450
  bytes: Number(row.bytes),
72260
72451
  digest: String(row.digest),
72261
72452
  sourceUrl: row.source_url ? String(row.source_url) : null,
72453
+ sourcePageUrl: null,
72454
+ sourceKind: "registered",
72455
+ selectionSource: "registered",
72262
72456
  reused: true
72263
72457
  };
72264
72458
  }
72265
72459
  async function hostCommonsImage(input) {
72266
72460
  if (hostOverride) return hostOverride(input);
72267
72461
  await ensureCommonsImageSchema();
72268
- if (!input.sourceUrl && !input.imageBase64) {
72269
- throw new CommonsImageError("image_source_missing", "Provide either sourceUrl or imageBase64.");
72462
+ if (input.sourceUrl && !input.imageBase64 && !input.artifactId && !input.sourceType) {
72463
+ const registered6 = await findCommonsHostedImageByUrl(input.sourceUrl);
72464
+ if (registered6) return registered6;
72270
72465
  }
72271
- const bytes = input.imageBase64 ? decodeBase64Image(input.imageBase64) : await downloadImage(String(input.sourceUrl));
72466
+ const resolved = await resolveCommonsImageSource(input);
72467
+ const bytes = resolved.bytes;
72272
72468
  const contentType = sniffImageFormat(bytes);
72273
72469
  if (!contentType) {
72274
72470
  throw new CommonsImageError(
@@ -72290,7 +72486,10 @@ async function hostCommonsImage(input) {
72290
72486
  contentType: String(reusable.content_type),
72291
72487
  bytes: Number(reusable.bytes),
72292
72488
  digest: digest2,
72293
- sourceUrl: reusable.source_url ? String(reusable.source_url) : null,
72489
+ sourceUrl: resolved.sourceUrl,
72490
+ sourcePageUrl: resolved.sourcePageUrl,
72491
+ sourceKind: resolved.sourceKind,
72492
+ selectionSource: resolved.selectionSource,
72294
72493
  reused: true
72295
72494
  };
72296
72495
  }
@@ -72319,14 +72518,25 @@ async function hostCommonsImage(input) {
72319
72518
  stored.url,
72320
72519
  contentType,
72321
72520
  bytes.length,
72322
- input.sourceUrl ?? null,
72521
+ resolved.sourceUrl,
72323
72522
  input.alt ?? null,
72324
72523
  input.license ?? null,
72325
72524
  input.attribution ?? null,
72326
72525
  (/* @__PURE__ */ new Date()).toISOString()
72327
72526
  ]
72328
72527
  });
72329
- return { id, url: stored.url, contentType, bytes: bytes.length, digest: digest2, sourceUrl: input.sourceUrl ?? null, reused: false };
72528
+ return {
72529
+ id,
72530
+ url: stored.url,
72531
+ contentType,
72532
+ bytes: bytes.length,
72533
+ digest: digest2,
72534
+ sourceUrl: resolved.sourceUrl,
72535
+ sourcePageUrl: resolved.sourcePageUrl,
72536
+ sourceKind: resolved.sourceKind,
72537
+ selectionSource: resolved.selectionSource,
72538
+ reused: false
72539
+ };
72330
72540
  }
72331
72541
  async function hostEntityImages(input) {
72332
72542
  const rewrite = { mediaUrls: /* @__PURE__ */ new Map(), dropped: [] };
@@ -72368,7 +72578,7 @@ async function hostEntityImages(input) {
72368
72578
  }
72369
72579
  return rewrite;
72370
72580
  }
72371
- var import_node_crypto46, import_promises16, import_node_net2, COMMONS_IMAGE_MAX_BYTES, COMMONS_IMAGE_MAX_REDIRECTS, COMMONS_IMAGE_FETCH_TIMEOUT_MS, COMMONS_IMAGE_RETRY_GUIDANCE, CommonsImageError, imageSchemaReady, imageSchemaDb, hostOverride;
72581
+ var import_node_crypto46, import_promises16, import_node_net2, COMMONS_IMAGE_MAX_BYTES, COMMONS_IMAGE_MAX_REDIRECTS, COMMONS_IMAGE_FETCH_TIMEOUT_MS, COMMONS_IMAGE_PAGE_MAX_BYTES, COMMONS_IMAGE_MAX_PAGE_CANDIDATES, COMMONS_IMAGE_RETRY_GUIDANCE, CommonsImageError, imageSchemaReady, imageSchemaDb, hostOverride;
72372
72582
  var init_commons_image_store = __esm({
72373
72583
  "src/api/commons-image-store.ts"() {
72374
72584
  "use strict";
@@ -72377,10 +72587,15 @@ var init_commons_image_store = __esm({
72377
72587
  import_node_net2 = require("net");
72378
72588
  init_blob_store();
72379
72589
  init_db();
72590
+ init_image_source_artifacts();
72591
+ init_html_document();
72592
+ init_wayback();
72380
72593
  COMMONS_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
72381
72594
  COMMONS_IMAGE_MAX_REDIRECTS = 3;
72382
72595
  COMMONS_IMAGE_FETCH_TIMEOUT_MS = 2e4;
72383
- COMMONS_IMAGE_RETRY_GUIDANCE = "Call commons_host_image with a different stable public HTTPS image URL or imageBase64, replace featuredImage.url with the returned URL, validate again, then retry commons_submit_entity with the same idempotency key.";
72596
+ COMMONS_IMAGE_PAGE_MAX_BYTES = 2 * 1024 * 1024;
72597
+ COMMONS_IMAGE_MAX_PAGE_CANDIDATES = 12;
72598
+ COMMONS_IMAGE_RETRY_GUIDANCE = "Call commons_host_image with imageBase64, an owner-authorized artifactId, a public HTTPS image URL, or a public HTTPS webpage containing a usable featured image. Replace featuredImage.url with the returned permanent URL, validate again, then retry commons_submit_entity with the same idempotency key.";
72384
72599
  CommonsImageError = class extends Error {
72385
72600
  constructor(code, message, httpStatus = 400, retryable = false, retryGuidance = COMMONS_IMAGE_RETRY_GUIDANCE) {
72386
72601
  super(message);
@@ -75926,11 +76141,13 @@ var init_commons_routes = __esm({
75926
76141
  HostImageSchema = import_zod54.z.object({
75927
76142
  sourceUrl: import_zod54.z.string().url().optional(),
75928
76143
  imageBase64: import_zod54.z.string().min(16).optional(),
76144
+ artifactId: import_zod54.z.string().min(1).max(500).optional(),
76145
+ sourceType: import_zod54.z.enum(["uploaded", "ai_generated"]).optional(),
75929
76146
  alt: import_zod54.z.string().max(500).optional(),
75930
76147
  license: import_zod54.z.string().max(240).optional(),
75931
76148
  attribution: import_zod54.z.string().max(500).optional()
75932
- }).strict().refine((body) => Boolean(body.sourceUrl || body.imageBase64), {
75933
- message: "Provide either sourceUrl or imageBase64."
76149
+ }).strict().refine((body) => [body.sourceUrl, body.imageBase64, body.artifactId].filter(Boolean).length === 1, {
76150
+ message: "Provide exactly one of sourceUrl, imageBase64, or artifactId."
75934
76151
  });
75935
76152
  commonsApp.post("/images", auth2, async (c) => {
75936
76153
  const parsed = HostImageSchema.safeParse(await c.req.json().catch(() => ({})));
@@ -17,9 +17,9 @@ loadDotEnv();
17
17
  async function main() {
18
18
  const [{ serve }, { app }, { startWorker }, { migrate }] = await Promise.all([
19
19
  import("@hono/node-server"),
20
- import("../server-KSVJ4X4V.js"),
21
- import("../worker-IBLGV272.js"),
22
- import("../db-MNNNIWVS.js")
20
+ import("../server-ROIJWWJG.js"),
21
+ import("../worker-JGWV2LID.js"),
22
+ import("../db-ZGZAKYBW.js")
23
23
  ]);
24
24
  const PORT = parseInt(process.env.PORT ?? "3001");
25
25
  try {
@@ -30,7 +30,7 @@ var import_promises5 = require("fs/promises");
30
30
  var import_node_path3 = require("path");
31
31
 
32
32
  // src/version.ts
33
- var PACKAGE_VERSION = "0.66.7";
33
+ var PACKAGE_VERSION = "0.67.1";
34
34
 
35
35
  // src/cli/agent-config.ts
36
36
  function apiKeyValue(options) {
@@ -13,7 +13,7 @@ import "../chunk-VXLU74YZ.js";
13
13
  import "../chunk-GGZEC22A.js";
14
14
  import {
15
15
  PACKAGE_VERSION
16
- } from "../chunk-7KB5QTHP.js";
16
+ } from "../chunk-VES63X4Q.js";
17
17
 
18
18
  // src/cli/human-cli.ts
19
19
  import { Command } from "commander";
@@ -3,7 +3,7 @@
3
3
 
4
4
  // release-message.json
5
5
  var release_message_default = {
6
- message: "Transparent Commons now verifies featured-image readiness before publishing, and replacement integration connections keep their paid period."
6
+ message: "Transparent Commons image hosting now accepts the source a user has and returns the same permanent-image result in both readable and typed MCP channels."
7
7
  };
8
8
 
9
9
  // src/install-terminal.ts
@@ -112,7 +112,7 @@ function renderInstallTerminal(options) {
112
112
  }
113
113
 
114
114
  // src/version.ts
115
- var PACKAGE_VERSION = "0.66.7";
115
+ var PACKAGE_VERSION = "0.67.1";
116
116
 
117
117
  // bin/mcp-scraper-install.ts
118
118
  var noColor = process.argv.includes("--no-color") || process.env.NO_COLOR !== void 0 || process.env.FORCE_COLOR === "0" || !process.stdout.isTTY;