@adcp/sdk 6.5.0 → 6.6.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/bin/adcp.js +99 -0
- package/dist/lib/core/AgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
- package/dist/lib/core/SingleAgentClient.js +31 -0
- package/dist/lib/core/SingleAgentClient.js.map +1 -1
- package/dist/lib/mock-server/creative-template/seed-data.d.ts +45 -0
- package/dist/lib/mock-server/creative-template/seed-data.d.ts.map +1 -0
- package/dist/lib/mock-server/creative-template/seed-data.js +149 -0
- package/dist/lib/mock-server/creative-template/seed-data.js.map +1 -0
- package/dist/lib/mock-server/creative-template/server.d.ts +13 -0
- package/dist/lib/mock-server/creative-template/server.d.ts.map +1 -0
- package/dist/lib/mock-server/creative-template/server.js +280 -0
- package/dist/lib/mock-server/creative-template/server.js.map +1 -0
- package/dist/lib/mock-server/index.d.ts +38 -0
- package/dist/lib/mock-server/index.d.ts.map +1 -0
- package/dist/lib/mock-server/index.js +107 -0
- package/dist/lib/mock-server/index.js.map +1 -0
- package/dist/lib/mock-server/signal-marketplace/seed-data.d.ts +77 -0
- package/dist/lib/mock-server/signal-marketplace/seed-data.d.ts.map +1 -0
- package/dist/lib/mock-server/signal-marketplace/seed-data.js +194 -0
- package/dist/lib/mock-server/signal-marketplace/seed-data.js.map +1 -0
- package/dist/lib/mock-server/signal-marketplace/server.d.ts +15 -0
- package/dist/lib/mock-server/signal-marketplace/server.d.ts.map +1 -0
- package/dist/lib/mock-server/signal-marketplace/server.js +333 -0
- package/dist/lib/mock-server/signal-marketplace/server.js.map +1 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/decisioning/capabilities.d.ts +7 -2
- package/dist/lib/server/decisioning/capabilities.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +144 -2
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/testing/storyboard/loader.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/loader.js +38 -0
- package/dist/lib/testing/storyboard/loader.js.map +1 -1
- package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/runner.js +67 -52
- package/dist/lib/testing/storyboard/runner.js.map +1 -1
- package/dist/lib/testing/storyboard/types.d.ts +33 -0
- package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/types.js.map +1 -1
- package/dist/lib/utils/capabilities.d.ts +22 -0
- package/dist/lib/utils/capabilities.d.ts.map +1 -1
- package/dist/lib/utils/capabilities.js +44 -0
- package/dist/lib/utils/capabilities.js.map +1 -1
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/package.json +1 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export interface MockCohort {
|
|
2
|
+
cohort_id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
category: 'behavioral' | 'demographic' | 'intent' | 'contextual' | 'retargeting';
|
|
6
|
+
member_count: number;
|
|
7
|
+
total_universe: number;
|
|
8
|
+
freshness_days: number;
|
|
9
|
+
activation_status: 'active' | 'draft' | 'archived';
|
|
10
|
+
data_provider_domain: string;
|
|
11
|
+
data_provider_id: string;
|
|
12
|
+
/** Human-readable name of the upstream data provider — flows directly to
|
|
13
|
+
* AdCP `signal_id.data_provider` (required by signals response schema).
|
|
14
|
+
* Without it, adapters have to fabricate the value from the domain, which
|
|
15
|
+
* trains the wrong reflex. */
|
|
16
|
+
data_provider_name: string;
|
|
17
|
+
value_type: 'binary' | 'numeric' | 'categorical';
|
|
18
|
+
range?: {
|
|
19
|
+
min: number;
|
|
20
|
+
max: number;
|
|
21
|
+
};
|
|
22
|
+
categories?: string[];
|
|
23
|
+
pricing: MockPricingTier[];
|
|
24
|
+
metadata?: Record<string, unknown>;
|
|
25
|
+
created_at: string;
|
|
26
|
+
updated_at: string;
|
|
27
|
+
}
|
|
28
|
+
export interface MockPricingTier {
|
|
29
|
+
pricing_id: string;
|
|
30
|
+
model: 'cpm';
|
|
31
|
+
cpm_amount: number;
|
|
32
|
+
currency: string;
|
|
33
|
+
minimum_spend?: number;
|
|
34
|
+
}
|
|
35
|
+
export interface MockDestination {
|
|
36
|
+
destination_id: string;
|
|
37
|
+
name: string;
|
|
38
|
+
platform_type: 'dsp' | 'ssp' | 'social' | 'ctv' | 'retail' | 'agent';
|
|
39
|
+
integration: 'api_push' | 'segment_id' | 'key_value' | 'agent_url';
|
|
40
|
+
platform_code?: string;
|
|
41
|
+
agent_url?: string;
|
|
42
|
+
expected_match_rate?: number;
|
|
43
|
+
}
|
|
44
|
+
export interface MockOperator {
|
|
45
|
+
operator_id: string;
|
|
46
|
+
display_name: string;
|
|
47
|
+
/** AdCP-side operator identifier the adapter receives in `account.operator`. */
|
|
48
|
+
adcp_operator: string;
|
|
49
|
+
visible_cohort_ids: string[];
|
|
50
|
+
visible_destination_ids: string[];
|
|
51
|
+
/** Map of cohort_id → operator-scoped pricing override. Falls back to default pricing if absent. */
|
|
52
|
+
pricing_overrides: Record<string, MockPricingTier[]>;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Default pricing for each cohort. Operator-specific overrides live on the
|
|
56
|
+
* MockOperator entries below — this is what `op_pinnacle` (the storyboard's
|
|
57
|
+
* operator) sees. A second operator in this fixture (`op_summit`) sees the
|
|
58
|
+
* same Trident cohorts at a different rate.
|
|
59
|
+
*/
|
|
60
|
+
export declare const COHORTS: MockCohort[];
|
|
61
|
+
export declare const DESTINATIONS: MockDestination[];
|
|
62
|
+
/**
|
|
63
|
+
* Mapping table the adapter has to consume. The AdCP request carries
|
|
64
|
+
* `account.operator: "pinnacle-agency.example"`; the adapter maps that to
|
|
65
|
+
* the upstream operator_id and sends `X-Operator-Id` accordingly.
|
|
66
|
+
*
|
|
67
|
+
* Two operators are seeded so the adapter MUST respect the mapping — using
|
|
68
|
+
* the wrong operator id (or omitting the header) yields a different cohort
|
|
69
|
+
* set and the storyboard fails.
|
|
70
|
+
*/
|
|
71
|
+
export declare const OPERATORS: MockOperator[];
|
|
72
|
+
/**
|
|
73
|
+
* Default static API key shared across all operators owned by the customer.
|
|
74
|
+
* Override at boot via `--api-key` if a test wants a different value.
|
|
75
|
+
*/
|
|
76
|
+
export declare const DEFAULT_API_KEY = "mock_signal_market_key_do_not_use_in_prod";
|
|
77
|
+
//# sourceMappingURL=seed-data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed-data.d.ts","sourceRoot":"","sources":["../../../../src/lib/mock-server/signal-marketplace/seed-data.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,YAAY,GAAG,aAAa,GAAG,QAAQ,GAAG,YAAY,GAAG,aAAa,CAAC;IACjF,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;IACnD,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;kCAG8B;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,QAAQ,GAAG,SAAS,GAAG,aAAa,CAAC;IACjD,KAAK,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;IACrE,WAAW,EAAE,UAAU,GAAG,YAAY,GAAG,WAAW,GAAG,WAAW,CAAC;IACnE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,uBAAuB,EAAE,MAAM,EAAE,CAAC;IAClC,oGAAoG;IACpG,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;CACtD;AAKD;;;;;GAKG;AACH,eAAO,MAAM,OAAO,EAAE,UAAU,EA0G/B,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,eAAe,EAyBzC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,EAAE,YAAY,EAsCnC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,8CAA8C,CAAC"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_API_KEY = exports.OPERATORS = exports.DESTINATIONS = exports.COHORTS = void 0;
|
|
4
|
+
const NOW = '2026-04-15T12:00:00Z';
|
|
5
|
+
const RECENT = '2026-04-30T08:30:00Z';
|
|
6
|
+
/**
|
|
7
|
+
* Default pricing for each cohort. Operator-specific overrides live on the
|
|
8
|
+
* MockOperator entries below — this is what `op_pinnacle` (the storyboard's
|
|
9
|
+
* operator) sees. A second operator in this fixture (`op_summit`) sees the
|
|
10
|
+
* same Trident cohorts at a different rate.
|
|
11
|
+
*/
|
|
12
|
+
exports.COHORTS = [
|
|
13
|
+
{
|
|
14
|
+
cohort_id: 'ckhsh_us_evb_2024q4_001',
|
|
15
|
+
name: 'Likely EV Buyers (Trident, US)',
|
|
16
|
+
description: 'Auto-intent shoppers showing strong EV-specific signals — model-comparison sessions, charger-locator activity, and EV-incentive content engagement.',
|
|
17
|
+
category: 'intent',
|
|
18
|
+
member_count: 8_000_000,
|
|
19
|
+
total_universe: 100_000_000,
|
|
20
|
+
freshness_days: 1,
|
|
21
|
+
activation_status: 'active',
|
|
22
|
+
data_provider_domain: 'tridentauto.example',
|
|
23
|
+
data_provider_id: 'likely_ev_buyers',
|
|
24
|
+
data_provider_name: 'Trident Auto Insights',
|
|
25
|
+
value_type: 'binary',
|
|
26
|
+
pricing: [
|
|
27
|
+
{
|
|
28
|
+
pricing_id: 'tier_default_evb_cpm',
|
|
29
|
+
model: 'cpm',
|
|
30
|
+
cpm_amount: 3.5,
|
|
31
|
+
currency: 'USD',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
metadata: { trident_taxonomy_version: '2024.4' },
|
|
35
|
+
created_at: NOW,
|
|
36
|
+
updated_at: RECENT,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
cohort_id: 'ckhsh_us_pp_2024q4_002',
|
|
40
|
+
name: 'Purchase Propensity Score (Trident, US)',
|
|
41
|
+
description: 'Per-user 0-1 propensity score for next-90-day vehicle purchase, modeled across browsing, dealership-visit, and credit-shopping signals.',
|
|
42
|
+
category: 'behavioral',
|
|
43
|
+
member_count: 55_000_000,
|
|
44
|
+
total_universe: 100_000_000,
|
|
45
|
+
freshness_days: 7,
|
|
46
|
+
activation_status: 'active',
|
|
47
|
+
data_provider_domain: 'tridentauto.example',
|
|
48
|
+
data_provider_id: 'purchase_propensity',
|
|
49
|
+
data_provider_name: 'Trident Auto Insights',
|
|
50
|
+
value_type: 'numeric',
|
|
51
|
+
range: { min: 0, max: 1 },
|
|
52
|
+
pricing: [
|
|
53
|
+
{
|
|
54
|
+
pricing_id: 'tier_default_pp_cpm',
|
|
55
|
+
model: 'cpm',
|
|
56
|
+
cpm_amount: 4.0,
|
|
57
|
+
currency: 'USD',
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
metadata: { trident_taxonomy_version: '2024.4' },
|
|
61
|
+
created_at: NOW,
|
|
62
|
+
updated_at: RECENT,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
cohort_id: 'ckhsh_us_cv_2024q4_003',
|
|
66
|
+
name: 'Competitor Dealer Visitors (Meridian, US)',
|
|
67
|
+
description: 'Mobile devices observed in geofenced areas around competitor auto-dealer locations within the past 30 days.',
|
|
68
|
+
category: 'behavioral',
|
|
69
|
+
member_count: 6_000_000,
|
|
70
|
+
total_universe: 100_000_000,
|
|
71
|
+
freshness_days: 3,
|
|
72
|
+
activation_status: 'active',
|
|
73
|
+
data_provider_domain: 'meridiangeo.example',
|
|
74
|
+
data_provider_id: 'competitor_visitors',
|
|
75
|
+
data_provider_name: 'Meridian Geo',
|
|
76
|
+
value_type: 'binary',
|
|
77
|
+
pricing: [
|
|
78
|
+
{
|
|
79
|
+
pricing_id: 'tier_default_cv_cpm',
|
|
80
|
+
model: 'cpm',
|
|
81
|
+
cpm_amount: 5.0,
|
|
82
|
+
currency: 'USD',
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
metadata: { meridian_geo_radius_meters: 250 },
|
|
86
|
+
created_at: NOW,
|
|
87
|
+
updated_at: RECENT,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
cohort_id: 'ckhsh_us_ntb_2024q4_004',
|
|
91
|
+
name: 'New-to-Brand Auto Shoppers (ShopGrid, US)',
|
|
92
|
+
description: 'Shoppers researching auto purchases who have no prior transaction history with target brand. Built from ShopGrid retail-exhaust data.',
|
|
93
|
+
category: 'intent',
|
|
94
|
+
member_count: 25_000_000,
|
|
95
|
+
total_universe: 100_000_000,
|
|
96
|
+
freshness_days: 2,
|
|
97
|
+
activation_status: 'active',
|
|
98
|
+
data_provider_domain: 'shopgrid.example',
|
|
99
|
+
data_provider_id: 'new_to_brand',
|
|
100
|
+
data_provider_name: 'ShopGrid Retail Data',
|
|
101
|
+
value_type: 'binary',
|
|
102
|
+
pricing: [
|
|
103
|
+
{
|
|
104
|
+
pricing_id: 'tier_default_ntb_cpm',
|
|
105
|
+
model: 'cpm',
|
|
106
|
+
cpm_amount: 3.5,
|
|
107
|
+
currency: 'USD',
|
|
108
|
+
},
|
|
109
|
+
],
|
|
110
|
+
metadata: { shopgrid_lookback_days: 180 },
|
|
111
|
+
created_at: NOW,
|
|
112
|
+
updated_at: RECENT,
|
|
113
|
+
},
|
|
114
|
+
];
|
|
115
|
+
exports.DESTINATIONS = [
|
|
116
|
+
{
|
|
117
|
+
destination_id: 'dest_ttd_main',
|
|
118
|
+
name: 'The Trade Desk — Production',
|
|
119
|
+
platform_type: 'dsp',
|
|
120
|
+
integration: 'segment_id',
|
|
121
|
+
platform_code: 'the-trade-desk',
|
|
122
|
+
expected_match_rate: 0.78,
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
destination_id: 'dest_streamhaus_ctv',
|
|
126
|
+
name: 'StreamHaus CTV',
|
|
127
|
+
platform_type: 'ctv',
|
|
128
|
+
integration: 'segment_id',
|
|
129
|
+
platform_code: 'streamhaus',
|
|
130
|
+
expected_match_rate: 0.62,
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
destination_id: 'dest_wonderstruck_agent',
|
|
134
|
+
name: 'Wonderstruck Sales Agent',
|
|
135
|
+
platform_type: 'agent',
|
|
136
|
+
integration: 'agent_url',
|
|
137
|
+
agent_url: 'https://wonderstruck.salesagents.example',
|
|
138
|
+
expected_match_rate: 0.95,
|
|
139
|
+
},
|
|
140
|
+
];
|
|
141
|
+
/**
|
|
142
|
+
* Mapping table the adapter has to consume. The AdCP request carries
|
|
143
|
+
* `account.operator: "pinnacle-agency.example"`; the adapter maps that to
|
|
144
|
+
* the upstream operator_id and sends `X-Operator-Id` accordingly.
|
|
145
|
+
*
|
|
146
|
+
* Two operators are seeded so the adapter MUST respect the mapping — using
|
|
147
|
+
* the wrong operator id (or omitting the header) yields a different cohort
|
|
148
|
+
* set and the storyboard fails.
|
|
149
|
+
*/
|
|
150
|
+
exports.OPERATORS = [
|
|
151
|
+
{
|
|
152
|
+
operator_id: 'op_pinnacle',
|
|
153
|
+
display_name: 'Pinnacle Agency',
|
|
154
|
+
adcp_operator: 'pinnacle-agency.example',
|
|
155
|
+
visible_cohort_ids: exports.COHORTS.map(c => c.cohort_id),
|
|
156
|
+
visible_destination_ids: exports.DESTINATIONS.map(d => d.destination_id),
|
|
157
|
+
pricing_overrides: {},
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
operator_id: 'op_summit',
|
|
161
|
+
display_name: 'Summit Media',
|
|
162
|
+
adcp_operator: 'summit-media.example',
|
|
163
|
+
// Only sees Trident cohorts.
|
|
164
|
+
visible_cohort_ids: ['ckhsh_us_evb_2024q4_001', 'ckhsh_us_pp_2024q4_002'],
|
|
165
|
+
visible_destination_ids: ['dest_ttd_main', 'dest_streamhaus_ctv'],
|
|
166
|
+
// Premium rate card — same cohorts, +$1 CPM.
|
|
167
|
+
pricing_overrides: {
|
|
168
|
+
ckhsh_us_evb_2024q4_001: [
|
|
169
|
+
{
|
|
170
|
+
pricing_id: 'tier_summit_evb_cpm',
|
|
171
|
+
model: 'cpm',
|
|
172
|
+
cpm_amount: 4.5,
|
|
173
|
+
currency: 'USD',
|
|
174
|
+
minimum_spend: 10_000,
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
ckhsh_us_pp_2024q4_002: [
|
|
178
|
+
{
|
|
179
|
+
pricing_id: 'tier_summit_pp_cpm',
|
|
180
|
+
model: 'cpm',
|
|
181
|
+
cpm_amount: 5.0,
|
|
182
|
+
currency: 'USD',
|
|
183
|
+
minimum_spend: 10_000,
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
];
|
|
189
|
+
/**
|
|
190
|
+
* Default static API key shared across all operators owned by the customer.
|
|
191
|
+
* Override at boot via `--api-key` if a test wants a different value.
|
|
192
|
+
*/
|
|
193
|
+
exports.DEFAULT_API_KEY = 'mock_signal_market_key_do_not_use_in_prod';
|
|
194
|
+
//# sourceMappingURL=seed-data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed-data.js","sourceRoot":"","sources":["../../../../src/lib/mock-server/signal-marketplace/seed-data.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type MockCohort, type MockDestination, type MockOperator } from './seed-data';
|
|
2
|
+
export interface BootOptions {
|
|
3
|
+
port: number;
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
/** Override seed cohorts. Defaults to fixture data. */
|
|
6
|
+
cohorts?: MockCohort[];
|
|
7
|
+
destinations?: MockDestination[];
|
|
8
|
+
operators?: MockOperator[];
|
|
9
|
+
}
|
|
10
|
+
export interface BootResult {
|
|
11
|
+
url: string;
|
|
12
|
+
close: () => Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export declare function bootSignalMarketplace(options: BootOptions): Promise<BootResult>;
|
|
15
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../../src/lib/mock-server/signal-marketplace/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,YAAY,EAElB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,eAAe,EAAE,CAAC;IACjC,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAqDrF"}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bootSignalMarketplace = bootSignalMarketplace;
|
|
4
|
+
const node_http_1 = require("node:http");
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
const seed_data_1 = require("./seed-data");
|
|
7
|
+
async function bootSignalMarketplace(options) {
|
|
8
|
+
const apiKey = options.apiKey ?? seed_data_1.DEFAULT_API_KEY;
|
|
9
|
+
const cohorts = options.cohorts ?? seed_data_1.COHORTS;
|
|
10
|
+
const destinations = options.destinations ?? seed_data_1.DESTINATIONS;
|
|
11
|
+
const operators = options.operators ?? seed_data_1.OPERATORS;
|
|
12
|
+
// Activations live in memory. Keyed by activation_id; cross-checked against
|
|
13
|
+
// operator_id on read so cross-tenant leakage shows up as 403.
|
|
14
|
+
const activations = new Map();
|
|
15
|
+
// client_request_id idempotency table — keyed by `<operator_id>::<client_request_id>`
|
|
16
|
+
// so two operators can use the same client_request_id and not collide.
|
|
17
|
+
const idempotency = new Map();
|
|
18
|
+
const server = (0, node_http_1.createServer)((req, res) => {
|
|
19
|
+
handleRequest(req, res, {
|
|
20
|
+
apiKey,
|
|
21
|
+
cohorts,
|
|
22
|
+
destinations,
|
|
23
|
+
operators,
|
|
24
|
+
activations,
|
|
25
|
+
idempotency,
|
|
26
|
+
}).catch(err => {
|
|
27
|
+
// Defense-in-depth — handlers should never throw, but if one does we
|
|
28
|
+
// emit a 500 with a request_id so adopter logs can still trace it.
|
|
29
|
+
const requestId = req.headers['x-request-id'] ?? (0, node_crypto_1.randomUUID)();
|
|
30
|
+
writeJson(res, 500, {
|
|
31
|
+
code: 'internal_error',
|
|
32
|
+
message: err?.message ?? 'unexpected error',
|
|
33
|
+
request_id: requestId,
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
await new Promise((resolve, reject) => {
|
|
38
|
+
server.once('error', reject);
|
|
39
|
+
server.listen(options.port, '127.0.0.1', () => {
|
|
40
|
+
server.removeListener('error', reject);
|
|
41
|
+
resolve();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
// Use the actually-bound port. Caller may pass 0 to request an OS-assigned
|
|
45
|
+
// free port (test convenience); reading address() gives the truth either way.
|
|
46
|
+
const addr = server.address();
|
|
47
|
+
const boundPort = typeof addr === 'object' && addr ? addr.port : options.port;
|
|
48
|
+
const url = `http://127.0.0.1:${boundPort}`;
|
|
49
|
+
return {
|
|
50
|
+
url,
|
|
51
|
+
close: () => new Promise((resolve, reject) => {
|
|
52
|
+
server.close(err => (err ? reject(err) : resolve()));
|
|
53
|
+
}),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async function handleRequest(req, res, ctx) {
|
|
57
|
+
// Authentication first. Order matters — surface bad-credential errors before
|
|
58
|
+
// operator/cohort lookups so adopters can debug auth in isolation.
|
|
59
|
+
const auth = req.headers['authorization'];
|
|
60
|
+
if (!auth || !auth.startsWith('Bearer ') || auth.slice(7) !== ctx.apiKey) {
|
|
61
|
+
writeJson(res, 401, { code: 'unauthorized', message: 'Missing or invalid bearer credential.' });
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const operatorHeader = req.headers['x-operator-id'];
|
|
65
|
+
const operatorId = Array.isArray(operatorHeader) ? operatorHeader[0] : operatorHeader;
|
|
66
|
+
if (!operatorId) {
|
|
67
|
+
writeJson(res, 403, {
|
|
68
|
+
code: 'operator_required',
|
|
69
|
+
message: 'X-Operator-Id header is required on every request.',
|
|
70
|
+
});
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const operator = ctx.operators.find(o => o.operator_id === operatorId);
|
|
74
|
+
if (!operator) {
|
|
75
|
+
writeJson(res, 403, {
|
|
76
|
+
code: 'unknown_operator',
|
|
77
|
+
message: `Unknown operator: ${operatorId}`,
|
|
78
|
+
});
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const url = new URL(req.url ?? '/', `http://127.0.0.1`);
|
|
82
|
+
const path = url.pathname;
|
|
83
|
+
const method = req.method ?? 'GET';
|
|
84
|
+
// GET /v2/cohorts
|
|
85
|
+
if (method === 'GET' && path === '/v2/cohorts') {
|
|
86
|
+
return handleListCohorts(url, ctx, operator, res);
|
|
87
|
+
}
|
|
88
|
+
// GET /v2/cohorts/{id}
|
|
89
|
+
const cohortMatch = path.match(/^\/v2\/cohorts\/([^/]+)$/);
|
|
90
|
+
if (method === 'GET' && cohortMatch && cohortMatch[1]) {
|
|
91
|
+
return handleGetCohort(decodeURIComponent(cohortMatch[1]), ctx, operator, res);
|
|
92
|
+
}
|
|
93
|
+
// GET /v2/destinations
|
|
94
|
+
if (method === 'GET' && path === '/v2/destinations') {
|
|
95
|
+
return handleListDestinations(ctx, operator, res);
|
|
96
|
+
}
|
|
97
|
+
// POST /v2/activations
|
|
98
|
+
if (method === 'POST' && path === '/v2/activations') {
|
|
99
|
+
return handleCreateActivation(req, ctx, operator, res);
|
|
100
|
+
}
|
|
101
|
+
// GET /v2/activations/{id}
|
|
102
|
+
const activationMatch = path.match(/^\/v2\/activations\/([^/]+)$/);
|
|
103
|
+
if (method === 'GET' && activationMatch && activationMatch[1]) {
|
|
104
|
+
return handleGetActivation(decodeURIComponent(activationMatch[1]), ctx, operator, res);
|
|
105
|
+
}
|
|
106
|
+
writeJson(res, 404, { code: 'not_found', message: `No route for ${method} ${path}` });
|
|
107
|
+
}
|
|
108
|
+
function handleListCohorts(url, ctx, op, res) {
|
|
109
|
+
const visible = ctx.cohorts.filter(c => op.visible_cohort_ids.includes(c.cohort_id));
|
|
110
|
+
const category = url.searchParams.get('category');
|
|
111
|
+
const dataProviderDomain = url.searchParams.get('data_provider_domain');
|
|
112
|
+
const q = url.searchParams.get('q')?.toLowerCase();
|
|
113
|
+
let filtered = visible;
|
|
114
|
+
if (category)
|
|
115
|
+
filtered = filtered.filter(c => c.category === category);
|
|
116
|
+
if (dataProviderDomain)
|
|
117
|
+
filtered = filtered.filter(c => c.data_provider_domain === dataProviderDomain);
|
|
118
|
+
if (q) {
|
|
119
|
+
filtered = filtered.filter(c => c.name.toLowerCase().includes(q) || c.description.toLowerCase().includes(q));
|
|
120
|
+
}
|
|
121
|
+
const projected = filtered.map(c => projectCohortPricing(c, op));
|
|
122
|
+
writeJson(res, 200, { cohorts: projected });
|
|
123
|
+
}
|
|
124
|
+
function handleGetCohort(cohortId, ctx, op, res) {
|
|
125
|
+
const cohort = ctx.cohorts.find(c => c.cohort_id === cohortId);
|
|
126
|
+
if (!cohort) {
|
|
127
|
+
writeJson(res, 404, { code: 'cohort_not_found', message: `Cohort ${cohortId} not found.` });
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (!op.visible_cohort_ids.includes(cohortId)) {
|
|
131
|
+
// Distinguish "not visible to you" from "doesn't exist" — both real upstreams
|
|
132
|
+
// do this and it forces the adapter to handle 403 separately from 404.
|
|
133
|
+
writeJson(res, 403, {
|
|
134
|
+
code: 'cohort_not_visible',
|
|
135
|
+
message: `Cohort ${cohortId} is not visible to operator ${op.operator_id}.`,
|
|
136
|
+
});
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
writeJson(res, 200, projectCohortPricing(cohort, op));
|
|
140
|
+
}
|
|
141
|
+
function handleListDestinations(ctx, op, res) {
|
|
142
|
+
const visible = ctx.destinations.filter(d => op.visible_destination_ids.includes(d.destination_id));
|
|
143
|
+
writeJson(res, 200, { destinations: visible });
|
|
144
|
+
}
|
|
145
|
+
async function handleCreateActivation(req, ctx, op, res) {
|
|
146
|
+
let body;
|
|
147
|
+
try {
|
|
148
|
+
body = await readJson(req);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
writeJson(res, 400, { code: 'invalid_json', message: 'Request body must be valid JSON.' });
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (!isObject(body)) {
|
|
155
|
+
writeJson(res, 400, { code: 'invalid_request', message: 'Body must be an object.' });
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const { cohort_id, destination_id, pricing_id, duration_days, client_request_id } = body;
|
|
159
|
+
if (typeof cohort_id !== 'string' || typeof destination_id !== 'string' || typeof pricing_id !== 'string') {
|
|
160
|
+
writeJson(res, 400, {
|
|
161
|
+
code: 'invalid_request',
|
|
162
|
+
message: 'cohort_id, destination_id, and pricing_id are required strings.',
|
|
163
|
+
});
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
// Idempotency replay — same client_request_id under same operator returns the
|
|
167
|
+
// existing activation. Different operators using the same client_request_id
|
|
168
|
+
// are independent because the table is keyed on `<operator_id>::<key>`.
|
|
169
|
+
// Body equivalence: replays with mismatched (cohort_id, destination_id,
|
|
170
|
+
// pricing_id) return 409 idempotency_conflict instead of silently returning
|
|
171
|
+
// the original — matches Stripe's idempotency contract and the AdCP spec
|
|
172
|
+
// semantics. Surfaces adapter bugs that reuse a single client_request_id
|
|
173
|
+
// across logically-distinct AdCP requests instead of hiding them.
|
|
174
|
+
if (typeof client_request_id === 'string' && client_request_id.length > 0) {
|
|
175
|
+
const idemKey = `${op.operator_id}::${client_request_id}`;
|
|
176
|
+
const existing = ctx.idempotency.get(idemKey);
|
|
177
|
+
if (existing) {
|
|
178
|
+
const activation = ctx.activations.get(existing);
|
|
179
|
+
if (activation) {
|
|
180
|
+
const sameBody = activation.cohort_id === cohort_id &&
|
|
181
|
+
activation.destination_id === destination_id &&
|
|
182
|
+
activation.pricing_id === pricing_id;
|
|
183
|
+
if (!sameBody) {
|
|
184
|
+
writeJson(res, 409, {
|
|
185
|
+
code: 'idempotency_conflict',
|
|
186
|
+
message: `client_request_id ${client_request_id} was previously used with a different ` +
|
|
187
|
+
`(cohort_id, destination_id, pricing_id) tuple. ` +
|
|
188
|
+
`Use a fresh idempotency key for distinct requests.`,
|
|
189
|
+
});
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
writeJson(res, 200, serializeActivation(activation));
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
const cohort = ctx.cohorts.find(c => c.cohort_id === cohort_id);
|
|
198
|
+
if (!cohort || !op.visible_cohort_ids.includes(cohort_id)) {
|
|
199
|
+
writeJson(res, cohort ? 403 : 404, {
|
|
200
|
+
code: cohort ? 'cohort_not_visible' : 'cohort_not_found',
|
|
201
|
+
message: `Cohort ${cohort_id} ${cohort ? 'not visible to operator' : 'not found'}.`,
|
|
202
|
+
});
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
const destination = ctx.destinations.find(d => d.destination_id === destination_id);
|
|
206
|
+
if (!destination || !op.visible_destination_ids.includes(destination_id)) {
|
|
207
|
+
writeJson(res, destination ? 403 : 404, {
|
|
208
|
+
code: destination ? 'destination_not_visible' : 'destination_not_found',
|
|
209
|
+
message: `Destination ${destination_id} ${destination ? 'not visible' : 'not found'}.`,
|
|
210
|
+
});
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const pricingTiers = pricingForCohort(cohort, op);
|
|
214
|
+
const tier = pricingTiers.find(t => t.pricing_id === pricing_id);
|
|
215
|
+
if (!tier) {
|
|
216
|
+
writeJson(res, 400, {
|
|
217
|
+
code: 'invalid_pricing',
|
|
218
|
+
message: `pricing_id ${pricing_id} is not a valid tier for this cohort under operator ${op.operator_id}.`,
|
|
219
|
+
});
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const activationId = `act_${(0, node_crypto_1.randomUUID)().replace(/-/g, '').slice(0, 16)}`;
|
|
223
|
+
const now = new Date();
|
|
224
|
+
const expiresAt = new Date(now.getTime() + (typeof duration_days === 'number' ? duration_days : 90) * 86400_000);
|
|
225
|
+
// Agent destinations activate synchronously (the SA records and confirms);
|
|
226
|
+
// DSP/CTV destinations are async — initial pending, transitions to active
|
|
227
|
+
// when the storyboard's later poll fetches.
|
|
228
|
+
const isAgentDest = destination.platform_type === 'agent';
|
|
229
|
+
const activation = {
|
|
230
|
+
activation_id: activationId,
|
|
231
|
+
operator_id: op.operator_id,
|
|
232
|
+
cohort_id,
|
|
233
|
+
destination_id,
|
|
234
|
+
pricing_id,
|
|
235
|
+
status: isAgentDest ? 'active' : 'pending',
|
|
236
|
+
created_at: now.toISOString(),
|
|
237
|
+
updated_at: now.toISOString(),
|
|
238
|
+
expires_at: expiresAt.toISOString(),
|
|
239
|
+
...(isAgentDest
|
|
240
|
+
? {
|
|
241
|
+
agent_activation_key: { agent_segment: cohort.data_provider_id },
|
|
242
|
+
match_rate: destination.expected_match_rate ?? 0.9,
|
|
243
|
+
member_count_matched: cohort.member_count,
|
|
244
|
+
}
|
|
245
|
+
: {}),
|
|
246
|
+
};
|
|
247
|
+
ctx.activations.set(activationId, activation);
|
|
248
|
+
if (typeof client_request_id === 'string' && client_request_id.length > 0) {
|
|
249
|
+
ctx.idempotency.set(`${op.operator_id}::${client_request_id}`, activationId);
|
|
250
|
+
}
|
|
251
|
+
writeJson(res, 201, serializeActivation(activation));
|
|
252
|
+
}
|
|
253
|
+
function handleGetActivation(activationId, ctx, op, res) {
|
|
254
|
+
const activation = ctx.activations.get(activationId);
|
|
255
|
+
if (!activation) {
|
|
256
|
+
writeJson(res, 404, { code: 'activation_not_found', message: `Activation ${activationId} not found.` });
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (activation.operator_id !== op.operator_id) {
|
|
260
|
+
// Cross-operator read attempt — surfaces as 403, not 404, so an attacker
|
|
261
|
+
// can't probe activation ID space across tenants. Real platforms vary on
|
|
262
|
+
// this (some return 404 to avoid existence oracles); 403 here is the
|
|
263
|
+
// adopter-friendly choice for a fixture.
|
|
264
|
+
writeJson(res, 403, {
|
|
265
|
+
code: 'activation_not_visible',
|
|
266
|
+
message: `Activation ${activationId} belongs to a different operator.`,
|
|
267
|
+
});
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
// Auto-promote pending DSP activations to in_progress on first poll, then
|
|
271
|
+
// active on second poll. Storyboard's polling loop walks this state machine.
|
|
272
|
+
if (activation.status === 'pending') {
|
|
273
|
+
activation.status = 'in_progress';
|
|
274
|
+
activation.updated_at = new Date().toISOString();
|
|
275
|
+
}
|
|
276
|
+
else if (activation.status === 'in_progress') {
|
|
277
|
+
const cohort = ctx.cohorts.find(c => c.cohort_id === activation.cohort_id);
|
|
278
|
+
const destination = ctx.destinations.find(d => d.destination_id === activation.destination_id);
|
|
279
|
+
activation.status = 'active';
|
|
280
|
+
activation.match_rate = destination?.expected_match_rate ?? 0.75;
|
|
281
|
+
activation.member_count_matched = Math.floor((cohort?.member_count ?? 0) * (destination?.expected_match_rate ?? 0.75));
|
|
282
|
+
activation.platform_segment_id = `seg_${activation.activation_id.replace('act_', '')}`;
|
|
283
|
+
activation.updated_at = new Date().toISOString();
|
|
284
|
+
}
|
|
285
|
+
writeJson(res, 200, serializeActivation(activation));
|
|
286
|
+
}
|
|
287
|
+
function projectCohortPricing(cohort, op) {
|
|
288
|
+
return {
|
|
289
|
+
...cohort,
|
|
290
|
+
pricing: pricingForCohort(cohort, op),
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
function pricingForCohort(cohort, op) {
|
|
294
|
+
const override = op.pricing_overrides[cohort.cohort_id];
|
|
295
|
+
return override && override.length > 0 ? override : cohort.pricing;
|
|
296
|
+
}
|
|
297
|
+
function serializeActivation(a) {
|
|
298
|
+
// operator_id is internal book-keeping — not part of the public contract.
|
|
299
|
+
const { operator_id, ...rest } = a;
|
|
300
|
+
return rest;
|
|
301
|
+
}
|
|
302
|
+
function readJson(req) {
|
|
303
|
+
return new Promise((resolve, reject) => {
|
|
304
|
+
const chunks = [];
|
|
305
|
+
req.on('data', chunk => chunks.push(chunk));
|
|
306
|
+
req.on('error', reject);
|
|
307
|
+
req.on('end', () => {
|
|
308
|
+
const raw = Buffer.concat(chunks).toString('utf8');
|
|
309
|
+
if (!raw) {
|
|
310
|
+
resolve({});
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
try {
|
|
314
|
+
resolve(JSON.parse(raw));
|
|
315
|
+
}
|
|
316
|
+
catch (err) {
|
|
317
|
+
reject(err);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
function writeJson(res, status, body) {
|
|
323
|
+
const json = JSON.stringify(body);
|
|
324
|
+
res.writeHead(status, {
|
|
325
|
+
'content-type': 'application/json; charset=utf-8',
|
|
326
|
+
'content-length': Buffer.byteLength(json),
|
|
327
|
+
});
|
|
328
|
+
res.end(json);
|
|
329
|
+
}
|
|
330
|
+
function isObject(x) {
|
|
331
|
+
return typeof x === 'object' && x !== null && !Array.isArray(x);
|
|
332
|
+
}
|
|
333
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../../src/lib/mock-server/signal-marketplace/server.ts"],"names":[],"mappings":"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"}
|