mcp-scraper 0.83.0 → 0.83.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.
- package/CHANGELOG.md +16 -1
- package/README.md +1 -1
- package/dist/bin/api-server.js +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-core.js +3 -3
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.js +3 -3
- package/dist/{chunk-AIVNZZO3.js → chunk-22SQKQCO.js} +2 -2
- package/dist/{chunk-QSZXAA5F.js → chunk-2SUX4DKY.js} +1 -1
- package/dist/{chunk-FUG2IRKP.js → chunk-I4KYWMZB.js} +1 -1
- package/dist/{server-ICMRDYI4.js → server-S7EUK25A.js} +39 -6
- 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.83.2] - 2026-09-01
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Scoped auto-discovered X-Ray click and form rules to the route where each CTA was observed, preventing shared selectors from tagging unrelated pages.
|
|
12
|
+
- Made runtime health report only route-eligible rules and made setup verification retain the strongest observed selector match across routes instead of an arbitrary database row.
|
|
13
|
+
|
|
14
|
+
## [0.83.1] - 2026-09-01
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Allowed the X-Ray Pixel to authenticate normal same-origin runtime-manifest and health requests from their approved `Referer` hostname when browsers omit the `Origin` header, while preserving approved-domain enforcement and failing closed when neither header identifies an HTTP origin.
|
|
19
|
+
|
|
7
20
|
## [0.83.0] - 2026-09-01
|
|
8
21
|
|
|
9
22
|
### Added
|
|
@@ -1579,7 +1592,9 @@ All notable changes to MCP Scraper are documented here. The format is based on [
|
|
|
1579
1592
|
- Write actions remain unavailable until the account owner explicitly enables them.
|
|
1580
1593
|
- Provider-specific connection data is normalized into one agent-facing contract.
|
|
1581
1594
|
|
|
1582
|
-
[Unreleased]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.
|
|
1595
|
+
[Unreleased]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.83.2...HEAD
|
|
1596
|
+
[0.83.2]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.83.1...v0.83.2
|
|
1597
|
+
[0.83.1]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.83.0...v0.83.1
|
|
1583
1598
|
[0.83.0]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.82.0...v0.83.0
|
|
1584
1599
|
[0.82.0]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.81.0...v0.82.0
|
|
1585
1600
|
[0.81.0]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.80.0...v0.81.0
|
package/README.md
CHANGED
|
@@ -175,7 +175,7 @@ Build the branded one-click bundle:
|
|
|
175
175
|
npm run build:mcpb
|
|
176
176
|
```
|
|
177
177
|
|
|
178
|
-
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.83.
|
|
178
|
+
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.83.2`, SHA-256 `1bca7955ad6eb8d1d67da62a2ac77d69275a937805fb926583f8086baddcc7c1`). 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.
|
|
179
179
|
|
|
180
180
|
The MCPB install exposes every tool — web-intelligence plus all `browser_*` tools — through the one `mcp-scraper` server.
|
|
181
181
|
|
package/dist/bin/api-server.js
CHANGED
|
@@ -17,7 +17,7 @@ loadDotEnv();
|
|
|
17
17
|
async function main() {
|
|
18
18
|
const [{ serve }, { app, personalAssistantProductionStartup }, { startWorker }, { migrate }] = await Promise.all([
|
|
19
19
|
import("@hono/node-server"),
|
|
20
|
-
import("../server-
|
|
20
|
+
import("../server-S7EUK25A.js"),
|
|
21
21
|
import("../worker-FM3ZRDY4.js"),
|
|
22
22
|
import("../db-Z34LPZNR.js")
|
|
23
23
|
]);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runMcpScraperStdio
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-22SQKQCO.js";
|
|
5
|
+
import "../chunk-2SUX4DKY.js";
|
|
6
6
|
import "../chunk-PGJQDMC2.js";
|
|
7
7
|
import "../chunk-DNM65UCK.js";
|
|
8
8
|
import "../chunk-T3MZISOF.js";
|
|
@@ -13,7 +13,7 @@ import "../chunk-OPQIGAFB.js";
|
|
|
13
13
|
import "../chunk-UXVT7FWW.js";
|
|
14
14
|
import "../chunk-BGD7U3AE.js";
|
|
15
15
|
import "../chunk-GGZEC22A.js";
|
|
16
|
-
import "../chunk-
|
|
16
|
+
import "../chunk-I4KYWMZB.js";
|
|
17
17
|
import "../chunk-YXNDOQXN.js";
|
|
18
18
|
|
|
19
19
|
// src/mcp/thorbit-restricted-tool-surface.ts
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "../chunk-UXVT7FWW.js";
|
|
5
5
|
import {
|
|
6
6
|
PACKAGE_VERSION
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-I4KYWMZB.js";
|
|
8
8
|
|
|
9
9
|
// bin/mcp-scraper-install.ts
|
|
10
10
|
var noColor = process.argv.includes("--no-color") || process.env.NO_COLOR !== void 0 || process.env.FORCE_COLOR === "0" || !process.stdout.isTTY;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runMcpScraperStdio
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-22SQKQCO.js";
|
|
5
|
+
import "../chunk-2SUX4DKY.js";
|
|
6
6
|
import "../chunk-PGJQDMC2.js";
|
|
7
7
|
import "../chunk-DNM65UCK.js";
|
|
8
8
|
import "../chunk-T3MZISOF.js";
|
|
@@ -13,7 +13,7 @@ import "../chunk-OPQIGAFB.js";
|
|
|
13
13
|
import "../chunk-UXVT7FWW.js";
|
|
14
14
|
import "../chunk-BGD7U3AE.js";
|
|
15
15
|
import "../chunk-GGZEC22A.js";
|
|
16
|
-
import "../chunk-
|
|
16
|
+
import "../chunk-I4KYWMZB.js";
|
|
17
17
|
import "../chunk-YXNDOQXN.js";
|
|
18
18
|
|
|
19
19
|
// bin/mcp-stdio-server.ts
|
|
@@ -12,13 +12,13 @@ import {
|
|
|
12
12
|
registerScheduledResultsMcpTools,
|
|
13
13
|
registerSerpIntelligenceCaptureTools,
|
|
14
14
|
resolveDeploymentProfile
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-2SUX4DKY.js";
|
|
16
16
|
import {
|
|
17
17
|
renderInstallTerminal
|
|
18
18
|
} from "./chunk-UXVT7FWW.js";
|
|
19
19
|
import {
|
|
20
20
|
PACKAGE_VERSION
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-I4KYWMZB.js";
|
|
22
22
|
|
|
23
23
|
// src/mcp/stdio-runtime.ts
|
|
24
24
|
import { readFileSync } from "fs";
|
|
@@ -373,7 +373,7 @@ import {
|
|
|
373
373
|
resolveLocalSourcebookSchemaType,
|
|
374
374
|
transcribeMediaUrl,
|
|
375
375
|
transitionAnalyticsExperiment
|
|
376
|
-
} from "./chunk-
|
|
376
|
+
} from "./chunk-2SUX4DKY.js";
|
|
377
377
|
import {
|
|
378
378
|
auditImageUrls,
|
|
379
379
|
auditImages,
|
|
@@ -494,7 +494,7 @@ import {
|
|
|
494
494
|
} from "./chunk-GGZEC22A.js";
|
|
495
495
|
import {
|
|
496
496
|
PACKAGE_VERSION
|
|
497
|
-
} from "./chunk-
|
|
497
|
+
} from "./chunk-I4KYWMZB.js";
|
|
498
498
|
import {
|
|
499
499
|
CaptchaError,
|
|
500
500
|
MapsSearchIncompletePageError,
|
|
@@ -53247,6 +53247,14 @@ function normalizedSetupHostname(startUrl) {
|
|
|
53247
53247
|
throw new AnalyticsRepositoryError("analytics_setup_start_url_invalid", "Provide a valid public HTTP or HTTPS startUrl.", 400);
|
|
53248
53248
|
}
|
|
53249
53249
|
}
|
|
53250
|
+
function bestAnalyticsRuleHealthRows(rows) {
|
|
53251
|
+
const best = /* @__PURE__ */ new Map();
|
|
53252
|
+
for (const row of rows) {
|
|
53253
|
+
const observed = best.get(row.rule_id);
|
|
53254
|
+
if (!observed || row.match_count > observed.match_count) best.set(row.rule_id, row);
|
|
53255
|
+
}
|
|
53256
|
+
return best;
|
|
53257
|
+
}
|
|
53250
53258
|
async function approvedSetupSite(input) {
|
|
53251
53259
|
const hostname = normalizedSetupHostname(input.startUrl);
|
|
53252
53260
|
const normalizedHost2 = hostname.replace(/^www\./, "");
|
|
@@ -53294,6 +53302,7 @@ function analyticsSiteSetupService() {
|
|
|
53294
53302
|
eventName: candidate.eventName,
|
|
53295
53303
|
triggerKind: candidate.action === "submit" ? "form" : "click",
|
|
53296
53304
|
selector: candidate.selector,
|
|
53305
|
+
path: candidate.routePath,
|
|
53297
53306
|
pathMatch: "exact",
|
|
53298
53307
|
hostnames: [hostname],
|
|
53299
53308
|
metadata: candidate.context,
|
|
@@ -53323,7 +53332,7 @@ function analyticsSiteSetupService() {
|
|
|
53323
53332
|
db.query("SELECT count(*)::int AS count FROM analytics_events WHERE site_id=$1 AND received_at >= now()-interval '1 day'", [record7.siteId]),
|
|
53324
53333
|
currentManifest ? db.query("SELECT rule_id,rule_version,match_count,route_path FROM analytics_runtime_rule_health WHERE site_id=$1 AND manifest_id=$2", [record7.siteId, currentManifest.manifestId]) : Promise.resolve({ rows: [] })
|
|
53325
53334
|
]);
|
|
53326
|
-
const healthByRule =
|
|
53335
|
+
const healthByRule = bestAnalyticsRuleHealthRows(ruleHealth.rows);
|
|
53327
53336
|
return {
|
|
53328
53337
|
inventory: capture.inventory,
|
|
53329
53338
|
requiredSemanticActions: Math.max(1, record7.outcomePlan.semanticActions.length),
|
|
@@ -53841,6 +53850,9 @@ function safeOrigin(origin) {
|
|
|
53841
53850
|
return null;
|
|
53842
53851
|
}
|
|
53843
53852
|
}
|
|
53853
|
+
function resolveAnalyticsPublicRequestOrigin(input) {
|
|
53854
|
+
return safeOrigin(input.origin) ?? safeOrigin(input.referer);
|
|
53855
|
+
}
|
|
53844
53856
|
function dashboardOriginAllowed(origin) {
|
|
53845
53857
|
if (origin === "https://mcpscraper.dev" || origin === "https://www.mcpscraper.dev")
|
|
53846
53858
|
return true;
|
|
@@ -53899,6 +53911,24 @@ function analyticsPixelSdk() {
|
|
|
53899
53911
|
function analyticsDefinitionLoaderSdk() {
|
|
53900
53912
|
return `;(()=>{const s=document.currentScript||document.querySelector('script[src*="/analytics/v1/pixel.js"][data-pixel]');if(!s)return;const pixel=s.dataset.pixel,api=window.mcpAnalytics;if(!pixel||!api)return;const endpoint=new URL('/analytics/v1/pixels/'+encodeURIComponent(pixel)+'/runtime-manifest',s.src).toString(),healthEndpoint=new URL('/analytics/v1/pixels/'+encodeURIComponent(pixel)+'/runtime-health',s.src).toString(),eventPattern=/^[a-z][a-z0-9_]{1,79}$/;let definitions=[],manifest=null,rollback=[],observer=null,contexts=[],expiryTimer=null;const hostname=location.hostname.toLowerCase().replace(/\\.$/,''),cacheKey='mcp_xray_manifest_'+pixel,assignmentKey=id=>'mcp_xray_experiment_'+id,consented=()=>{try{return api.debug().consent.purposes.site_analytics==='granted'&&!navigator.globalPrivacyControl}catch{return false}},onHost=d=>!Array.isArray(d.hostnames)||d.hostnames.length===0||d.hostnames.includes(hostname),bounded=(value,max)=>typeof value==='string'&&value.trim()?value.trim().slice(0,max):undefined,dimension=value=>{const v=bounded(value,80),digits=v&&v.match(/\\d/g);return v&&/^[a-z][a-z0-9_-]{0,79}$/i.test(v)&&(!digits||digits.length<7)?v.toLowerCase():undefined},validCurrency=value=>{const currency=typeof value==='string'?value.trim():'';return /^[a-z]{3}$/i.test(currency)?currency.toUpperCase():undefined},safeMetadata=value=>{const input=value&&typeof value==='object'?value:{},out={};if(typeof input.value==='number'&&Number.isFinite(input.value)&&input.value>=0)out.value=Math.min(input.value,1e12);const currency=validCurrency(input.currency);if(currency)out.currency=currency;for(const [from,to,max] of [['orderId','order_id',200],['contentId','content_id',200],['contentType','content_type',80]]){const v=bounded(input[from],max);if(v)out[to]=v}for(const key of ['placement','component','action','destination','plan']){const v=dimension(input[key]);if(v)out[key]=v}return out},tagMetadata=element=>{const out={};for(const [attr,key] of [['data-xray-placement','placement'],['data-xray-component','component'],['data-xray-action','action'],['data-xray-destination','destination'],['data-xray-plan','plan']]){const value=dimension(element.getAttribute(attr));if(value)out[key]=value}const amount=Number(element.getAttribute('data-xray-value'));if(Number.isFinite(amount)&&amount>=0)out.value=Math.min(amount,1e12);const currency=validCurrency(element.getAttribute('data-xray-currency'));if(currency)out.currency=currency;for(const [attr,key,max] of [['data-xray-order-id','order_id',200],['data-xray-content-id','content_id',200],['data-xray-content-type','content_type',80]]){const value=bounded(element.getAttribute(attr),max);if(value)out[key]=value}return out},seen=d=>{if(!d.oncePerSession)return false;try{return sessionStorage.getItem('mcp_xray_rule_'+d.id+'_'+d.version)==='1'}catch{return false}},mark=d=>{if(!d.oncePerSession)return;try{sessionStorage.setItem('mcp_xray_rule_'+d.id+'_'+d.version,'1')}catch{}},fire=(d,properties={})=>{if(!consented()||!onHost(d)||seen(d))return;const evidence=typeof d.id==='string'&&Number.isInteger(d.version)?{eventDefinitionId:d.id,eventDefinitionVersion:d.version}:{};api.track(d.eventName,{...safeMetadata(d.metadata),...properties,xray_definition:bounded(d.name,120),xray_trigger:d.triggerKind,xray_manifest_revision:manifest&&manifest.revision,xray_manifest_digest:manifest&&manifest.digest},evidence);mark(d)},matches=(target,selector)=>{try{return target instanceof Element&&Boolean(target.closest(selector))}catch{return false}},pageMatches=d=>onHost(d)&&d.triggerKind==='page'&&(d.pathMatch==='prefix'?location.pathname.startsWith(d.path):location.pathname===d.path),firePages=()=>definitions.filter(pageMatches).forEach(d=>fire(d)),fireSemantic=(target,interaction,fired)=>{if(!consented()||!(target instanceof Element))return;const element=target.closest('[data-xray-event]');if(!element||interaction==='click'&&element.tagName==='FORM'||interaction==='submit'&&element.tagName!=='FORM')return;const eventName=(element.getAttribute('data-xray-event')||'').trim();if(eventName.length>80||!eventPattern.test(eventName))return;const configured=definitions.filter(d=>d.triggerKind==='semantic'&&d.eventName===eventName&&onHost(d));if(configured.length)configured.forEach(d=>{if(!fired.has(d.id)){fired.add(d.id);fire(d,tagMetadata(element))}});else api.track(eventName,{...tagMetadata(element),xray_trigger:'semantic'})},restore=()=>{for(const item of rollback.splice(0).reverse()){try{if(item.kind==='replace_text')item.node.textContent=item.value;else if(item.kind==='set_style_token'){if(item.value===null)item.node.removeAttribute('data-xray-style-token');else item.node.setAttribute('data-xray-style-token',item.value)}else if(item.kind==='swap_image'){item.node.setAttribute('src',item.src);item.node.setAttribute('alt',item.alt)}else if(item.kind==='move_relative'&&item.parent)item.parent.insertBefore(item.node,item.next);else if(item.kind==='set_visibility')item.node.hidden=item.hidden}catch{}}},hash=value=>{let h=2166136261;for(let i=0;i<value.length;i++){h^=value.charCodeAt(i);h=Math.imul(h,16777619)}return(h>>>0)/4294967296},fingerprint=value=>{const part=Math.floor(hash(value)*4294967296).toString(16).padStart(8,'0');return part.repeat(8)},assigned=experiment=>{try{const existing=localStorage.getItem(assignmentKey(experiment.experimentId));if(existing){const parsed=JSON.parse(existing);if(parsed.revision===experiment.revision&&experiment.variants.some(v=>v.variantId===parsed.variantId))return parsed.variantId}const unit=(experiment.assignmentUnit==='session'?api.debug().sessionId:api.debug().visitorId)||'anonymous',bucket=hash(experiment.experimentId+':'+experiment.revision+':'+unit);let cursor=0,selected=experiment.variants[experiment.variants.length-1];for(const variant of experiment.variants){cursor+=variant.allocation;if(bucket<cursor){selected=variant;break}}localStorage.setItem(assignmentKey(experiment.experimentId),JSON.stringify({revision:experiment.revision,variantId:selected.variantId}));return selected.variantId}catch{return null}},safeSelector=value=>typeof value==='string'&&value.length>0&&value.length<=500&&!/[{};]/.test(value),applyOperation=(operation,index)=>{if(!safeSelector(operation.selector))return false;const matched=document.querySelectorAll(operation.selector);if(matched.length!==1)return false;const node=matched[0];if(!(node instanceof Element))return false;if(operation.kind==='replace_text'&&typeof operation.text==='string'&&!/[<>]/.test(operation.text)&&operation.text.length<=240){rollback.push({kind:operation.kind,node,value:node.textContent});node.textContent=operation.text;return true}if(operation.kind==='set_style_token'&&['cta_primary','cta_secondary','cta_contrast','muted','highlight'].includes(operation.token)){rollback.push({kind:operation.kind,node,value:node.getAttribute('data-xray-style-token')});node.setAttribute('data-xray-style-token',operation.token);return true}if(operation.kind==='swap_image'&&node instanceof HTMLImageElement&&typeof operation.src==='string'&&operation.src.startsWith('https://')&&typeof operation.alt==='string'&&operation.alt.length<=240){rollback.push({kind:operation.kind,node,src:node.src,alt:node.alt});node.src=operation.src;node.alt=operation.alt;return true}if(operation.kind==='move_relative'&&safeSelector(operation.anchorSelector)){const anchor=document.querySelector(operation.anchorSelector);if(!(anchor instanceof Element)||!anchor.parentNode||node.parentNode!==anchor.parentNode)return false;rollback.push({kind:operation.kind,node,parent:node.parentNode,next:node.nextSibling});anchor.parentNode.insertBefore(node,operation.position==='before'?anchor:anchor.nextSibling);return true}if(operation.kind==='set_visibility'&&typeof operation.visible==='boolean'){rollback.push({kind:operation.kind,node,hidden:node.hidden});node.hidden=!operation.visible;return true}return false},experimentsEligible=()=>manifest&&!manifest.killSwitch&&Date.parse(manifest.expiresAt)>Date.now()&&consented(),applyExperiments=()=>{restore();contexts=[];if(!experimentsEligible())return;let selectedExperiment=false;for(const experiment of manifest.experiments||[]){if(selectedExperiment)continue;if(!['canary','active'].includes(experiment.state)||Date.parse(experiment.expiresAt)<=Date.now()||!experiment.audience.routePrefixes.some(path=>location.pathname.startsWith(path)))continue;if(experiment.state==='canary'&&new URLSearchParams(location.search).get('xray_canary')!==experiment.experimentId)continue;if(experiment.state==='active'&&experiment.audience.trafficClass!=='production'&&s.dataset.trafficClass!==experiment.audience.trafficClass)continue;const variantId=assigned(experiment),variant=experiment.variants.find(v=>v.variantId===variantId);if(!variant)continue;const assignmentKeyValue='mcp_xray_assignment_'+experiment.experimentId+'_'+experiment.revision+'_'+variant.variantId;let assignmentSeen=false;try{const storage=experiment.assignmentUnit==='session'?sessionStorage:localStorage;assignmentSeen=storage.getItem(assignmentKeyValue)==='1';if(!assignmentSeen)storage.setItem(assignmentKeyValue,'1')}catch{}if(!assignmentSeen)queueMicrotask(()=>api.track('xray_experiment_assignment',{experiment_id:experiment.experimentId,experiment_revision:experiment.revision,variant_id:variant.variantId}));let applied=true;const applyStarted=performance.now();for(let i=0;i<variant.operations.length;i++)applied=applyOperation(variant.operations[i],i)&&applied;if(performance.now()-applyStarted>experiment.performanceGuardrailMs)applied=false;if(!applied)restore();else{selectedExperiment=true;contexts=[{experimentId:experiment.experimentId,revision:experiment.revision,variantId:variant.variantId}];const exposureKey='mcp_xray_exposure_'+experiment.experimentId+'_'+experiment.revision+'_'+variant.variantId;let exposed=false;try{exposed=sessionStorage.getItem(exposureKey)==='1';if(!exposed)sessionStorage.setItem(exposureKey,'1')}catch{}if(!exposed)queueMicrotask(()=>api.track('xray_experiment_exposure',{experiment_id:experiment.experimentId,experiment_revision:experiment.revision,variant_id:variant.variantId,traffic_class:experiment.audience.trafficClass}))}}},health=()=>{if(!manifest||!Array.isArray(definitions)||!consented())return;const rules=definitions.filter(d=>d.selector).slice(0,100).map(d=>{let count=0;try{count=Math.min(100,document.querySelectorAll(d.selector).length)}catch{}return{manifestRevision:manifest.revision,manifestDigest:manifest.digest,ruleId:d.id,ruleVersion:d.version,routePath:location.pathname,selectorQuality:d.selector.startsWith('[data-xray-event')?'portable':d.selector.startsWith('#')?'stable':'fragile',matchCount:count,structuralFingerprint:fingerprint([d.id,d.version,location.pathname,d.selector,count].join(':')),observedAt:new Date().toISOString()}});if(rules.length)fetch(healthEndpoint,{method:'POST',headers:{'content-type':'text/plain;charset=UTF-8'},body:JSON.stringify({manifestId:manifest.manifestId,rules}),credentials:'omit',keepalive:true}).catch(()=>{})},reconcile=()=>{if(observer)observer.disconnect();try{health();applyExperiments()}finally{if(observer)observer.observe(document.documentElement,{childList:true,subtree:true})}},stable=value=>Array.isArray(value)?value.map(stable):value&&typeof value==='object'?Object.fromEntries(Object.entries(value).sort(([a],[b])=>a.localeCompare(b)).map(([key,item])=>[key,stable(item)])):value,digestMatches=async candidate=>{if(!candidate||!crypto.subtle||!/^[a-f0-9]{64}$/.test(candidate.digest))return false;const {digest,...unsigned}=candidate,bytes=await crypto.subtle.digest('SHA-256',new TextEncoder().encode(JSON.stringify(stable(unsigned)))),actual=[...new Uint8Array(bytes)].map(byte=>byte.toString(16).padStart(2,'0')).join('');return actual===digest},loadCached=async()=>{try{const cached=JSON.parse(localStorage.getItem(cacheKey)||'null');if(cached&&cached.schemaVersion===1&&Array.isArray(cached.eventRules)&&await digestMatches(cached)){manifest={...cached,experiments:[]};definitions=manifest.eventRules.filter(onHost);firePages();reconcile();return true}}catch{}return false},accept=async body=>{const candidate=body&&body.manifest;if(!candidate||candidate.schemaVersion!==1||!Array.isArray(candidate.eventRules)||!Array.isArray(candidate.experiments)||!(await digestMatches(candidate)))return false;manifest=candidate;definitions=candidate.eventRules.filter(onHost);if(expiryTimer)clearTimeout(expiryTimer);const deadlines=[Date.parse(candidate.expiresAt),...(candidate.experiments||[]).map(item=>Date.parse(item.expiresAt))].filter(Number.isFinite),deadline=Math.min(...deadlines);expiryTimer=setTimeout(()=>{restore();contexts=[]},Math.max(0,Math.min(deadline-Date.now(),2147483647)));try{localStorage.setItem(cacheKey,JSON.stringify(candidate))}catch{}firePages();reconcile();return true};const baseTrack=api.track.bind(api);api.track=(name,properties={},...rest)=>{const context=contexts[0];return baseTrack(name,context?{...properties,xray_experiment_id:context.experimentId,xray_experiment_revision:context.revision,xray_variant_id:context.variantId}:properties,...rest)};document.addEventListener('click',event=>{const fired=new Set();fireSemantic(event.target,'click',fired);for(const d of definitions.filter(d=>onHost(d)&&d.triggerKind==='click'&&matches(event.target,d.selector)))if(!fired.has(d.id)){fired.add(d.id);fire(d)}},{capture:true,passive:true});document.addEventListener('submit',event=>{const fired=new Set();fireSemantic(event.target,'submit',fired);for(const d of definitions.filter(d=>onHost(d)&&d.triggerKind==='form'&&matches(event.target,d.selector)))if(!fired.has(d.id)){fired.add(d.id);fire(d)}},{capture:true});for(const method of ['pushState','replaceState']){const original=history[method];history[method]=function(...args){const result=original.apply(this,args);queueMicrotask(()=>{firePages();reconcile()});return result}}addEventListener('popstate',()=>queueMicrotask(()=>{firePages();reconcile()}));const originalConsent=api.consent;api.consent=state=>{const result=originalConsent(state);queueMicrotask(()=>{firePages();reconcile()});return result};observer=new MutationObserver(()=>{clearTimeout(observer._xrayTimer);observer._xrayTimer=setTimeout(reconcile,100)});observer.observe(document.documentElement,{childList:true,subtree:true});fetch(endpoint,{credentials:'omit'}).then(r=>r.ok?r.json():null).then(async body=>{if(!(await accept(body)))await loadCached()}).catch(()=>loadCached())})();`;
|
|
53901
53913
|
}
|
|
53914
|
+
function analyticsRouteScopedDefinitionLoaderSdk() {
|
|
53915
|
+
const source = analyticsDefinitionLoaderSdk();
|
|
53916
|
+
const replacements = [
|
|
53917
|
+
[
|
|
53918
|
+
"onHost=d=>!Array.isArray(d.hostnames)||d.hostnames.length===0||d.hostnames.includes(hostname),bounded=",
|
|
53919
|
+
"onHost=d=>!Array.isArray(d.hostnames)||d.hostnames.length===0||d.hostnames.includes(hostname),onRoute=d=>!d.path||(d.pathMatch==='prefix'?location.pathname.startsWith(d.path):location.pathname===d.path),bounded="
|
|
53920
|
+
],
|
|
53921
|
+
["if(!consented()||!onHost(d)||seen(d))return", "if(!consented()||!onHost(d)||!onRoute(d)||seen(d))return"],
|
|
53922
|
+
["d.eventName===eventName&&onHost(d)", "d.eventName===eventName&&onHost(d)&&onRoute(d)"],
|
|
53923
|
+
["definitions.filter(d=>d.selector).slice", "definitions.filter(d=>d.selector&&onHost(d)&&onRoute(d)).slice"],
|
|
53924
|
+
["definitions.filter(d=>onHost(d)&&d.triggerKind==='click'", "definitions.filter(d=>onHost(d)&&onRoute(d)&&d.triggerKind==='click'"],
|
|
53925
|
+
["definitions.filter(d=>onHost(d)&&d.triggerKind==='form'", "definitions.filter(d=>onHost(d)&&onRoute(d)&&d.triggerKind==='form'"]
|
|
53926
|
+
];
|
|
53927
|
+
return replacements.reduce((current, [from, to]) => {
|
|
53928
|
+
if (!current.includes(from)) throw new Error(`analytics_definition_loader_marker_missing:${from}`);
|
|
53929
|
+
return current.replace(from, to);
|
|
53930
|
+
}, source);
|
|
53931
|
+
}
|
|
53902
53932
|
function analyticsLegacyConsentSdk() {
|
|
53903
53933
|
return `;(()=>{const s=document.currentScript||document.querySelector('script[src*="/analytics/v1/pixel.js"][data-pixel]'),api=window.mcpAnalytics;if(!s||!api||s.dataset.consent!=='granted')return;try{localStorage.removeItem('mcp_xray_touches_'+String(s.dataset.pixel||'').replace(/[^a-z0-9]/gi,'_'))}catch{}api.consent({purposes:{site_analytics:'granted',enhanced_matching:'granted',advertising_measurement:'granted'},policyVersion:1,jurisdictionProfile:'legacy_explicit_grant'})})();`;
|
|
53904
53934
|
}
|
|
@@ -54064,7 +54094,7 @@ analyticsApp.get("/health/ready", async (c) => {
|
|
|
54064
54094
|
analyticsApp.get("/v1/pixel.js", (c) => {
|
|
54065
54095
|
c.header("Content-Type", "application/javascript; charset=utf-8");
|
|
54066
54096
|
c.header("Cache-Control", "public, max-age=300");
|
|
54067
|
-
return c.body(`${analyticsPixelSdk()}${analyticsIdentityBridgeSdk()}${analyticsLegacyConsentSdk()}${
|
|
54097
|
+
return c.body(`${analyticsPixelSdk()}${analyticsIdentityBridgeSdk()}${analyticsLegacyConsentSdk()}${analyticsRouteScopedDefinitionLoaderSdk()}${analyticsLinkerSdk()}${analyticsVisualPickerSdk()}${analyticsVisualPickerUxSdk()}${analyticsConsentGatewaySdk()}`);
|
|
54068
54098
|
});
|
|
54069
54099
|
async function publicConsentPixel(c) {
|
|
54070
54100
|
const origin = safeOrigin(c.req.header("origin"));
|
|
@@ -54198,7 +54228,10 @@ async function publicRuntimeContext(c) {
|
|
|
54198
54228
|
const result3 = await getPublicAnalyticsEventDefinitions(publicPixelId);
|
|
54199
54229
|
if (!result3.ownerUserId || !result3.siteId) return { error: c.json({ ok: false, error: "Pixel not found." }, 404) };
|
|
54200
54230
|
if (!await analyticsOwnerHasCurrentEntitlement(result3.ownerUserId)) return { error: c.json({ ok: false, error: "X-Ray subscription required." }, 402) };
|
|
54201
|
-
const origin =
|
|
54231
|
+
const origin = resolveAnalyticsPublicRequestOrigin({
|
|
54232
|
+
origin: c.req.header("origin"),
|
|
54233
|
+
referer: c.req.header("referer")
|
|
54234
|
+
});
|
|
54202
54235
|
const hostname = origin ? normalizeAnalyticsHostname(new URL(origin).hostname) : "";
|
|
54203
54236
|
if (!hostname) return { error: c.json({ ok: false, error: "Approved Pixel hostname required." }, 403) };
|
|
54204
54237
|
const approved = await getAnalyticsPool().query(
|
|
@@ -54238,7 +54271,7 @@ analyticsApp.get("/v1/pixels/:publicPixelId/runtime-manifest", async (c) => {
|
|
|
54238
54271
|
});
|
|
54239
54272
|
return c.json({ ok: true, hostname: context.hostname, manifest }, 200, {
|
|
54240
54273
|
"Cache-Control": "public, max-age=60, stale-while-revalidate=300",
|
|
54241
|
-
"Vary": "Origin"
|
|
54274
|
+
"Vary": "Origin, Referer"
|
|
54242
54275
|
});
|
|
54243
54276
|
});
|
|
54244
54277
|
var AnalyticsRuntimeHealthSchema = z44.object({
|