mcp-scraper 0.73.4 → 0.73.6

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 CHANGED
@@ -4,6 +4,18 @@ All notable changes to MCP Scraper are documented here. The format is based on [
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.73.6] - 2026-08-28
8
+
9
+ ### Fixed
10
+
11
+ - Linked retained pixel events and conversions to their sessions through keyed identifiers, restoring enhanced Journey page, event, acquisition, chronology, conversion, and revenue detail after a visitor becomes a known person.
12
+
13
+ ## [0.73.5] - 2026-08-28
14
+
15
+ ### Fixed
16
+
17
+ - Promoted resolved visitor-reference journey details to person presentation, so deterministic identity resolution immediately unlocks the known-person label and authorized masked identity panel across the complete historical journey.
18
+
7
19
  ## [0.73.4] - 2026-08-28
8
20
 
9
21
  ### Fixed
@@ -1334,7 +1346,8 @@ All notable changes to MCP Scraper are documented here. The format is based on [
1334
1346
  - Write actions remain unavailable until the account owner explicitly enables them.
1335
1347
  - Provider-specific connection data is normalized into one agent-facing contract.
1336
1348
 
1337
- [Unreleased]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.73.4...HEAD
1349
+ [Unreleased]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.73.5...HEAD
1350
+ [0.73.5]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.73.4...v0.73.5
1338
1351
  [0.73.4]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.73.3...v0.73.4
1339
1352
  [0.73.3]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.73.2...v0.73.3
1340
1353
  [0.73.2]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.73.1...v0.73.2
package/README.md CHANGED
@@ -173,7 +173,7 @@ Build the branded one-click bundle:
173
173
  npm run build:mcpb
174
174
  ```
175
175
 
176
- 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.73.4`, SHA-256 `f5edf036670debed712e2bbf421f45da59dc4aabee1ad505b8a5824de232f7ed`). 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.
176
+ 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.73.6`, SHA-256 `8998408725170b1d2a1998f15dd31d1fa6d32d27ae5fda53181557ebf80f3284`). 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.
177
177
 
178
178
  The MCPB install exposes every tool — web-intelligence plus all `browser_*` tools — through the one `mcp-scraper` server.
179
179
 
@@ -84,7 +84,7 @@ import {
84
84
  updateAnalyticsPixel,
85
85
  upsertAnalyticsAdSpend,
86
86
  upsertAnalyticsHostGroup
87
- } from "./chunk-M6XDENOO.js";
87
+ } from "./chunk-52PVP5P2.js";
88
88
  import "./chunk-PJEEKOUM.js";
89
89
  import "./chunk-WEFPBAAG.js";
90
90
  export {
@@ -17,7 +17,7 @@ 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-YZJPP6CB.js"),
20
+ import("../server-6JEC3JHU.js"),
21
21
  import("../worker-CBK5DWEE.js"),
22
22
  import("../db-566MOHHD.js")
23
23
  ]);
@@ -25,7 +25,7 @@ async function main() {
25
25
  try {
26
26
  await migrate();
27
27
  if (process.env.ANALYTICS_DATABASE_URL) {
28
- const { migrateAnalytics } = await import("../analytics-repository-7XYPQ2YJ.js");
28
+ const { migrateAnalytics } = await import("../analytics-repository-22MAFYHS.js");
29
29
  await migrateAnalytics();
30
30
  }
31
31
  startWorker();
@@ -13,7 +13,7 @@ import "../chunk-VXLU74YZ.js";
13
13
  import "../chunk-GGZEC22A.js";
14
14
  import {
15
15
  PACKAGE_VERSION
16
- } from "../chunk-LHHUHX5N.js";
16
+ } from "../chunk-4W4TIA3A.js";
17
17
 
18
18
  // src/cli/human-cli.ts
19
19
  import { Command } from "commander";
@@ -4,7 +4,7 @@ import {
4
4
  } from "../chunk-Q2J23DHY.js";
5
5
  import {
6
6
  PACKAGE_VERSION
7
- } from "../chunk-LHHUHX5N.js";
7
+ } from "../chunk-4W4TIA3A.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;
@@ -13,7 +13,7 @@ import {
13
13
  registerScheduledResultsMcpTools,
14
14
  registerSerpIntelligenceCaptureTools,
15
15
  resolveDeploymentProfile
16
- } from "../chunk-EC5X2SNZ.js";
16
+ } from "../chunk-HCBQHUON.js";
17
17
  import "../chunk-PGJQDMC2.js";
18
18
  import "../chunk-T3MZISOF.js";
19
19
  import "../chunk-7RQULQF3.js";
@@ -26,7 +26,7 @@ import "../chunk-VXLU74YZ.js";
26
26
  import "../chunk-GGZEC22A.js";
27
27
  import {
28
28
  PACKAGE_VERSION
29
- } from "../chunk-LHHUHX5N.js";
29
+ } from "../chunk-4W4TIA3A.js";
30
30
  import "../chunk-DNM65UCK.js";
31
31
  import "../chunk-EQJRPDUS.js";
32
32
  import "../chunk-WEFPBAAG.js";
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var PACKAGE_VERSION = "0.73.4";
2
+ var PACKAGE_VERSION = "0.73.6";
3
3
 
4
4
  export {
5
5
  PACKAGE_VERSION
@@ -946,6 +946,8 @@ async function migrateAnalytics() {
946
946
  hostname text NOT NULL,
947
947
  visitor_id text,
948
948
  session_id text,
949
+ visitor_hmac text,
950
+ session_hmac text,
949
951
  event_name text NOT NULL,
950
952
  occurred_at timestamptz NOT NULL,
951
953
  received_at timestamptz NOT NULL DEFAULT now(),
@@ -969,6 +971,7 @@ async function migrateAnalytics() {
969
971
  site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
970
972
  pixel_id uuid REFERENCES analytics_pixels(id) ON DELETE SET NULL,
971
973
  session_id text,
974
+ session_hmac text,
972
975
  conversion_kind text NOT NULL,
973
976
  value_minor bigint NOT NULL DEFAULT 0,
974
977
  currency text NOT NULL DEFAULT 'USD',
@@ -1169,6 +1172,16 @@ async function migrateAnalytics() {
1169
1172
  await client.query(
1170
1173
  `ALTER TABLE analytics_events ADD COLUMN IF NOT EXISTS click_ids jsonb NOT NULL DEFAULT '{}'::jsonb`
1171
1174
  );
1175
+ await client.query(
1176
+ `ALTER TABLE analytics_events ADD COLUMN IF NOT EXISTS visitor_hmac text`
1177
+ );
1178
+ await client.query(
1179
+ `ALTER TABLE analytics_events ADD COLUMN IF NOT EXISTS session_hmac text`
1180
+ );
1181
+ await client.query(
1182
+ `ALTER TABLE analytics_conversions ADD COLUMN IF NOT EXISTS session_hmac text`
1183
+ );
1184
+ await backfillAnalyticsJourneyLinkageHmacs(client);
1172
1185
  await client.query(
1173
1186
  `ALTER TABLE analytics_form_submissions ADD COLUMN IF NOT EXISTS click_ids jsonb NOT NULL DEFAULT '{}'::jsonb`
1174
1187
  );
@@ -2472,6 +2485,15 @@ async function migrateAnalytics() {
2472
2485
  await client.query(
2473
2486
  "CREATE INDEX IF NOT EXISTS analytics_events_site_time ON analytics_events(site_id, occurred_at DESC)"
2474
2487
  );
2488
+ await client.query(
2489
+ "CREATE INDEX IF NOT EXISTS analytics_events_site_session_hmac_time ON analytics_events(site_id, session_hmac, occurred_at DESC)"
2490
+ );
2491
+ await client.query(
2492
+ "CREATE INDEX IF NOT EXISTS analytics_events_site_visitor_hmac_time ON analytics_events(site_id, visitor_hmac, occurred_at DESC)"
2493
+ );
2494
+ await client.query(
2495
+ "CREATE INDEX IF NOT EXISTS analytics_conversions_site_session_hmac_time ON analytics_conversions(site_id, session_hmac, occurred_at DESC)"
2496
+ );
2475
2497
  await client.query(
2476
2498
  "CREATE INDEX IF NOT EXISTS analytics_events_pixel_time ON analytics_events(pixel_id, occurred_at DESC)"
2477
2499
  );
@@ -2603,7 +2625,7 @@ async function migrateAnalytics() {
2603
2625
  );
2604
2626
  await client.query(`
2605
2627
  INSERT INTO analytics_schema_migrations(version)
2606
- VALUES ('2026-08-05.1'), ('2026-08-05.2'), ('2026-08-05.3'), ('2026-08-05.4'), ('2026-08-05.5'), ('2026-08-05.6'), ('2026-08-05.7'), ('2026-08-05.8'), ('2026-08-05.9'), ('2026-08-05.10'), ('2026-08-05.11'), ('2026-08-05.12'), ('2026-08-05.13'), ('2026-08-05.14'), ('2026-08-26.1'), ('2026-08-26.2'), ('2026-08-26.3'), ('2026-08-26.4'), ('2026-08-27.1')
2628
+ VALUES ('2026-08-05.1'), ('2026-08-05.2'), ('2026-08-05.3'), ('2026-08-05.4'), ('2026-08-05.5'), ('2026-08-05.6'), ('2026-08-05.7'), ('2026-08-05.8'), ('2026-08-05.9'), ('2026-08-05.10'), ('2026-08-05.11'), ('2026-08-05.12'), ('2026-08-05.13'), ('2026-08-05.14'), ('2026-08-26.1'), ('2026-08-26.2'), ('2026-08-26.3'), ('2026-08-26.4'), ('2026-08-27.1'), ('2026-08-28.1')
2607
2629
  ON CONFLICT (version) DO NOTHING
2608
2630
  `);
2609
2631
  } catch (error) {
@@ -3623,10 +3645,10 @@ async function ingestAnalyticsEvents(input) {
3623
3645
  occurred_at, path, canonical_url, title, referrer, source, medium, campaign,
3624
3646
  device_class, properties, country_code, region_code, click_ids, person_id,
3625
3647
  channel_family, platform, campaign_id, ad_set_id, ad_id, creative_id, placement, utm_term, utm_content,
3626
- engaged_ms, scroll_depth
3648
+ engaged_ms, scroll_depth, visitor_hmac, session_hmac
3627
3649
  ) VALUES (
3628
3650
  $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18::jsonb, $19, $20, $21::jsonb, $22,
3629
- $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33
3651
+ $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35
3630
3652
  ) ON CONFLICT(site_id, event_id) DO NOTHING`,
3631
3653
  [
3632
3654
  randomUUID2(),
@@ -3661,7 +3683,9 @@ async function ingestAnalyticsEvents(input) {
3661
3683
  attribution.term,
3662
3684
  attribution.content,
3663
3685
  boundedEngagedMs(event.engagedMs),
3664
- boundedScrollDepth(event.scrollDepth)
3686
+ boundedScrollDepth(event.scrollDepth),
3687
+ event.visitorId ? identityHmac("visitor_id", event.visitorId) : null,
3688
+ event.sessionId ? identityHmac("session_id", event.sessionId) : null
3665
3689
  ]
3666
3690
  );
3667
3691
  if (inserted.rowCount) {
@@ -3811,8 +3835,8 @@ async function createAnalyticsConversion(input) {
3811
3835
  const inserted = await client.query(
3812
3836
  `INSERT INTO analytics_conversions(
3813
3837
  id, source_event_id, site_id, pixel_id, session_id, conversion_kind,
3814
- value_minor, currency, occurred_at, person_id, order_id
3815
- ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)
3838
+ value_minor, currency, occurred_at, person_id, order_id, session_hmac
3839
+ ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12)
3816
3840
  ON CONFLICT(site_id, source_event_id) DO NOTHING RETURNING id`,
3817
3841
  [
3818
3842
  proposedId,
@@ -3825,7 +3849,8 @@ async function createAnalyticsConversion(input) {
3825
3849
  (input.currency || "USD").toUpperCase(),
3826
3850
  input.occurredAt,
3827
3851
  resolvedPerson.rows[0]?.person_id ?? null,
3828
- input.orderId ?? null
3852
+ input.orderId ?? null,
3853
+ input.sessionId ? identityHmac("session_id", input.sessionId) : null
3829
3854
  ]
3830
3855
  );
3831
3856
  const created = Boolean(inserted.rowCount);
@@ -4807,6 +4832,54 @@ function sanitizeClickIds(value) {
4807
4832
  function identityHmac(kind, value) {
4808
4833
  return createHmac2("sha256", getSessionSecret()).update(`${kind}:${value.trim().toLowerCase()}`).digest("hex");
4809
4834
  }
4835
+ async function backfillAnalyticsJourneyLinkageHmacs(client) {
4836
+ const batchSize = 500;
4837
+ while (true) {
4838
+ const events = await client.query(
4839
+ `SELECT id, visitor_id, session_id
4840
+ FROM analytics_events
4841
+ WHERE (visitor_id IS NOT NULL AND visitor_hmac IS NULL)
4842
+ OR (session_id IS NOT NULL AND session_hmac IS NULL)
4843
+ ORDER BY id
4844
+ LIMIT $1`,
4845
+ [batchSize]
4846
+ );
4847
+ if (!events.rowCount) break;
4848
+ await client.query(
4849
+ `UPDATE analytics_events e
4850
+ SET visitor_hmac = COALESCE(e.visitor_hmac, patch.visitor_hmac),
4851
+ session_hmac = COALESCE(e.session_hmac, patch.session_hmac)
4852
+ FROM unnest($1::uuid[], $2::text[], $3::text[]) AS patch(id, visitor_hmac, session_hmac)
4853
+ WHERE e.id = patch.id`,
4854
+ [
4855
+ events.rows.map((row) => row.id),
4856
+ events.rows.map((row) => row.visitor_id ? identityHmac("visitor_id", row.visitor_id) : null),
4857
+ events.rows.map((row) => row.session_id ? identityHmac("session_id", row.session_id) : null)
4858
+ ]
4859
+ );
4860
+ }
4861
+ while (true) {
4862
+ const conversions = await client.query(
4863
+ `SELECT id, session_id
4864
+ FROM analytics_conversions
4865
+ WHERE session_id IS NOT NULL AND session_hmac IS NULL
4866
+ ORDER BY id
4867
+ LIMIT $1`,
4868
+ [batchSize]
4869
+ );
4870
+ if (!conversions.rowCount) break;
4871
+ await client.query(
4872
+ `UPDATE analytics_conversions c
4873
+ SET session_hmac = patch.session_hmac
4874
+ FROM unnest($1::uuid[], $2::text[]) AS patch(id, session_hmac)
4875
+ WHERE c.id = patch.id AND c.session_hmac IS NULL`,
4876
+ [
4877
+ conversions.rows.map((row) => row.id),
4878
+ conversions.rows.map((row) => identityHmac("session_id", row.session_id))
4879
+ ]
4880
+ );
4881
+ }
4882
+ }
4810
4883
  function newAnalyticsPersonPublicRef() {
4811
4884
  return `xrp_${randomBytes2(18).toString("base64url")}`;
4812
4885
  }
@@ -32,7 +32,7 @@ import {
32
32
  } from "./chunk-VXLU74YZ.js";
33
33
  import {
34
34
  PACKAGE_VERSION
35
- } from "./chunk-LHHUHX5N.js";
35
+ } from "./chunk-4W4TIA3A.js";
36
36
  import {
37
37
  createPrivateArtifact,
38
38
  privateArtifactOwnerId,
@@ -153,7 +153,7 @@ import {
153
153
  upsertAnalyticsAdSpend,
154
154
  upsertAnalyticsHostGroup,
155
155
  verifyAnalyticsWebhookSignature
156
- } from "./chunk-M6XDENOO.js";
156
+ } from "./chunk-52PVP5P2.js";
157
157
  import {
158
158
  claimServiceConnectionAction,
159
159
  ensureServiceConnectionsSchema,
@@ -280,7 +280,7 @@ import {
280
280
  resolveDeploymentProfile,
281
281
  resolveLocalSourcebookSchemaType,
282
282
  transcribeMediaUrl
283
- } from "./chunk-EC5X2SNZ.js";
283
+ } from "./chunk-HCBQHUON.js";
284
284
  import {
285
285
  auditImageUrls,
286
286
  auditImages,
@@ -345,7 +345,7 @@ import {
345
345
  } from "./chunk-GGZEC22A.js";
346
346
  import {
347
347
  PACKAGE_VERSION
348
- } from "./chunk-LHHUHX5N.js";
348
+ } from "./chunk-4W4TIA3A.js";
349
349
  import {
350
350
  SITE_EXTRACT_ARTIFACT_PREFIX,
351
351
  abandonExtractSettlement,
@@ -34575,17 +34575,17 @@ async function analyticsSessions(input, db = getAnalyticsPool()) {
34575
34575
  FROM analytics_sessions s
34576
34576
  WHERE s.site_id = $1
34577
34577
  ), facts AS (
34578
- SELECT DISTINCT ON (e.session_id)
34579
- e.session_id, e.country_code, e.region_code, e.device_class,
34578
+ SELECT DISTINCT ON (e.session_hmac)
34579
+ e.session_hmac, e.country_code, e.region_code, e.device_class,
34580
34580
  e.source, e.medium, e.campaign
34581
34581
  FROM analytics_events e
34582
34582
  WHERE e.site_id = $1
34583
- ORDER BY e.session_id, e.occurred_at
34583
+ ORDER BY e.session_hmac, e.occurred_at
34584
34584
  ), conversions AS (
34585
- SELECT c.session_id, count(*)::int AS conversion_count,
34585
+ SELECT c.session_hmac, count(*)::int AS conversion_count,
34586
34586
  sum(c.value_minor)::bigint AS revenue_minor,
34587
34587
  CASE WHEN count(DISTINCT c.currency) = 1 THEN min(c.currency) END AS currency
34588
- FROM analytics_conversions c WHERE c.site_id = $1 GROUP BY c.session_id
34588
+ FROM analytics_conversions c WHERE c.site_id = $1 GROUP BY c.session_hmac
34589
34589
  )
34590
34590
  SELECT r.id AS internal_id, r.visitor_hmac, r.person_id, r.started_at, r.last_active_at,
34591
34591
  r.ended_at, r.duration_ms, r.landing_path, r.exit_path, r.pageview_count,
@@ -34593,8 +34593,8 @@ async function analyticsSessions(input, db = getAnalyticsPool()) {
34593
34593
  f.source, f.medium, f.campaign, COALESCE(c.conversion_count, 0)::int AS conversion_count,
34594
34594
  c.revenue_minor, c.currency
34595
34595
  FROM ranked r
34596
- LEFT JOIN facts f ON f.session_id = r.session_hmac
34597
- LEFT JOIN conversions c ON c.session_id = r.session_hmac
34596
+ LEFT JOIN facts f ON f.session_hmac = r.session_hmac
34597
+ LEFT JOIN conversions c ON c.session_hmac = r.session_hmac
34598
34598
  WHERE ($2::timestamptz IS NULL OR (r.started_at, r.id) < ($2::timestamptz, $3::uuid))
34599
34599
  AND ($4::boolean IS NULL OR (r.session_number > 1) = $4)
34600
34600
  AND ($5::boolean IS NULL OR (COALESCE(c.conversion_count, 0) > 0) = $5)
@@ -34602,7 +34602,7 @@ async function analyticsSessions(input, db = getAnalyticsPool()) {
34602
34602
  AND ($7::bigint IS NULL OR r.duration_ms <= $7)
34603
34603
  AND ($8::text IS NULL OR EXISTS (
34604
34604
  SELECT 1 FROM analytics_events ee
34605
- WHERE ee.site_id = $1 AND ee.session_id = r.session_hmac AND ee.event_name = $8
34605
+ WHERE ee.site_id = $1 AND ee.session_hmac = r.session_hmac AND ee.event_name = $8
34606
34606
  ))
34607
34607
  ORDER BY r.started_at DESC, r.id DESC LIMIT $9`, [
34608
34608
  input.siteId,
@@ -34655,7 +34655,7 @@ async function analyticsVisitors(input, db = getAnalyticsPool()) {
34655
34655
  count(*)::int AS conversion_count, sum(c.value_minor)::bigint AS revenue_minor,
34656
34656
  CASE WHEN count(DISTINCT c.currency) = 1 THEN min(c.currency) END AS currency
34657
34657
  FROM analytics_conversions c
34658
- LEFT JOIN analytics_sessions s ON s.site_id=c.site_id AND s.session_hmac=c.session_id
34658
+ LEFT JOIN analytics_sessions s ON s.site_id=c.site_id AND s.session_hmac=c.session_hmac
34659
34659
  WHERE c.site_id=$1 GROUP BY COALESCE(c.person_id::text, s.visitor_hmac)
34660
34660
  )
34661
34661
  SELECT v.*, COALESCE(c.conversion_count,0)::int AS conversion_count, c.revenue_minor, c.currency
@@ -34774,7 +34774,7 @@ async function analyticsSessionTimeline(input, db = getAnalyticsPool()) {
34774
34774
  e.event_name AS name, e.path, e.referrer, e.source, e.medium, e.campaign,
34775
34775
  NULL::bigint AS value_minor, NULL::text AS currency,
34776
34776
  'deterministic'::text AS evidence_class, 'pixel_event'::text AS provenance
34777
- FROM analytics_events e JOIN subject_sessions s ON s.session_hmac=e.session_id AND e.site_id=$1
34777
+ FROM analytics_events e JOIN subject_sessions s ON s.session_hmac=e.session_hmac AND e.site_id=$1
34778
34778
  UNION ALL
34779
34779
  SELECT t.occurred_at, t.id::text, 'touch', COALESCE(t.touch_kind,'touch'), t.landing_path,
34780
34780
  t.referrer, t.source, t.medium, t.campaign, NULL, NULL, 'deterministic', 'attribution_touch'
@@ -34788,13 +34788,13 @@ async function analyticsSessionTimeline(input, db = getAnalyticsPool()) {
34788
34788
  SELECT c.occurred_at, c.id::text, 'conversion', c.conversion_kind, NULL, NULL, NULL, NULL, NULL,
34789
34789
  c.value_minor, c.currency, 'deterministic', COALESCE(c.value_source,'conversion')
34790
34790
  FROM analytics_conversions c
34791
- WHERE c.site_id=$1 AND (c.person_id=$2 OR c.session_id IN (SELECT session_hmac FROM subject_sessions))
34791
+ WHERE c.site_id=$1 AND (c.person_id=$2 OR c.session_hmac IN (SELECT session_hmac FROM subject_sessions))
34792
34792
  UNION ALL
34793
34793
  SELECT e.occurred_at, ve.id::text, 'value', e.event_name, e.path, NULL, e.source, e.medium,
34794
34794
  e.campaign, ve.value_minor, ve.currency, 'deterministic', ve.value_source
34795
34795
  FROM analytics_event_value_evaluations ve
34796
34796
  JOIN analytics_events e ON e.id=ve.source_event_id AND e.site_id=ve.site_id
34797
- JOIN subject_sessions s ON s.session_hmac=e.session_id
34797
+ JOIN subject_sessions s ON s.session_hmac=e.session_hmac
34798
34798
  WHERE ve.site_id=$1
34799
34799
  UNION ALL
34800
34800
  SELECT se.evaluated_at, se.id::text, 'score', sd.name, NULL, NULL, NULL, NULL, NULL,
@@ -34826,12 +34826,12 @@ async function analyticsSessionTimeline(input, db = getAnalyticsPool()) {
34826
34826
  WITH subject_sessions AS (${subjectSessionsSql}), ranged_sessions AS (
34827
34827
  SELECT * FROM subject_sessions WHERE started_at >= $5::timestamptz AND started_at < $6::timestamptz
34828
34828
  ), ranged_events AS (
34829
- SELECT e.* FROM analytics_events e JOIN subject_sessions s ON s.session_hmac=e.session_id
34829
+ SELECT e.* FROM analytics_events e JOIN subject_sessions s ON s.session_hmac=e.session_hmac
34830
34830
  WHERE e.site_id=$1 AND e.occurred_at >= $5::timestamptz AND e.occurred_at < $6::timestamptz
34831
34831
  ), ranged_conversions AS (
34832
34832
  SELECT c.* FROM analytics_conversions c
34833
34833
  WHERE c.site_id=$1 AND c.occurred_at >= $5::timestamptz AND c.occurred_at < $6::timestamptz
34834
- AND (c.person_id=$2 OR c.session_id IN (SELECT session_hmac FROM subject_sessions))
34834
+ AND (c.person_id=$2 OR c.session_hmac IN (SELECT session_hmac FROM subject_sessions))
34835
34835
  )
34836
34836
  SELECT (SELECT (array_agg(person_id ORDER BY started_at) FILTER (WHERE person_id IS NOT NULL))[1]::text FROM subject_sessions) AS resolved_person_id,
34837
34837
  (SELECT count(*)::int FROM ranged_sessions) AS sessions,
@@ -34845,13 +34845,13 @@ async function analyticsSessionTimeline(input, db = getAnalyticsPool()) {
34845
34845
  db.query(`/* analyticsEnhancedJourney:pages */
34846
34846
  WITH subject_sessions AS (${subjectSessionsSql}), pageviews AS (
34847
34847
  SELECT e.path, e.session_id, count(*)::int AS visits
34848
- FROM analytics_events e JOIN subject_sessions s ON s.session_hmac=e.session_id
34848
+ FROM analytics_events e JOIN subject_sessions s ON s.session_hmac=e.session_hmac
34849
34849
  WHERE e.site_id=$1 AND e.event_name='page_view' AND e.path IS NOT NULL
34850
34850
  AND e.occurred_at >= $5::timestamptz AND e.occurred_at < $6::timestamptz
34851
34851
  GROUP BY e.path,e.session_id
34852
34852
  ), engagement AS (
34853
34853
  SELECT e.path, sum(e.engaged_ms)::bigint AS engaged_ms
34854
- FROM analytics_events e JOIN subject_sessions s ON s.session_hmac=e.session_id
34854
+ FROM analytics_events e JOIN subject_sessions s ON s.session_hmac=e.session_hmac
34855
34855
  WHERE e.site_id=$1 AND e.event_name='page_engagement' AND e.path IS NOT NULL AND e.engaged_ms IS NOT NULL
34856
34856
  AND e.occurred_at >= $5::timestamptz AND e.occurred_at < $6::timestamptz GROUP BY e.path
34857
34857
  ), conversion_pages AS (
@@ -34862,7 +34862,7 @@ async function analyticsSessionTimeline(input, db = getAnalyticsPool()) {
34862
34862
  AND e.occurred_at <= c.occurred_at ORDER BY e.occurred_at DESC,e.id DESC LIMIT 1
34863
34863
  ) latest ON true
34864
34864
  WHERE c.site_id=$1 AND c.occurred_at >= $5::timestamptz AND c.occurred_at < $6::timestamptz
34865
- AND (c.person_id=$2 OR c.session_id IN (SELECT session_hmac FROM subject_sessions))
34865
+ AND (c.person_id=$2 OR c.session_hmac IN (SELECT session_hmac FROM subject_sessions))
34866
34866
  GROUP BY latest.path
34867
34867
  )
34868
34868
  SELECT p.path,sum(p.visits)::int AS visits,count(*)::int AS unique_sessions,e.engaged_ms,
@@ -34871,27 +34871,27 @@ async function analyticsSessionTimeline(input, db = getAnalyticsPool()) {
34871
34871
  GROUP BY p.path,e.engaged_ms,c.conversions ORDER BY visits DESC,p.path LIMIT 20`, [...subjectValues]),
34872
34872
  db.query(`/* analyticsEnhancedJourney:acquisition */
34873
34873
  WITH subject_sessions AS (${subjectSessionsSql}), first_touch AS (
34874
- SELECT DISTINCT ON (e.session_id) e.session_id,e.source,e.medium,e.campaign,e.referrer
34875
- FROM analytics_events e JOIN subject_sessions s ON s.session_hmac=e.session_id
34874
+ SELECT DISTINCT ON (e.session_hmac) e.session_hmac,e.source,e.medium,e.campaign,e.referrer
34875
+ FROM analytics_events e JOIN subject_sessions s ON s.session_hmac=e.session_hmac
34876
34876
  WHERE e.site_id=$1 AND e.occurred_at >= $5::timestamptz AND e.occurred_at < $6::timestamptz
34877
- ORDER BY e.session_id,e.occurred_at,e.id
34877
+ ORDER BY e.session_hmac,e.occurred_at,e.id
34878
34878
  ), event_counts AS (
34879
- SELECT e.session_id,count(*)::int AS events FROM analytics_events e JOIN subject_sessions s ON s.session_hmac=e.session_id
34880
- WHERE e.site_id=$1 AND e.occurred_at >= $5::timestamptz AND e.occurred_at < $6::timestamptz GROUP BY e.session_id
34879
+ SELECT e.session_hmac,count(*)::int AS events FROM analytics_events e JOIN subject_sessions s ON s.session_hmac=e.session_hmac
34880
+ WHERE e.site_id=$1 AND e.occurred_at >= $5::timestamptz AND e.occurred_at < $6::timestamptz GROUP BY e.session_hmac
34881
34881
  ), conversion_counts AS (
34882
- SELECT c.session_id,count(*)::int AS conversions FROM analytics_conversions c
34882
+ SELECT c.session_hmac,count(*)::int AS conversions FROM analytics_conversions c
34883
34883
  WHERE c.site_id=$1 AND c.occurred_at >= $5::timestamptz AND c.occurred_at < $6::timestamptz
34884
- AND (c.person_id=$2 OR c.session_id IN (SELECT session_hmac FROM subject_sessions)) GROUP BY c.session_id
34884
+ AND (c.person_id=$2 OR c.session_hmac IN (SELECT session_hmac FROM subject_sessions)) GROUP BY c.session_hmac
34885
34885
  )
34886
34886
  SELECT f.source,f.medium,f.campaign,f.referrer,count(*)::int AS sessions,
34887
34887
  sum(COALESCE(e.events,0))::int AS events,sum(COALESCE(c.conversions,0))::int AS conversions
34888
- FROM first_touch f LEFT JOIN event_counts e USING(session_id) LEFT JOIN conversion_counts c USING(session_id)
34888
+ FROM first_touch f LEFT JOIN event_counts e USING(session_hmac) LEFT JOIN conversion_counts c USING(session_hmac)
34889
34889
  GROUP BY f.source,f.medium,f.campaign,f.referrer ORDER BY sessions DESC,f.source NULLS LAST LIMIT 20`, [...subjectValues]),
34890
34890
  db.query(`/* analyticsEnhancedJourney:events */
34891
34891
  WITH subject_sessions AS (${subjectSessionsSql}), event_groups AS (
34892
34892
  SELECT e.event_name AS name,count(*)::int AS count,count(DISTINCT e.session_id)::int AS unique_sessions,
34893
34893
  array_agg(DISTINCT e.session_id) AS session_ids
34894
- FROM analytics_events e JOIN subject_sessions s ON s.session_hmac=e.session_id
34894
+ FROM analytics_events e JOIN subject_sessions s ON s.session_hmac=e.session_hmac
34895
34895
  WHERE e.site_id=$1 AND e.occurred_at >= $5::timestamptz AND e.occurred_at < $6::timestamptz
34896
34896
  GROUP BY e.event_name
34897
34897
  )
@@ -34904,25 +34904,25 @@ async function analyticsSessionTimeline(input, db = getAnalyticsPool()) {
34904
34904
  WITH subject_sessions AS (${subjectSessionsSql}), ranged_sessions AS (
34905
34905
  SELECT * FROM subject_sessions WHERE started_at >= $5::timestamptz AND started_at < $6::timestamptz
34906
34906
  ), event_stats AS (
34907
- SELECT e.session_id,count(*) FILTER (WHERE e.event_name='page_view')::int AS pageviews,count(*)::int AS events
34908
- FROM analytics_events e JOIN ranged_sessions s ON s.session_hmac=e.session_id
34909
- WHERE e.site_id=$1 AND e.occurred_at >= $5::timestamptz AND e.occurred_at < $6::timestamptz GROUP BY e.session_id
34907
+ SELECT e.session_hmac,count(*) FILTER (WHERE e.event_name='page_view')::int AS pageviews,count(*)::int AS events
34908
+ FROM analytics_events e JOIN ranged_sessions s ON s.session_hmac=e.session_hmac
34909
+ WHERE e.site_id=$1 AND e.occurred_at >= $5::timestamptz AND e.occurred_at < $6::timestamptz GROUP BY e.session_hmac
34910
34910
  ), first_touch AS (
34911
- SELECT DISTINCT ON (e.session_id) e.session_id,e.source,e.medium,e.campaign,e.referrer
34912
- FROM analytics_events e JOIN ranged_sessions s ON s.session_hmac=e.session_id
34913
- WHERE e.site_id=$1 ORDER BY e.session_id,e.occurred_at,e.id
34911
+ SELECT DISTINCT ON (e.session_hmac) e.session_hmac,e.source,e.medium,e.campaign,e.referrer
34912
+ FROM analytics_events e JOIN ranged_sessions s ON s.session_hmac=e.session_hmac
34913
+ WHERE e.site_id=$1 ORDER BY e.session_hmac,e.occurred_at,e.id
34914
34914
  ), conversion_stats AS (
34915
- SELECT c.session_id,count(*)::int AS conversions,sum(c.value_minor)::bigint AS revenue_minor,
34915
+ SELECT c.session_hmac,count(*)::int AS conversions,sum(c.value_minor)::bigint AS revenue_minor,
34916
34916
  CASE WHEN count(DISTINCT c.currency)=1 THEN min(c.currency) END AS currency
34917
- FROM analytics_conversions c JOIN ranged_sessions s ON s.session_hmac=c.session_id
34918
- WHERE c.site_id=$1 AND c.occurred_at >= $5::timestamptz AND c.occurred_at < $6::timestamptz GROUP BY c.session_id
34917
+ FROM analytics_conversions c JOIN ranged_sessions s ON s.session_hmac=c.session_hmac
34918
+ WHERE c.site_id=$1 AND c.occurred_at >= $5::timestamptz AND c.occurred_at < $6::timestamptz GROUP BY c.session_hmac
34919
34919
  )
34920
34920
  SELECT s.id AS internal_id,s.started_at,s.ended_at,s.duration_ms,s.landing_path,s.exit_path,
34921
34921
  COALESCE(e.pageviews,0)::int AS pageviews,COALESCE(e.events,0)::int AS events,
34922
34922
  COALESCE(c.conversions,0)::int AS conversions,c.revenue_minor,c.currency,
34923
34923
  f.source,f.medium,f.campaign,f.referrer
34924
- FROM ranged_sessions s LEFT JOIN event_stats e ON e.session_id=s.session_hmac
34925
- LEFT JOIN first_touch f ON f.session_id=s.session_hmac LEFT JOIN conversion_stats c ON c.session_id=s.session_hmac
34924
+ FROM ranged_sessions s LEFT JOIN event_stats e ON e.session_hmac=s.session_hmac
34925
+ LEFT JOIN first_touch f ON f.session_hmac=s.session_hmac LEFT JOIN conversion_stats c ON c.session_hmac=s.session_hmac
34926
34926
  ORDER BY s.started_at DESC,s.id DESC LIMIT 50`, [...subjectValues])
34927
34927
  ]);
34928
34928
  const rows = result2.rows.map((row) => ({ ...row, _cursorAt: isoTimestamp(row.occurred_at), _cursorId: row.stable_id }));
@@ -34948,11 +34948,12 @@ async function analyticsSessionTimeline(input, db = getAnalyticsPool()) {
34948
34948
  total_engagement_ms: null,
34949
34949
  average_engagement_ms: null
34950
34950
  };
34951
+ const resolvedPersonId = summary.resolved_person_id ?? subject.personId;
34951
34952
  return {
34952
34953
  subject: {
34953
- kind: subject.kind,
34954
+ kind: resolvedPersonId ? "person" : subject.kind,
34954
34955
  reference: input.reference,
34955
- personRef: summary.resolved_person_id ? createAnalyticsReportReference("person", input.siteId, summary.resolved_person_id) : subject.personId ? createAnalyticsReportReference("person", input.siteId, subject.personId) : null
34956
+ personRef: resolvedPersonId ? createAnalyticsReportReference("person", input.siteId, resolvedPersonId) : null
34956
34957
  },
34957
34958
  range: { ...range, fromInclusive: true, toExclusive: true },
34958
34959
  journeyTier: "confirmed",
@@ -35095,17 +35096,17 @@ async function analyticsBestGuessJourneys(input, db = getAnalyticsPool()) {
35095
35096
  (SELECT count(*) FROM analytics_sessions s
35096
35097
  WHERE s.site_id=ca.site_id AND s.visitor_hmac=inode.value_hmac)::int AS session_count,
35097
35098
  (SELECT count(*) FROM analytics_events e JOIN analytics_sessions s
35098
- ON s.site_id=e.site_id AND s.session_hmac=e.session_id
35099
+ ON s.site_id=e.site_id AND s.session_hmac=e.session_hmac
35099
35100
  WHERE e.site_id=ca.site_id AND s.visitor_hmac=inode.value_hmac)::int AS event_count,
35100
35101
  (SELECT count(*) FROM analytics_conversions c JOIN analytics_sessions s
35101
- ON s.site_id=c.site_id AND s.session_hmac=c.session_id
35102
+ ON s.site_id=c.site_id AND s.session_hmac=c.session_hmac
35102
35103
  WHERE c.site_id=ca.site_id AND s.visitor_hmac=inode.value_hmac)::int AS conversion_count,
35103
35104
  (SELECT sum(c.value_minor) FROM analytics_conversions c JOIN analytics_sessions s
35104
- ON s.site_id=c.site_id AND s.session_hmac=c.session_id
35105
+ ON s.site_id=c.site_id AND s.session_hmac=c.session_hmac
35105
35106
  WHERE c.site_id=ca.site_id AND s.visitor_hmac=inode.value_hmac)::bigint AS revenue_minor,
35106
35107
  (SELECT CASE WHEN count(DISTINCT c.currency)=1 THEN min(c.currency) END
35107
35108
  FROM analytics_conversions c JOIN analytics_sessions s
35108
- ON s.site_id=c.site_id AND s.session_hmac=c.session_id
35109
+ ON s.site_id=c.site_id AND s.session_hmac=c.session_hmac
35109
35110
  WHERE c.site_id=ca.site_id AND s.visitor_hmac=inode.value_hmac) AS currency
35110
35111
  FROM analytics_identity_nodes inode
35111
35112
  WHERE inode.site_id=ca.site_id AND inode.namespace_id=ca.namespace_id
@@ -36368,8 +36369,8 @@ async function recordAnalyticsExternalEvent(input) {
36368
36369
  `INSERT INTO analytics_conversions(
36369
36370
  id, source_event_id, site_id, session_id, conversion_kind,
36370
36371
  value_minor, currency, occurred_at, person_id, rule_id, rule_version, order_id,
36371
- value_source, value_provenance
36372
- ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14::jsonb)
36372
+ value_source, value_provenance, session_hmac
36373
+ ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14::jsonb,$15)
36373
36374
  ON CONFLICT(site_id, source_event_id) DO NOTHING RETURNING id`,
36374
36375
  [
36375
36376
  conversionId,
@@ -36385,7 +36386,8 @@ async function recordAnalyticsExternalEvent(input) {
36385
36386
  rule.version,
36386
36387
  event2.orderId ?? null,
36387
36388
  valueSource,
36388
- JSON.stringify(resolvedValue.provenance)
36389
+ JSON.stringify(resolvedValue.provenance),
36390
+ event2.sessionId ? identityHmac("session_id", event2.sessionId) : null
36389
36391
  ]
36390
36392
  );
36391
36393
  if (!result2.rowCount) continue;
@@ -49411,8 +49413,8 @@ async function deleteAnalyticsPrivacySubject(input) {
49411
49413
  ["activationJobs", `DELETE FROM analytics_activation_jobs WHERE person_id=ANY($1::uuid[]) OR conversion_id IN (SELECT id FROM analytics_conversions WHERE site_id=$2 AND (person_id=ANY($1::uuid[]) OR session_id=ANY($3::text[])))`, [target.personIds, siteId, target.sessionHmacs]],
49412
49414
  ["externalEvents", `DELETE FROM analytics_external_events WHERE site_id=$1 AND (person_id=ANY($2::uuid[]) OR session_hmac=ANY($3::text[]) OR visitor_hmac=ANY($4::text[]))`, [siteId, target.personIds, target.sessionHmacs, target.visitorHmacs]],
49413
49415
  ["formSubmissions", `DELETE FROM analytics_form_submissions WHERE site_id=$1 AND (person_id=ANY($2::uuid[]) OR session_id=ANY($3::text[]) OR visitor_id=$4)`, [siteId, target.personIds, target.sessionHmacs, subject.ref]],
49414
- ["conversions", `DELETE FROM analytics_conversions WHERE site_id=$1 AND (person_id=ANY($2::uuid[]) OR session_id=ANY($3::text[]))`, [siteId, target.personIds, target.sessionHmacs]],
49415
- ["events", `DELETE FROM analytics_events WHERE site_id=$1 AND (person_id=ANY($2::uuid[]) OR session_id=ANY($3::text[]) OR visitor_id=ANY($4::text[]) OR visitor_id=$5)`, [siteId, target.personIds, target.sessionHmacs, target.visitorHmacs, subject.ref]],
49416
+ ["conversions", `DELETE FROM analytics_conversions WHERE site_id=$1 AND (person_id=ANY($2::uuid[]) OR session_hmac=ANY($3::text[]))`, [siteId, target.personIds, target.sessionHmacs]],
49417
+ ["events", `DELETE FROM analytics_events WHERE site_id=$1 AND (person_id=ANY($2::uuid[]) OR session_hmac=ANY($3::text[]) OR visitor_hmac=ANY($4::text[]) OR visitor_hmac=$5)`, [siteId, target.personIds, target.sessionHmacs, target.visitorHmacs, subject.ref]],
49416
49418
  ["touches", `DELETE FROM analytics_attribution_touches WHERE site_id=$1 AND (person_id=ANY($2::uuid[]) OR session_id=ANY($3::uuid[]) OR visitor_hmac=ANY($4::text[]))`, [siteId, target.personIds, target.sessionIds, target.visitorHmacs]],
49417
49419
  ["sessions", `DELETE FROM analytics_sessions WHERE site_id=$1 AND id=ANY($2::uuid[])`, [siteId, target.sessionIds]],
49418
49420
  ["linkers", `DELETE FROM analytics_linker_tokens WHERE site_id=$1 AND identity_node_id=ANY($2::uuid[])`, [siteId, target.identityNodeIds]],
@@ -49495,7 +49497,7 @@ async function applyAnalyticsPrivacyWithdrawal(input) {
49495
49497
  [siteId, target.personIds, now]
49496
49498
  ));
49497
49499
  affectedCounts.eventAdvertisingIds = count(await client2.query(
49498
- `UPDATE analytics_events SET click_ids='{}'::jsonb WHERE site_id=$1 AND (person_id=ANY($2::uuid[]) OR visitor_id=$3) AND click_ids <> '{}'::jsonb`,
49500
+ `UPDATE analytics_events SET click_ids='{}'::jsonb WHERE site_id=$1 AND (person_id=ANY($2::uuid[]) OR visitor_hmac=$3) AND click_ids <> '{}'::jsonb`,
49499
49501
  [siteId, target.personIds, subject.ref]
49500
49502
  ));
49501
49503
  affectedCounts.touchAdvertisingIds = count(await client2.query(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-scraper",
3
- "version": "0.73.4",
3
+ "version": "0.73.6",
4
4
  "description": "MCP server for MCP Scraper web intelligence tools",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",