mcp-scraper 0.83.5 → 0.84.0
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 +26 -1
- package/README.md +2 -2
- package/dist/{analytics-repository-GA6P5S5J.js → analytics-repository-4VZQ4TKW.js} +9 -1
- package/dist/bin/api-server.js +3 -3
- package/dist/bin/mcp-scraper-cli.js +3 -3
- package/dist/bin/mcp-scraper-core.js +6 -6
- package/dist/bin/mcp-scraper-install.js +2 -2
- package/dist/bin/mcp-stdio-server.js +6 -6
- package/dist/{chunk-ZHPGPVJJ.js → chunk-4KFD2WXG.js} +1 -1
- package/dist/{chunk-BGD7U3AE.js → chunk-4S6HPHPB.js} +13 -4
- package/dist/{chunk-ACDNW7TG.js → chunk-LHIWX7RM.js} +1 -1
- package/dist/{chunk-UXVT7FWW.js → chunk-NLWBM55O.js} +2 -2
- package/dist/{chunk-2B636U7P.js → chunk-OUTE3755.js} +1 -1
- package/dist/{chunk-CNAJWRJT.js → chunk-TLRJV4SL.js} +583 -29
- package/dist/{chunk-2BOBOKFQ.js → chunk-U77X4NIR.js} +3084 -1313
- package/dist/{chunk-4NZ6JFK5.js → chunk-UM7DCY6W.js} +2 -2
- package/dist/{chunk-VJHMPJR7.js → chunk-WDWWCNMW.js} +3 -3
- package/dist/{chunk-HGJJQY24.js → chunk-ZB55UMMF.js} +1 -1
- package/dist/{extract-bundle-HTWWJD6N.js → extract-bundle-SI35H4HR.js} +2 -2
- package/dist/{gmail-service-VXE7OYNA.js → gmail-service-MOZ6S56I.js} +2 -2
- package/dist/{server-2E4YF6TY.js → server-3F3JMHBF.js} +2677 -2247
- package/dist/{site-extract-repository-Y5WQFSQW.js → site-extract-repository-3WC3VB5Y.js} +2 -2
- package/dist/{worker-FM3ZRDY4.js → worker-VTFGHWZL.js} +1 -1
- package/package.json +1 -1
- package/public/.well-known/xray-install.json +12 -4
- package/public/agent-install.md +12 -2
|
@@ -3393,9 +3393,247 @@ async function migrateAnalytics() {
|
|
|
3393
3393
|
await client.query("CREATE INDEX IF NOT EXISTS analytics_site_setups_owner_updated ON analytics_site_setups(owner_user_id, updated_at DESC)");
|
|
3394
3394
|
await client.query("CREATE INDEX IF NOT EXISTS analytics_site_setups_site_updated ON analytics_site_setups(site_id, updated_at DESC)");
|
|
3395
3395
|
await client.query("CREATE INDEX IF NOT EXISTS analytics_site_setup_receipts_setup_revision ON analytics_site_setup_receipts(setup_id, revision, occurred_at)");
|
|
3396
|
+
await client.query(`ALTER TABLE analytics_conversions ADD COLUMN IF NOT EXISTS authority_key text`);
|
|
3397
|
+
await client.query(`ALTER TABLE analytics_conversions ADD COLUMN IF NOT EXISTS authority_id uuid`);
|
|
3398
|
+
await client.query(`ALTER TABLE analytics_conversions ADD COLUMN IF NOT EXISTS authority_version_id uuid`);
|
|
3399
|
+
await client.query(`ALTER TABLE analytics_conversions ADD COLUMN IF NOT EXISTS restated_at timestamptz`);
|
|
3400
|
+
await client.query(`CREATE UNIQUE INDEX IF NOT EXISTS analytics_conversions_site_authority_key
|
|
3401
|
+
ON analytics_conversions(site_id, authority_key) WHERE authority_key IS NOT NULL`);
|
|
3402
|
+
await client.query(`
|
|
3403
|
+
CREATE TABLE IF NOT EXISTS analytics_revenue_authorities (
|
|
3404
|
+
authority_id uuid PRIMARY KEY,
|
|
3405
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3406
|
+
provider text NOT NULL,
|
|
3407
|
+
source_account_ref text NOT NULL,
|
|
3408
|
+
connection_id uuid REFERENCES analytics_connections(id) ON DELETE SET NULL,
|
|
3409
|
+
outcome_family text NOT NULL,
|
|
3410
|
+
authority_role text NOT NULL CHECK (authority_role IN ('primary','observation')),
|
|
3411
|
+
state text NOT NULL CHECK (state IN ('configured_unverified','verified','live','degraded','disabled','blocked')),
|
|
3412
|
+
current_revision integer NOT NULL DEFAULT 1 CHECK (current_revision > 0),
|
|
3413
|
+
created_by_user_id bigint NOT NULL,
|
|
3414
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
3415
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
3416
|
+
disabled_at timestamptz,
|
|
3417
|
+
UNIQUE(site_id, provider, source_account_ref, outcome_family)
|
|
3418
|
+
)
|
|
3419
|
+
`);
|
|
3420
|
+
await client.query(`CREATE UNIQUE INDEX IF NOT EXISTS analytics_revenue_authorities_one_primary
|
|
3421
|
+
ON analytics_revenue_authorities(site_id, outcome_family)
|
|
3422
|
+
WHERE authority_role='primary' AND state <> 'disabled'`);
|
|
3423
|
+
await client.query(`
|
|
3424
|
+
CREATE TABLE IF NOT EXISTS analytics_provider_customer_bindings (
|
|
3425
|
+
binding_id uuid PRIMARY KEY,
|
|
3426
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3427
|
+
authority_id uuid NOT NULL REFERENCES analytics_revenue_authorities(authority_id) ON DELETE CASCADE,
|
|
3428
|
+
provider_customer_ref_hmac text NOT NULL CHECK (provider_customer_ref_hmac ~ '^[a-f0-9]{64}$'),
|
|
3429
|
+
person_id uuid NOT NULL REFERENCES analytics_people(id) ON DELETE CASCADE,
|
|
3430
|
+
verification_status text NOT NULL CHECK (verification_status IN ('verified','revoked')),
|
|
3431
|
+
evidence_ref text NOT NULL,
|
|
3432
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
3433
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
3434
|
+
revoked_at timestamptz,
|
|
3435
|
+
UNIQUE(authority_id, provider_customer_ref_hmac),
|
|
3436
|
+
UNIQUE(authority_id, person_id)
|
|
3437
|
+
)
|
|
3438
|
+
`);
|
|
3439
|
+
await client.query(`
|
|
3440
|
+
CREATE TABLE IF NOT EXISTS analytics_authoritative_outcomes (
|
|
3441
|
+
outcome_id uuid PRIMARY KEY,
|
|
3442
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3443
|
+
authority_id uuid NOT NULL REFERENCES analytics_revenue_authorities(authority_id) ON DELETE RESTRICT,
|
|
3444
|
+
authority_key text NOT NULL,
|
|
3445
|
+
provider_object_kind text NOT NULL,
|
|
3446
|
+
provider_object_ref_hmac text NOT NULL,
|
|
3447
|
+
provider_customer_ref_hmac text,
|
|
3448
|
+
outcome_kind text NOT NULL,
|
|
3449
|
+
current_version integer NOT NULL DEFAULT 0 CHECK (current_version >= 0),
|
|
3450
|
+
conversion_id uuid REFERENCES analytics_conversions(id) ON DELETE SET NULL,
|
|
3451
|
+
person_id uuid REFERENCES analytics_people(id) ON DELETE SET NULL,
|
|
3452
|
+
first_observed_at timestamptz NOT NULL,
|
|
3453
|
+
last_observed_at timestamptz NOT NULL,
|
|
3454
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
3455
|
+
UNIQUE(site_id, authority_key)
|
|
3456
|
+
)
|
|
3457
|
+
`);
|
|
3458
|
+
await client.query(`
|
|
3459
|
+
CREATE TABLE IF NOT EXISTS analytics_authoritative_outcome_versions (
|
|
3460
|
+
version_id uuid NOT NULL UNIQUE,
|
|
3461
|
+
outcome_id uuid NOT NULL REFERENCES analytics_authoritative_outcomes(outcome_id) ON DELETE CASCADE,
|
|
3462
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3463
|
+
version integer NOT NULL CHECK (version > 0),
|
|
3464
|
+
transport_event_id text NOT NULL,
|
|
3465
|
+
status text NOT NULL,
|
|
3466
|
+
value_minor bigint NOT NULL,
|
|
3467
|
+
currency text NOT NULL CHECK (currency ~ '^[A-Z]{3}$'),
|
|
3468
|
+
occurred_at timestamptz NOT NULL,
|
|
3469
|
+
observed_at timestamptz NOT NULL,
|
|
3470
|
+
provenance jsonb NOT NULL DEFAULT '{}'::jsonb,
|
|
3471
|
+
receipt_ref text NOT NULL,
|
|
3472
|
+
request_fingerprint text NOT NULL CHECK (request_fingerprint ~ '^[a-f0-9]{64}$'),
|
|
3473
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
3474
|
+
PRIMARY KEY(outcome_id, version),
|
|
3475
|
+
UNIQUE(site_id, transport_event_id)
|
|
3476
|
+
)
|
|
3477
|
+
`);
|
|
3478
|
+
await client.query(`
|
|
3479
|
+
CREATE TABLE IF NOT EXISTS analytics_revenue_setup_revisions (
|
|
3480
|
+
setup_id uuid NOT NULL,
|
|
3481
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3482
|
+
revision integer NOT NULL CHECK (revision > 0),
|
|
3483
|
+
authority_id uuid REFERENCES analytics_revenue_authorities(authority_id) ON DELETE SET NULL,
|
|
3484
|
+
state text NOT NULL,
|
|
3485
|
+
plan jsonb NOT NULL,
|
|
3486
|
+
request_fingerprint text NOT NULL CHECK (request_fingerprint ~ '^[a-f0-9]{64}$'),
|
|
3487
|
+
created_by_user_id bigint NOT NULL,
|
|
3488
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
3489
|
+
PRIMARY KEY(setup_id, revision)
|
|
3490
|
+
)
|
|
3491
|
+
`);
|
|
3492
|
+
await client.query(`
|
|
3493
|
+
CREATE TABLE IF NOT EXISTS analytics_revenue_setup_receipts (
|
|
3494
|
+
receipt_id uuid PRIMARY KEY,
|
|
3495
|
+
setup_id uuid NOT NULL,
|
|
3496
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3497
|
+
revision integer NOT NULL,
|
|
3498
|
+
operation text NOT NULL,
|
|
3499
|
+
status text NOT NULL,
|
|
3500
|
+
idempotency_key text NOT NULL,
|
|
3501
|
+
request_fingerprint text NOT NULL CHECK (request_fingerprint ~ '^[a-f0-9]{64}$'),
|
|
3502
|
+
receipt jsonb NOT NULL,
|
|
3503
|
+
occurred_at timestamptz NOT NULL DEFAULT now(),
|
|
3504
|
+
FOREIGN KEY(setup_id, revision) REFERENCES analytics_revenue_setup_revisions(setup_id, revision) ON DELETE CASCADE,
|
|
3505
|
+
UNIQUE(site_id, idempotency_key)
|
|
3506
|
+
)
|
|
3507
|
+
`);
|
|
3508
|
+
await client.query(`
|
|
3509
|
+
CREATE TABLE IF NOT EXISTS analytics_post_purchase_surveys (
|
|
3510
|
+
survey_id uuid PRIMARY KEY,
|
|
3511
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3512
|
+
current_revision integer NOT NULL DEFAULT 1 CHECK (current_revision > 0),
|
|
3513
|
+
state text NOT NULL CHECK (state IN ('draft','published','paused','archived')),
|
|
3514
|
+
name text NOT NULL,
|
|
3515
|
+
question text NOT NULL,
|
|
3516
|
+
selection_mode text NOT NULL CHECK (selection_mode IN ('single','multiple')),
|
|
3517
|
+
eligible_outcome_families text[] NOT NULL,
|
|
3518
|
+
exchange_ttl_seconds integer NOT NULL CHECK (exchange_ttl_seconds BETWEEN 60 AND 86400),
|
|
3519
|
+
session_ttl_seconds integer NOT NULL CHECK (session_ttl_seconds BETWEEN 60 AND 86400),
|
|
3520
|
+
approved_copy_id text,
|
|
3521
|
+
create_idempotency_key text,
|
|
3522
|
+
create_request_fingerprint text,
|
|
3523
|
+
state_transition_receipts jsonb NOT NULL DEFAULT '{}'::jsonb CHECK (jsonb_typeof(state_transition_receipts)='object'),
|
|
3524
|
+
created_by_user_id bigint NOT NULL,
|
|
3525
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
3526
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
3527
|
+
archived_at timestamptz,
|
|
3528
|
+
UNIQUE(site_id, create_idempotency_key)
|
|
3529
|
+
)
|
|
3530
|
+
`);
|
|
3531
|
+
await client.query(`ALTER TABLE analytics_post_purchase_surveys
|
|
3532
|
+
ADD COLUMN IF NOT EXISTS state_transition_receipts jsonb NOT NULL DEFAULT '{}'::jsonb`);
|
|
3533
|
+
await client.query(`ALTER TABLE analytics_post_purchase_surveys
|
|
3534
|
+
DROP CONSTRAINT IF EXISTS analytics_post_purchase_surveys_state_transition_receipts_check`);
|
|
3535
|
+
await client.query(`ALTER TABLE analytics_post_purchase_surveys
|
|
3536
|
+
ADD CONSTRAINT analytics_post_purchase_surveys_state_transition_receipts_check
|
|
3537
|
+
CHECK (jsonb_typeof(state_transition_receipts)='object')`);
|
|
3538
|
+
await client.query(`
|
|
3539
|
+
CREATE TABLE IF NOT EXISTS analytics_post_purchase_survey_options (
|
|
3540
|
+
survey_id uuid NOT NULL REFERENCES analytics_post_purchase_surveys(survey_id) ON DELETE CASCADE,
|
|
3541
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3542
|
+
revision integer NOT NULL CHECK (revision > 0),
|
|
3543
|
+
option_id text NOT NULL,
|
|
3544
|
+
label text NOT NULL,
|
|
3545
|
+
position integer NOT NULL CHECK (position >= 0),
|
|
3546
|
+
active boolean NOT NULL DEFAULT true,
|
|
3547
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
3548
|
+
PRIMARY KEY(survey_id, revision, option_id),
|
|
3549
|
+
UNIQUE(survey_id, revision, position)
|
|
3550
|
+
)
|
|
3551
|
+
`);
|
|
3552
|
+
await client.query(`
|
|
3553
|
+
CREATE TABLE IF NOT EXISTS analytics_post_purchase_survey_invites (
|
|
3554
|
+
invite_id uuid PRIMARY KEY,
|
|
3555
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3556
|
+
survey_id uuid NOT NULL REFERENCES analytics_post_purchase_surveys(survey_id) ON DELETE CASCADE,
|
|
3557
|
+
survey_revision integer NOT NULL CHECK (survey_revision > 0),
|
|
3558
|
+
conversion_id uuid NOT NULL REFERENCES analytics_conversions(id) ON DELETE CASCADE,
|
|
3559
|
+
invitation_token_digest text NOT NULL CHECK (invitation_token_digest ~ '^[a-f0-9]{64}$'),
|
|
3560
|
+
purpose text NOT NULL DEFAULT 'customer_reported_measurement' CHECK (purpose='customer_reported_measurement'),
|
|
3561
|
+
approved_copy_id text NOT NULL,
|
|
3562
|
+
exchange_expires_at timestamptz NOT NULL,
|
|
3563
|
+
exchanged_at timestamptz,
|
|
3564
|
+
session_token_digest text CHECK (session_token_digest IS NULL OR session_token_digest ~ '^[a-f0-9]{64}$'),
|
|
3565
|
+
session_expires_at timestamptz,
|
|
3566
|
+
response_id uuid,
|
|
3567
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
3568
|
+
UNIQUE(site_id, invitation_token_digest),
|
|
3569
|
+
UNIQUE(site_id, session_token_digest),
|
|
3570
|
+
UNIQUE(survey_id, conversion_id)
|
|
3571
|
+
)
|
|
3572
|
+
`);
|
|
3573
|
+
await client.query(`
|
|
3574
|
+
CREATE TABLE IF NOT EXISTS analytics_post_purchase_survey_responses (
|
|
3575
|
+
response_id uuid PRIMARY KEY,
|
|
3576
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3577
|
+
survey_id uuid NOT NULL REFERENCES analytics_post_purchase_surveys(survey_id) ON DELETE CASCADE,
|
|
3578
|
+
survey_revision integer NOT NULL CHECK (survey_revision > 0),
|
|
3579
|
+
conversion_id uuid NOT NULL REFERENCES analytics_conversions(id) ON DELETE CASCADE,
|
|
3580
|
+
invite_id uuid NOT NULL REFERENCES analytics_post_purchase_survey_invites(invite_id) ON DELETE RESTRICT,
|
|
3581
|
+
body_fingerprint text NOT NULL CHECK (body_fingerprint ~ '^[a-f0-9]{64}$'),
|
|
3582
|
+
submitted_at timestamptz NOT NULL DEFAULT now(),
|
|
3583
|
+
UNIQUE(survey_id, conversion_id),
|
|
3584
|
+
UNIQUE(invite_id)
|
|
3585
|
+
)
|
|
3586
|
+
`);
|
|
3587
|
+
await client.query(`
|
|
3588
|
+
CREATE TABLE IF NOT EXISTS analytics_reported_influences (
|
|
3589
|
+
evidence_id uuid PRIMARY KEY,
|
|
3590
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3591
|
+
response_id uuid NOT NULL REFERENCES analytics_post_purchase_survey_responses(response_id) ON DELETE CASCADE,
|
|
3592
|
+
conversion_id uuid NOT NULL REFERENCES analytics_conversions(id) ON DELETE CASCADE,
|
|
3593
|
+
survey_id uuid NOT NULL REFERENCES analytics_post_purchase_surveys(survey_id) ON DELETE CASCADE,
|
|
3594
|
+
survey_revision integer NOT NULL CHECK (survey_revision > 0),
|
|
3595
|
+
option_id text NOT NULL,
|
|
3596
|
+
option_label text NOT NULL,
|
|
3597
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
3598
|
+
UNIQUE(response_id, option_id)
|
|
3599
|
+
)
|
|
3600
|
+
`);
|
|
3601
|
+
await client.query(`
|
|
3602
|
+
CREATE TABLE IF NOT EXISTS analytics_view_evidence_receipts (
|
|
3603
|
+
receipt_id uuid PRIMARY KEY,
|
|
3604
|
+
site_id uuid NOT NULL REFERENCES analytics_sites(id) ON DELETE CASCADE,
|
|
3605
|
+
provider text NOT NULL,
|
|
3606
|
+
source_account_ref text NOT NULL,
|
|
3607
|
+
provider_event_id text NOT NULL,
|
|
3608
|
+
evidence_granularity text NOT NULL CHECK (evidence_granularity='event_level'),
|
|
3609
|
+
verification_status text NOT NULL CHECK (verification_status='verified'),
|
|
3610
|
+
subject_kind text NOT NULL CHECK (subject_kind IN ('person','session','visitor')),
|
|
3611
|
+
subject_ref_hmac text NOT NULL,
|
|
3612
|
+
person_id uuid REFERENCES analytics_people(id) ON DELETE SET NULL,
|
|
3613
|
+
session_id uuid REFERENCES analytics_sessions(id) ON DELETE SET NULL,
|
|
3614
|
+
provider_receipt_ref text NOT NULL,
|
|
3615
|
+
occurred_at timestamptz NOT NULL,
|
|
3616
|
+
retention_expires_at timestamptz NOT NULL,
|
|
3617
|
+
touch_id uuid REFERENCES analytics_attribution_touches(id) ON DELETE SET NULL,
|
|
3618
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
3619
|
+
UNIQUE(site_id, provider, source_account_ref, provider_event_id)
|
|
3620
|
+
)
|
|
3621
|
+
`);
|
|
3622
|
+
await client.query(`ALTER TABLE analytics_conversions DROP CONSTRAINT IF EXISTS analytics_conversions_authority_id_fkey`);
|
|
3623
|
+
await client.query(`ALTER TABLE analytics_conversions ADD CONSTRAINT analytics_conversions_authority_id_fkey
|
|
3624
|
+
FOREIGN KEY(authority_id) REFERENCES analytics_revenue_authorities(authority_id) ON DELETE SET NULL`);
|
|
3625
|
+
await client.query(`ALTER TABLE analytics_conversions DROP CONSTRAINT IF EXISTS analytics_conversions_authority_version_id_fkey`);
|
|
3626
|
+
await client.query(`ALTER TABLE analytics_conversions ADD CONSTRAINT analytics_conversions_authority_version_id_fkey
|
|
3627
|
+
FOREIGN KEY(authority_version_id) REFERENCES analytics_authoritative_outcome_versions(version_id) ON DELETE SET NULL`);
|
|
3628
|
+
await client.query(`CREATE INDEX IF NOT EXISTS analytics_authoritative_outcomes_person
|
|
3629
|
+
ON analytics_authoritative_outcomes(site_id, person_id, last_observed_at DESC)`);
|
|
3630
|
+
await client.query(`CREATE INDEX IF NOT EXISTS analytics_reported_influences_conversion
|
|
3631
|
+
ON analytics_reported_influences(site_id, conversion_id, created_at)`);
|
|
3632
|
+
await client.query(`CREATE INDEX IF NOT EXISTS analytics_view_evidence_subject
|
|
3633
|
+
ON analytics_view_evidence_receipts(site_id, subject_ref_hmac, occurred_at DESC)`);
|
|
3396
3634
|
await client.query(`
|
|
3397
3635
|
INSERT INTO analytics_schema_migrations(version)
|
|
3398
|
-
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'), ('2026-08-28.2'), ('2026-08-28.3'), ('2026-08-28.4'), ('2026-08-31.1'), ('2026-09-01.1')
|
|
3636
|
+
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'), ('2026-08-28.2'), ('2026-08-28.3'), ('2026-08-28.4'), ('2026-08-31.1'), ('2026-09-01.1'), ('2026-09-01.2')
|
|
3399
3637
|
ON CONFLICT (version) DO NOTHING
|
|
3400
3638
|
`);
|
|
3401
3639
|
} catch (error) {
|
|
@@ -4594,6 +4832,271 @@ function paginateRows(rows, input, fingerprint) {
|
|
|
4594
4832
|
}
|
|
4595
4833
|
};
|
|
4596
4834
|
}
|
|
4835
|
+
async function insertAnalyticsRevenueSetupRevision(input) {
|
|
4836
|
+
const current = await input.db.query(
|
|
4837
|
+
`SELECT revision FROM analytics_revenue_setup_revisions
|
|
4838
|
+
WHERE setup_id=$1 ORDER BY revision DESC LIMIT 1 FOR UPDATE`,
|
|
4839
|
+
[input.setupId]
|
|
4840
|
+
);
|
|
4841
|
+
const currentRevision = current.rows[0]?.revision ?? 0;
|
|
4842
|
+
if (currentRevision !== input.expectedRevision) {
|
|
4843
|
+
throw new AnalyticsRepositoryError(
|
|
4844
|
+
"analytics_revenue_setup_stale_revision",
|
|
4845
|
+
`Revenue setup revision ${input.expectedRevision} is stale; current revision is ${currentRevision}.`,
|
|
4846
|
+
409
|
|
4847
|
+
);
|
|
4848
|
+
}
|
|
4849
|
+
const nextRevision = currentRevision + 1;
|
|
4850
|
+
await input.db.query(
|
|
4851
|
+
`INSERT INTO analytics_revenue_setup_revisions(
|
|
4852
|
+
setup_id,site_id,revision,authority_id,state,plan,request_fingerprint,created_by_user_id
|
|
4853
|
+
) VALUES($1,$2,$3,$4,$5,$6::jsonb,$7,$8)`,
|
|
4854
|
+
[
|
|
4855
|
+
input.setupId,
|
|
4856
|
+
input.siteId,
|
|
4857
|
+
nextRevision,
|
|
4858
|
+
input.authorityId ?? null,
|
|
4859
|
+
input.state,
|
|
4860
|
+
JSON.stringify(input.plan),
|
|
4861
|
+
input.requestFingerprint,
|
|
4862
|
+
input.createdByUserId
|
|
4863
|
+
]
|
|
4864
|
+
);
|
|
4865
|
+
return nextRevision;
|
|
4866
|
+
}
|
|
4867
|
+
async function appendAnalyticsAuthoritativeOutcomeVersion(input) {
|
|
4868
|
+
const replay = await input.db.query(
|
|
4869
|
+
`SELECT version_id,version,request_fingerprint FROM analytics_authoritative_outcome_versions
|
|
4870
|
+
WHERE site_id=$1 AND transport_event_id=$2`,
|
|
4871
|
+
[input.siteId, input.transportEventId]
|
|
4872
|
+
);
|
|
4873
|
+
if (replay.rows[0]) {
|
|
4874
|
+
if (replay.rows[0].request_fingerprint !== input.requestFingerprint) {
|
|
4875
|
+
throw new AnalyticsRepositoryError(
|
|
4876
|
+
"analytics_authoritative_outcome_replay_conflict",
|
|
4877
|
+
"The provider event was replayed with a different normalized body.",
|
|
4878
|
+
409
|
|
4879
|
+
);
|
|
4880
|
+
}
|
|
4881
|
+
return { versionId: replay.rows[0].version_id, version: replay.rows[0].version, replay: true };
|
|
4882
|
+
}
|
|
4883
|
+
const locked = await input.db.query(
|
|
4884
|
+
`SELECT current_version FROM analytics_authoritative_outcomes
|
|
4885
|
+
WHERE outcome_id=$1 AND site_id=$2 FOR UPDATE`,
|
|
4886
|
+
[input.outcomeId, input.siteId]
|
|
4887
|
+
);
|
|
4888
|
+
if (!locked.rows[0]) throw new AnalyticsRepositoryError("analytics_authoritative_outcome_not_found", "Authoritative outcome not found.", 404);
|
|
4889
|
+
const version = locked.rows[0].current_version + 1;
|
|
4890
|
+
const versionId = randomUUID2();
|
|
4891
|
+
await input.db.query(
|
|
4892
|
+
`INSERT INTO analytics_authoritative_outcome_versions(
|
|
4893
|
+
version_id,outcome_id,site_id,version,transport_event_id,status,value_minor,currency,
|
|
4894
|
+
occurred_at,observed_at,provenance,receipt_ref,request_fingerprint
|
|
4895
|
+
) VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11::jsonb,$12,$13)`,
|
|
4896
|
+
[
|
|
4897
|
+
versionId,
|
|
4898
|
+
input.outcomeId,
|
|
4899
|
+
input.siteId,
|
|
4900
|
+
version,
|
|
4901
|
+
input.transportEventId,
|
|
4902
|
+
input.status,
|
|
4903
|
+
input.valueMinor.toString(),
|
|
4904
|
+
input.currency.toUpperCase(),
|
|
4905
|
+
input.occurredAt,
|
|
4906
|
+
input.observedAt,
|
|
4907
|
+
JSON.stringify(input.provenance),
|
|
4908
|
+
input.receiptRef,
|
|
4909
|
+
input.requestFingerprint
|
|
4910
|
+
]
|
|
4911
|
+
);
|
|
4912
|
+
await input.db.query(
|
|
4913
|
+
`UPDATE analytics_authoritative_outcomes
|
|
4914
|
+
SET current_version=$2,last_observed_at=$3 WHERE outcome_id=$1`,
|
|
4915
|
+
[input.outcomeId, version, input.observedAt]
|
|
4916
|
+
);
|
|
4917
|
+
return { versionId, version, replay: false };
|
|
4918
|
+
}
|
|
4919
|
+
async function projectAnalyticsAuthoritativeConversion(input) {
|
|
4920
|
+
const verified = await input.db.query(
|
|
4921
|
+
`SELECT outcome.conversion_id,authority.authority_role,
|
|
4922
|
+
authority.state AS authority_state
|
|
4923
|
+
FROM analytics_authoritative_outcomes outcome
|
|
4924
|
+
JOIN analytics_revenue_authorities authority
|
|
4925
|
+
ON authority.authority_id=outcome.authority_id
|
|
4926
|
+
AND authority.site_id=outcome.site_id
|
|
4927
|
+
JOIN analytics_authoritative_outcome_versions version
|
|
4928
|
+
ON version.outcome_id=outcome.outcome_id
|
|
4929
|
+
AND version.site_id=outcome.site_id
|
|
4930
|
+
JOIN analytics_provider_customer_bindings binding
|
|
4931
|
+
ON binding.authority_id=authority.authority_id
|
|
4932
|
+
AND binding.site_id=authority.site_id
|
|
4933
|
+
AND binding.person_id=outcome.person_id
|
|
4934
|
+
AND binding.verification_status='verified'
|
|
4935
|
+
WHERE outcome.site_id=$1 AND outcome.outcome_id=$2
|
|
4936
|
+
AND outcome.authority_id=$3 AND outcome.authority_key=$4
|
|
4937
|
+
AND version.version_id=$5 AND outcome.person_id=$6
|
|
4938
|
+
FOR UPDATE OF outcome`,
|
|
4939
|
+
[
|
|
4940
|
+
input.siteId,
|
|
4941
|
+
input.outcomeId,
|
|
4942
|
+
input.authorityId,
|
|
4943
|
+
input.authorityKey,
|
|
4944
|
+
input.authorityVersionId,
|
|
4945
|
+
input.personId
|
|
4946
|
+
]
|
|
4947
|
+
);
|
|
4948
|
+
const evidence = verified.rows[0];
|
|
4949
|
+
if (!evidence) {
|
|
4950
|
+
throw new AnalyticsRepositoryError(
|
|
4951
|
+
"analytics_revenue_projection_evidence_invalid",
|
|
4952
|
+
"The authoritative outcome, version, and customer binding could not be verified.",
|
|
4953
|
+
409
|
|
4954
|
+
);
|
|
4955
|
+
}
|
|
4956
|
+
if (evidence.authority_role !== "primary" || !["verified", "live", "degraded"].includes(evidence.authority_state)) {
|
|
4957
|
+
throw new AnalyticsRepositoryError(
|
|
4958
|
+
"analytics_revenue_projection_authority_ineligible",
|
|
4959
|
+
"Only an active primary revenue authority may project conversions.",
|
|
4960
|
+
409
|
|
4961
|
+
);
|
|
4962
|
+
}
|
|
4963
|
+
const existing = await input.db.query(
|
|
4964
|
+
`SELECT conversion.id
|
|
4965
|
+
FROM analytics_conversions conversion
|
|
4966
|
+
JOIN analytics_authoritative_outcomes outcome
|
|
4967
|
+
ON outcome.conversion_id=conversion.id
|
|
4968
|
+
AND outcome.site_id=conversion.site_id
|
|
4969
|
+
WHERE conversion.site_id=$1 AND conversion.authority_key=$2
|
|
4970
|
+
AND outcome.outcome_id=$3 AND outcome.authority_id=$4
|
|
4971
|
+
FOR UPDATE OF conversion`,
|
|
4972
|
+
[input.siteId, input.authorityKey, input.outcomeId, input.authorityId]
|
|
4973
|
+
);
|
|
4974
|
+
let conversionId = existing.rows[0]?.id;
|
|
4975
|
+
let created = false;
|
|
4976
|
+
let restated = false;
|
|
4977
|
+
if (conversionId) {
|
|
4978
|
+
await input.db.query(
|
|
4979
|
+
`UPDATE analytics_conversions
|
|
4980
|
+
SET value_minor=$2,currency=$3,occurred_at=$4,person_id=$5,
|
|
4981
|
+
authority_version_id=$6,value_source='restatement',
|
|
4982
|
+
value_provenance=$7::jsonb,restated_at=now()
|
|
4983
|
+
WHERE id=$1 AND site_id=$8 AND authority_id=$9 AND authority_key=$10`,
|
|
4984
|
+
[
|
|
4985
|
+
conversionId,
|
|
4986
|
+
input.valueMinor.toString(),
|
|
4987
|
+
input.currency.toUpperCase(),
|
|
4988
|
+
input.occurredAt,
|
|
4989
|
+
input.personId,
|
|
4990
|
+
input.authorityVersionId,
|
|
4991
|
+
JSON.stringify(input.valueProvenance),
|
|
4992
|
+
input.siteId,
|
|
4993
|
+
input.authorityId,
|
|
4994
|
+
input.authorityKey
|
|
4995
|
+
]
|
|
4996
|
+
);
|
|
4997
|
+
restated = true;
|
|
4998
|
+
} else {
|
|
4999
|
+
const id = randomUUID2();
|
|
5000
|
+
const inserted = await input.db.query(
|
|
5001
|
+
`INSERT INTO analytics_conversions(
|
|
5002
|
+
id,source_event_id,site_id,conversion_kind,value_minor,currency,
|
|
5003
|
+
occurred_at,person_id,authority_id,authority_key,authority_version_id,
|
|
5004
|
+
value_source,value_provenance
|
|
5005
|
+
) VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,'verified_revenue',$12::jsonb)
|
|
5006
|
+
ON CONFLICT(site_id,authority_key) WHERE authority_key IS NOT NULL
|
|
5007
|
+
DO NOTHING RETURNING id`,
|
|
5008
|
+
[
|
|
5009
|
+
id,
|
|
5010
|
+
input.sourceEventId,
|
|
5011
|
+
input.siteId,
|
|
5012
|
+
input.conversionKind,
|
|
5013
|
+
input.valueMinor.toString(),
|
|
5014
|
+
input.currency.toUpperCase(),
|
|
5015
|
+
input.occurredAt,
|
|
5016
|
+
input.personId,
|
|
5017
|
+
input.authorityId,
|
|
5018
|
+
input.authorityKey,
|
|
5019
|
+
input.authorityVersionId,
|
|
5020
|
+
JSON.stringify(input.valueProvenance)
|
|
5021
|
+
]
|
|
5022
|
+
);
|
|
5023
|
+
conversionId = inserted.rows[0]?.id;
|
|
5024
|
+
created = Boolean(conversionId);
|
|
5025
|
+
if (!conversionId) {
|
|
5026
|
+
const winner = await input.db.query(
|
|
5027
|
+
`SELECT conversion.id
|
|
5028
|
+
FROM analytics_conversions conversion
|
|
5029
|
+
JOIN analytics_authoritative_outcomes outcome
|
|
5030
|
+
ON outcome.conversion_id=conversion.id
|
|
5031
|
+
WHERE conversion.site_id=$1 AND conversion.authority_key=$2
|
|
5032
|
+
AND outcome.outcome_id=$3 AND outcome.authority_id=$4
|
|
5033
|
+
FOR UPDATE OF conversion`,
|
|
5034
|
+
[input.siteId, input.authorityKey, input.outcomeId, input.authorityId]
|
|
5035
|
+
);
|
|
5036
|
+
if (!winner.rows[0]) {
|
|
5037
|
+
throw new AnalyticsRepositoryError(
|
|
5038
|
+
"analytics_conversion_authority_conflict",
|
|
5039
|
+
"The authority key is already projected from a different authoritative outcome.",
|
|
5040
|
+
409
|
|
5041
|
+
);
|
|
5042
|
+
}
|
|
5043
|
+
conversionId = winner.rows[0].id;
|
|
5044
|
+
}
|
|
5045
|
+
await input.db.query(
|
|
5046
|
+
`UPDATE analytics_authoritative_outcomes SET conversion_id=$2
|
|
5047
|
+
WHERE outcome_id=$1 AND site_id=$3
|
|
5048
|
+
AND (conversion_id IS NULL OR conversion_id=$2)`,
|
|
5049
|
+
[input.outcomeId, conversionId, input.siteId]
|
|
5050
|
+
);
|
|
5051
|
+
}
|
|
5052
|
+
let queuedDestinations = 0;
|
|
5053
|
+
if (created && input.activationPayloadCiphertext) {
|
|
5054
|
+
const destinations = await input.db.query(
|
|
5055
|
+
`SELECT id,event_mapping FROM analytics_activation_destinations
|
|
5056
|
+
WHERE site_id=$1 AND status='active'
|
|
5057
|
+
AND automatic_delivery_enabled=true AND readiness IN ('verified','live')`,
|
|
5058
|
+
[input.siteId]
|
|
5059
|
+
);
|
|
5060
|
+
for (const destination of destinations.rows.filter((row) => activationMappingAllows(row.event_mapping, input.conversionKind))) {
|
|
5061
|
+
const queued = await input.db.query(
|
|
5062
|
+
`INSERT INTO analytics_activation_jobs(
|
|
5063
|
+
id,destination_id,conversion_id,person_id,payload_ciphertext
|
|
5064
|
+
) VALUES($1,$2,$3,$4,$5)
|
|
5065
|
+
ON CONFLICT(destination_id,conversion_id) DO NOTHING`,
|
|
5066
|
+
[
|
|
5067
|
+
randomUUID2(),
|
|
5068
|
+
destination.id,
|
|
5069
|
+
conversionId,
|
|
5070
|
+
input.personId,
|
|
5071
|
+
input.activationPayloadCiphertext
|
|
5072
|
+
]
|
|
5073
|
+
);
|
|
5074
|
+
queuedDestinations += queued.rowCount ?? 0;
|
|
5075
|
+
}
|
|
5076
|
+
}
|
|
5077
|
+
return { id: conversionId, created, restated, queuedDestinations };
|
|
5078
|
+
}
|
|
5079
|
+
async function consumeAnalyticsSurveyInvite(input) {
|
|
5080
|
+
const invite = await input.db.query(
|
|
5081
|
+
`SELECT invite_id,survey_id,survey_revision,conversion_id,exchange_expires_at,exchanged_at
|
|
5082
|
+
FROM analytics_post_purchase_survey_invites
|
|
5083
|
+
WHERE site_id=$1 AND invitation_token_digest=$2 FOR UPDATE`,
|
|
5084
|
+
[input.siteId, input.invitationTokenDigest]
|
|
5085
|
+
);
|
|
5086
|
+
const row = invite.rows[0];
|
|
5087
|
+
if (!row) throw new AnalyticsRepositoryError("analytics_survey_invite_not_found", "Survey invitation not found.", 404);
|
|
5088
|
+
if (row.exchanged_at) throw new AnalyticsRepositoryError("analytics_survey_invite_consumed", "Survey invitation has already been exchanged.", 409);
|
|
5089
|
+
if (Date.parse(new Date(row.exchange_expires_at).toISOString()) <= Date.parse(input.now)) {
|
|
5090
|
+
throw new AnalyticsRepositoryError("analytics_survey_exchange_expired", "Survey exchange code has expired.", 410);
|
|
5091
|
+
}
|
|
5092
|
+
await input.db.query(
|
|
5093
|
+
`UPDATE analytics_post_purchase_survey_invites
|
|
5094
|
+
SET exchanged_at=$2,session_token_digest=$3,session_expires_at=$4
|
|
5095
|
+
WHERE invite_id=$1`,
|
|
5096
|
+
[row.invite_id, input.now, input.sessionTokenDigest, input.sessionExpiresAt]
|
|
5097
|
+
);
|
|
5098
|
+
return { inviteId: row.invite_id, surveyId: row.survey_id, surveyRevision: row.survey_revision, conversionId: row.conversion_id };
|
|
5099
|
+
}
|
|
4597
5100
|
async function createAnalyticsConversion(input) {
|
|
4598
5101
|
const db = getAnalyticsPool();
|
|
4599
5102
|
const client = await db.connect();
|
|
@@ -4618,33 +5121,77 @@ async function createAnalyticsConversion(input) {
|
|
|
4618
5121
|
ORDER BY e.confidence DESC LIMIT 1`,
|
|
4619
5122
|
[input.siteId, identityHmac("session_id", input.sessionId)]
|
|
4620
5123
|
) : { rows: [] };
|
|
4621
|
-
const
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
5124
|
+
const authorityExisting = input.authority ? await client.query(
|
|
5125
|
+
`SELECT id FROM analytics_conversions
|
|
5126
|
+
WHERE site_id=$1 AND authority_key=$2 FOR UPDATE`,
|
|
5127
|
+
[input.siteId, input.authority.authorityKey]
|
|
5128
|
+
) : { rows: [], rowCount: 0 };
|
|
5129
|
+
let created = false;
|
|
5130
|
+
let restated = false;
|
|
5131
|
+
let conversionId;
|
|
5132
|
+
if (authorityExisting.rows[0]) {
|
|
5133
|
+
conversionId = authorityExisting.rows[0].id;
|
|
5134
|
+
await client.query(
|
|
5135
|
+
`UPDATE analytics_conversions
|
|
5136
|
+
SET value_minor=$2, currency=$3, occurred_at=$4,
|
|
5137
|
+
value_source='restatement', value_provenance=$5::jsonb,
|
|
5138
|
+
authority_id=$6, authority_version_id=$7, restated_at=now()
|
|
5139
|
+
WHERE id=$1`,
|
|
5140
|
+
[
|
|
5141
|
+
conversionId,
|
|
5142
|
+
input.valueMinor ?? 0,
|
|
5143
|
+
(input.currency || "USD").toUpperCase(),
|
|
5144
|
+
input.occurredAt,
|
|
5145
|
+
JSON.stringify(input.authority?.valueProvenance ?? {}),
|
|
5146
|
+
input.authority?.authorityId,
|
|
5147
|
+
input.authority?.authorityVersionId ?? null
|
|
5148
|
+
]
|
|
5149
|
+
);
|
|
5150
|
+
restated = true;
|
|
5151
|
+
} else {
|
|
5152
|
+
const proposedId = randomUUID2();
|
|
5153
|
+
const inserted = await client.query(
|
|
5154
|
+
`INSERT INTO analytics_conversions(
|
|
5155
|
+
id, source_event_id, site_id, pixel_id, session_id, conversion_kind,
|
|
5156
|
+
value_minor, currency, occurred_at, person_id, order_id, session_hmac,
|
|
5157
|
+
authority_id, authority_key, authority_version_id, value_source, value_provenance
|
|
5158
|
+
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17::jsonb)
|
|
5159
|
+
ON CONFLICT(site_id, source_event_id) DO NOTHING RETURNING id`,
|
|
5160
|
+
[
|
|
5161
|
+
proposedId,
|
|
5162
|
+
input.sourceEventId,
|
|
5163
|
+
input.siteId,
|
|
5164
|
+
input.pixelId ?? null,
|
|
5165
|
+
input.sessionId ?? null,
|
|
5166
|
+
input.conversionKind,
|
|
5167
|
+
input.valueMinor ?? 0,
|
|
5168
|
+
(input.currency || "USD").toUpperCase(),
|
|
5169
|
+
input.occurredAt,
|
|
5170
|
+
resolvedPerson.rows[0]?.person_id ?? null,
|
|
5171
|
+
input.orderId ?? null,
|
|
5172
|
+
input.sessionId ? identityHmac("session_id", input.sessionId) : null,
|
|
5173
|
+
input.authority?.authorityId ?? null,
|
|
5174
|
+
input.authority?.authorityKey ?? null,
|
|
5175
|
+
input.authority?.authorityVersionId ?? null,
|
|
5176
|
+
input.authority ? "verified_revenue" : "default_zero",
|
|
5177
|
+
JSON.stringify(input.authority?.valueProvenance ?? {})
|
|
5178
|
+
]
|
|
5179
|
+
);
|
|
5180
|
+
created = Boolean(inserted.rowCount);
|
|
5181
|
+
if (created) {
|
|
5182
|
+
conversionId = inserted.rows[0].id;
|
|
5183
|
+
} else {
|
|
5184
|
+
const existing = await client.query(
|
|
5185
|
+
`SELECT id,authority_key FROM analytics_conversions WHERE site_id=$1 AND source_event_id=$2 FOR UPDATE`,
|
|
5186
|
+
[input.siteId, input.sourceEventId]
|
|
5187
|
+
);
|
|
5188
|
+
if (!existing.rows[0]) throw new AnalyticsRepositoryError("analytics_conversion_conflict", "Conversion conflict could not be resolved.", 409);
|
|
5189
|
+
if (input.authority && existing.rows[0].authority_key !== input.authority.authorityKey) {
|
|
5190
|
+
throw new AnalyticsRepositoryError("analytics_conversion_authority_conflict", "The source event is already bound to a different revenue authority.", 409);
|
|
5191
|
+
}
|
|
5192
|
+
conversionId = existing.rows[0].id;
|
|
5193
|
+
}
|
|
5194
|
+
}
|
|
4648
5195
|
let queuedDestinations = 0;
|
|
4649
5196
|
if (created && input.activationPayloadCiphertext) {
|
|
4650
5197
|
const destinations = await client.query(
|
|
@@ -4671,7 +5218,7 @@ async function createAnalyticsConversion(input) {
|
|
|
4671
5218
|
}
|
|
4672
5219
|
}
|
|
4673
5220
|
await client.query("COMMIT");
|
|
4674
|
-
return { id: conversionId, created, queuedDestinations };
|
|
5221
|
+
return { id: conversionId, created, restated, queuedDestinations };
|
|
4675
5222
|
} catch (error) {
|
|
4676
5223
|
await client.query("ROLLBACK");
|
|
4677
5224
|
throw error;
|
|
@@ -7375,6 +7922,9 @@ export {
|
|
|
7375
7922
|
assertConnectionSupportsProvider,
|
|
7376
7923
|
buildProviderDeliveryRequest,
|
|
7377
7924
|
normalizeProviderReceipt,
|
|
7925
|
+
ANALYTICS_ATTRIBUTION_MODELS,
|
|
7926
|
+
buildAnalyticsAttributionReport,
|
|
7927
|
+
readImmutableConfirmedAttributionEvidence,
|
|
7378
7928
|
AnalyticsRepositoryError,
|
|
7379
7929
|
getAnalyticsPool,
|
|
7380
7930
|
closeAnalyticsPool,
|
|
@@ -7407,6 +7957,10 @@ export {
|
|
|
7407
7957
|
normalizeAnalyticsUrl,
|
|
7408
7958
|
sanitizeAnalyticsProperties,
|
|
7409
7959
|
ingestAnalyticsEvents,
|
|
7960
|
+
insertAnalyticsRevenueSetupRevision,
|
|
7961
|
+
appendAnalyticsAuthoritativeOutcomeVersion,
|
|
7962
|
+
projectAnalyticsAuthoritativeConversion,
|
|
7963
|
+
consumeAnalyticsSurveyInvite,
|
|
7410
7964
|
createAnalyticsConversion,
|
|
7411
7965
|
analyticsOverview,
|
|
7412
7966
|
analyticsTimeseries,
|