@adcp/sdk 6.11.0 → 6.12.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-config.js +7 -1
- package/bin/adcp.js +191 -4
- package/dist/lib/adapters/index.d.ts +0 -2
- package/dist/lib/adapters/index.d.ts.map +1 -1
- package/dist/lib/adapters/index.js +1 -8
- package/dist/lib/adapters/index.js.map +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +2 -7
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/mock-server/index.d.ts +2 -0
- package/dist/lib/mock-server/index.d.ts.map +1 -1
- package/dist/lib/mock-server/index.js +17 -0
- package/dist/lib/mock-server/index.js.map +1 -1
- package/dist/lib/mock-server/sales-guaranteed/recipe.d.ts +155 -0
- package/dist/lib/mock-server/sales-guaranteed/recipe.d.ts.map +1 -0
- package/dist/lib/mock-server/sales-guaranteed/recipe.js +107 -0
- package/dist/lib/mock-server/sales-guaranteed/recipe.js.map +1 -0
- package/dist/lib/mock-server/sales-guaranteed/server.d.ts.map +1 -1
- package/dist/lib/mock-server/sales-guaranteed/server.js +212 -0
- package/dist/lib/mock-server/sales-guaranteed/server.js.map +1 -1
- package/dist/lib/mock-server/sales-non-guaranteed/recipe.d.ts +123 -0
- package/dist/lib/mock-server/sales-non-guaranteed/recipe.d.ts.map +1 -0
- package/dist/lib/mock-server/sales-non-guaranteed/recipe.js +81 -0
- package/dist/lib/mock-server/sales-non-guaranteed/recipe.js.map +1 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/ctx-metadata/index.d.ts +1 -1
- package/dist/lib/server/ctx-metadata/index.d.ts.map +1 -1
- package/dist/lib/server/ctx-metadata/index.js +3 -1
- package/dist/lib/server/ctx-metadata/index.js.map +1 -1
- package/dist/lib/server/ctx-metadata/wire-shape.d.ts +21 -0
- package/dist/lib/server/ctx-metadata/wire-shape.d.ts.map +1 -1
- package/dist/lib/server/ctx-metadata/wire-shape.js +111 -0
- package/dist/lib/server/ctx-metadata/wire-shape.js.map +1 -1
- package/dist/lib/server/decisioning/context.d.ts +19 -0
- package/dist/lib/server/decisioning/context.d.ts.map +1 -1
- package/dist/lib/server/decisioning/index.d.ts +3 -0
- package/dist/lib/server/decisioning/index.d.ts.map +1 -1
- package/dist/lib/server/decisioning/index.js +16 -1
- package/dist/lib/server/decisioning/index.js.map +1 -1
- package/dist/lib/server/decisioning/platform.d.ts +17 -0
- package/dist/lib/server/decisioning/platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/platform.js.map +1 -1
- package/dist/lib/server/decisioning/proposal/dispatch.d.ts +203 -0
- package/dist/lib/server/decisioning/proposal/dispatch.d.ts.map +1 -0
- package/dist/lib/server/decisioning/proposal/dispatch.js +395 -0
- package/dist/lib/server/decisioning/proposal/dispatch.js.map +1 -0
- package/dist/lib/server/decisioning/proposal/index.d.ts +21 -0
- package/dist/lib/server/decisioning/proposal/index.d.ts.map +1 -0
- package/dist/lib/server/decisioning/proposal/index.js +37 -0
- package/dist/lib/server/decisioning/proposal/index.js.map +1 -0
- package/dist/lib/server/decisioning/proposal/lifecycle.d.ts +195 -0
- package/dist/lib/server/decisioning/proposal/lifecycle.d.ts.map +1 -0
- package/dist/lib/server/decisioning/proposal/lifecycle.js +366 -0
- package/dist/lib/server/decisioning/proposal/lifecycle.js.map +1 -0
- package/dist/lib/server/decisioning/proposal/mock-manager.d.ts +93 -0
- package/dist/lib/server/decisioning/proposal/mock-manager.d.ts.map +1 -0
- package/dist/lib/server/decisioning/proposal/mock-manager.js +109 -0
- package/dist/lib/server/decisioning/proposal/mock-manager.js.map +1 -0
- package/dist/lib/server/decisioning/proposal/store.d.ts +279 -0
- package/dist/lib/server/decisioning/proposal/store.d.ts.map +1 -0
- package/dist/lib/server/decisioning/proposal/store.js +291 -0
- package/dist/lib/server/decisioning/proposal/store.js.map +1 -0
- package/dist/lib/server/decisioning/proposal/types.d.ts +394 -0
- package/dist/lib/server/decisioning/proposal/types.d.ts.map +1 -0
- package/dist/lib/server/decisioning/proposal/types.js +58 -0
- package/dist/lib/server/decisioning/proposal/types.js.map +1 -0
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts +25 -0
- package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/from-platform.js +198 -15
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/server/index.d.ts +1 -1
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +3 -1
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/testing/client.d.ts.map +1 -1
- package/dist/lib/testing/client.js +7 -1
- package/dist/lib/testing/client.js.map +1 -1
- package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/task-map.js +1 -0
- package/dist/lib/testing/storyboard/task-map.js.map +1 -1
- package/dist/lib/testing/storyboard/test-kit.d.ts.map +1 -1
- package/dist/lib/testing/storyboard/test-kit.js +4 -0
- package/dist/lib/testing/storyboard/test-kit.js.map +1 -1
- package/dist/lib/testing/types.d.ts +10 -0
- package/dist/lib/testing/types.d.ts.map +1 -1
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/examples/hello_seller_adapter_guaranteed.ts +29 -2
- package/examples/hello_seller_adapter_proposal_mode.ts +575 -0
- package/package.json +1 -1
- package/dist/lib/adapters/proposal-manager.d.ts +0 -142
- package/dist/lib/adapters/proposal-manager.d.ts.map +0 -1
- package/dist/lib/adapters/proposal-manager.js +0 -184
- package/dist/lib/adapters/proposal-manager.js.map +0 -1
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proposal-lifecycle framework helpers — the v1.5 intercept seam.
|
|
3
|
+
*
|
|
4
|
+
* Sits parallel to existing dispatch helpers in `runtime/from-platform.ts`.
|
|
5
|
+
* Framework intercepts at a seam, does its work, dispatches.
|
|
6
|
+
*
|
|
7
|
+
* Public surface (the dispatch path imports these):
|
|
8
|
+
*
|
|
9
|
+
* - {@link enforceProposalExpiry} — D7. Look up the committed proposal,
|
|
10
|
+
* validate `state === 'committed'` and `now <= expires_at + grace`,
|
|
11
|
+
* return the record.
|
|
12
|
+
* - {@link validateCapabilityOverlap} — D4. Walk a buyer's
|
|
13
|
+
* `create_media_buy` / `update_media_buy` request packages against
|
|
14
|
+
* each recipe's `capability_overlap` and reject mismatches with
|
|
15
|
+
* `INVALID_REQUEST`.
|
|
16
|
+
* - {@link validateOverlapSubsetOfWire} — D4 round-4. Validate at
|
|
17
|
+
* `putDraft` time that each recipe's `capability_overlap` axis is a
|
|
18
|
+
* subset of the corresponding wire-declared product capabilities.
|
|
19
|
+
* Mismatches throw `INTERNAL_ERROR` (adopter bug, not buyer bug).
|
|
20
|
+
* - {@link detectFinalizeAction} — pull out the first finalize-action
|
|
21
|
+
* refine entry from a `GetProductsRequest`.
|
|
22
|
+
* - structured-log helpers per § Observability.
|
|
23
|
+
*
|
|
24
|
+
* Ports `adcp-client-python.src/adcp/decisioning/proposal_lifecycle.py`.
|
|
25
|
+
*
|
|
26
|
+
* @public
|
|
27
|
+
* @packageDocumentation
|
|
28
|
+
*/
|
|
29
|
+
import type { GetProductsRequest, Product } from '../../../types/tools.generated';
|
|
30
|
+
import type { ProposalRecord, ProposalStore } from './store';
|
|
31
|
+
import type { Recipe } from './types';
|
|
32
|
+
/**
|
|
33
|
+
* Validate a proposal is committed and within its hold window.
|
|
34
|
+
*
|
|
35
|
+
* Three failure modes mapped to spec error codes:
|
|
36
|
+
*
|
|
37
|
+
* - Record not found OR cross-tenant → `PROPOSAL_NOT_FOUND` (terminal).
|
|
38
|
+
* Cross-tenant probes return the same error as missing IDs (no
|
|
39
|
+
* principal-enumeration via id probing).
|
|
40
|
+
* - State !== `'committed'` → `PROPOSAL_NOT_COMMITTED` (correctable).
|
|
41
|
+
* The buyer needs to call `getProducts({ buying_mode: 'refine',
|
|
42
|
+
* refine: [{ action: 'finalize' }] })` first.
|
|
43
|
+
* - Committed but `now > expires_at + grace` → `PROPOSAL_EXPIRED`
|
|
44
|
+
* (correctable per AdCP 3.0.6 — the buyer re-discovers via
|
|
45
|
+
* `get_products` to obtain a fresh proposal).
|
|
46
|
+
*
|
|
47
|
+
* @public
|
|
48
|
+
*/
|
|
49
|
+
export declare function enforceProposalExpiry<TRecipe extends Recipe>(proposalId: string, args: {
|
|
50
|
+
proposalStore: ProposalStore<TRecipe>;
|
|
51
|
+
expectedAccountId: string;
|
|
52
|
+
graceSeconds?: number;
|
|
53
|
+
now?: Date;
|
|
54
|
+
}): Promise<ProposalRecord<TRecipe>>;
|
|
55
|
+
interface PackageLike {
|
|
56
|
+
product_id?: string;
|
|
57
|
+
pricing_option_id?: string;
|
|
58
|
+
pricing_model?: string;
|
|
59
|
+
delivery_type?: string;
|
|
60
|
+
signal_type?: string;
|
|
61
|
+
targeting_overlay?: Record<string, unknown>;
|
|
62
|
+
/**
|
|
63
|
+
* Adopter-resolved pricing model — the validation reads this when
|
|
64
|
+
* present. Set by the framework when it has resolved
|
|
65
|
+
* `pricing_option_id` against the product's pricing options.
|
|
66
|
+
*/
|
|
67
|
+
_resolved_pricing_model?: string;
|
|
68
|
+
_resolved_delivery_type?: string;
|
|
69
|
+
[k: string]: unknown;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Pre-adapter validation seam: walk buyer's packages against each recipe's
|
|
73
|
+
* `capability_overlap` and reject mismatches.
|
|
74
|
+
*
|
|
75
|
+
* Called from the framework's `create_media_buy` and `update_media_buy`
|
|
76
|
+
* dispatch paths after recipes are hydrated from the {@link ProposalStore}.
|
|
77
|
+
* Per D4, the framework owns this gate so every adopter doesn't write the
|
|
78
|
+
* same intersection logic.
|
|
79
|
+
*
|
|
80
|
+
* Validation axes (per {@link CapabilityOverlap}):
|
|
81
|
+
*
|
|
82
|
+
* - `pricingModels` — checked against `package._resolved_pricing_model`
|
|
83
|
+
* or `package.pricing_model`.
|
|
84
|
+
* - `targetingDimensions` — checked against `package.targeting_overlay` keys.
|
|
85
|
+
* - `deliveryTypes` — checked against `package._resolved_delivery_type`
|
|
86
|
+
* or `package.delivery_type`.
|
|
87
|
+
* - `signalTypes` — checked against `package.signal_type`.
|
|
88
|
+
*
|
|
89
|
+
* Per the design's undefined-vs-empty-set semantics: `undefined` skips the
|
|
90
|
+
* gate; an explicit `Set` (including the empty set) is enforced.
|
|
91
|
+
*
|
|
92
|
+
* @public
|
|
93
|
+
*/
|
|
94
|
+
export declare function validateCapabilityOverlap<TRecipe extends Recipe>(args: {
|
|
95
|
+
packages: readonly PackageLike[];
|
|
96
|
+
recipes: ReadonlyMap<string, TRecipe>;
|
|
97
|
+
fieldPathPrefix?: string;
|
|
98
|
+
}): void;
|
|
99
|
+
/**
|
|
100
|
+
* Validate `recipe.capability_overlap` is a subset of the matching product's
|
|
101
|
+
* wire-declared capabilities.
|
|
102
|
+
*
|
|
103
|
+
* Called at `putDraft` time. Mismatches throw `INTERNAL_ERROR` — this is
|
|
104
|
+
* an adopter bug (the manager declared an overlap claiming capabilities the
|
|
105
|
+
* wire shape doesn't advertise), not a buyer bug.
|
|
106
|
+
*
|
|
107
|
+
* @public
|
|
108
|
+
*/
|
|
109
|
+
export declare function validateOverlapSubsetOfWire<TRecipe extends Recipe>(args: {
|
|
110
|
+
recipes: ReadonlyMap<string, TRecipe>;
|
|
111
|
+
products: readonly Product[];
|
|
112
|
+
}): void;
|
|
113
|
+
/**
|
|
114
|
+
* Result of {@link detectFinalizeAction}: the index, proposal_id, and
|
|
115
|
+
* optional ask of the first finalize-action refine entry.
|
|
116
|
+
*
|
|
117
|
+
* @public
|
|
118
|
+
*/
|
|
119
|
+
export interface FinalizeActionRef {
|
|
120
|
+
index: number;
|
|
121
|
+
proposalId: string;
|
|
122
|
+
ask?: string;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Return the first finalize-action refine entry from a
|
|
126
|
+
* `GetProductsRequest`, or `null` if no finalize entry exists.
|
|
127
|
+
*
|
|
128
|
+
* The index points at the entry's position in `refine[]` so the framework
|
|
129
|
+
* can produce indexed wire field paths (`refine[3].proposal_id`) on
|
|
130
|
+
* rejection — buyers parsing the error get a precise pointer.
|
|
131
|
+
*
|
|
132
|
+
* Per the spec, `buying_mode: 'refine'` carries a `refine[]` array of
|
|
133
|
+
* entries. Each entry has a `scope` (`request` / `product` / `proposal`)
|
|
134
|
+
* and an optional `action` (`include` / `omit` / `finalize`). v1.5 only
|
|
135
|
+
* intercepts `proposal`-scoped entries with `action: 'finalize'`.
|
|
136
|
+
*
|
|
137
|
+
* The framework processes ONE finalize entry per request; if the buyer
|
|
138
|
+
* sends multiple finalize entries, only the first is processed (rest fall
|
|
139
|
+
* through to the standard refine path).
|
|
140
|
+
*
|
|
141
|
+
* @public
|
|
142
|
+
*/
|
|
143
|
+
export declare function detectFinalizeAction(req: GetProductsRequest): FinalizeActionRef | null;
|
|
144
|
+
/**
|
|
145
|
+
* Logger-shaped sink for structured proposal-lifecycle events. Defaults to
|
|
146
|
+
* `console.info`-style emission; the dispatch path can pass a typed logger
|
|
147
|
+
* to route through the rest of the framework's logging.
|
|
148
|
+
*
|
|
149
|
+
* @public
|
|
150
|
+
*/
|
|
151
|
+
export interface ProposalLifecycleLogger {
|
|
152
|
+
info(message: string, fields?: Record<string, unknown>): void;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Replace the module-level logger that proposal-lifecycle structured
|
|
156
|
+
* events (`proposal.draft_persisted`, `proposal.finalized`, `proposal.expired`,
|
|
157
|
+
* `proposal.consumed`) emit through. Adopters wire this to their existing
|
|
158
|
+
* logger (pino, bunyan, etc.) so lifecycle events route through the same
|
|
159
|
+
* pipeline as the rest of their server logs. Tests use it to capture
|
|
160
|
+
* structured emissions for assertion.
|
|
161
|
+
*
|
|
162
|
+
* @public
|
|
163
|
+
*/
|
|
164
|
+
export declare function setProposalLifecycleLogger(next: ProposalLifecycleLogger): void;
|
|
165
|
+
/** `proposal.draft_persisted` event. */
|
|
166
|
+
export declare function logDraftPersisted(args: {
|
|
167
|
+
proposalId: string;
|
|
168
|
+
accountId: string;
|
|
169
|
+
recipesCount: number;
|
|
170
|
+
}): void;
|
|
171
|
+
/**
|
|
172
|
+
* `proposal.finalized` event. `path` is `'inline'` or `'handoff'`.
|
|
173
|
+
*/
|
|
174
|
+
export declare function logFinalizeSucceeded(args: {
|
|
175
|
+
proposalId: string;
|
|
176
|
+
accountId: string;
|
|
177
|
+
expiresAt: Date;
|
|
178
|
+
path: 'inline' | 'handoff';
|
|
179
|
+
}): void;
|
|
180
|
+
/** `proposal.expired` event. */
|
|
181
|
+
export declare function logExpired(args: {
|
|
182
|
+
proposalId: string;
|
|
183
|
+
accountId: string;
|
|
184
|
+
now: Date;
|
|
185
|
+
expiresAt: Date;
|
|
186
|
+
graceSeconds: number;
|
|
187
|
+
}): void;
|
|
188
|
+
/** `proposal.consumed` event. */
|
|
189
|
+
export declare function logConsumed(args: {
|
|
190
|
+
proposalId: string;
|
|
191
|
+
accountId: string;
|
|
192
|
+
mediaBuyId: string;
|
|
193
|
+
}): void;
|
|
194
|
+
export {};
|
|
195
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../../../../src/lib/server/decisioning/proposal/lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Proposal-lifecycle framework helpers — the v1.5 intercept seam.
|
|
4
|
+
*
|
|
5
|
+
* Sits parallel to existing dispatch helpers in `runtime/from-platform.ts`.
|
|
6
|
+
* Framework intercepts at a seam, does its work, dispatches.
|
|
7
|
+
*
|
|
8
|
+
* Public surface (the dispatch path imports these):
|
|
9
|
+
*
|
|
10
|
+
* - {@link enforceProposalExpiry} — D7. Look up the committed proposal,
|
|
11
|
+
* validate `state === 'committed'` and `now <= expires_at + grace`,
|
|
12
|
+
* return the record.
|
|
13
|
+
* - {@link validateCapabilityOverlap} — D4. Walk a buyer's
|
|
14
|
+
* `create_media_buy` / `update_media_buy` request packages against
|
|
15
|
+
* each recipe's `capability_overlap` and reject mismatches with
|
|
16
|
+
* `INVALID_REQUEST`.
|
|
17
|
+
* - {@link validateOverlapSubsetOfWire} — D4 round-4. Validate at
|
|
18
|
+
* `putDraft` time that each recipe's `capability_overlap` axis is a
|
|
19
|
+
* subset of the corresponding wire-declared product capabilities.
|
|
20
|
+
* Mismatches throw `INTERNAL_ERROR` (adopter bug, not buyer bug).
|
|
21
|
+
* - {@link detectFinalizeAction} — pull out the first finalize-action
|
|
22
|
+
* refine entry from a `GetProductsRequest`.
|
|
23
|
+
* - structured-log helpers per § Observability.
|
|
24
|
+
*
|
|
25
|
+
* Ports `adcp-client-python.src/adcp/decisioning/proposal_lifecycle.py`.
|
|
26
|
+
*
|
|
27
|
+
* @public
|
|
28
|
+
* @packageDocumentation
|
|
29
|
+
*/
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.enforceProposalExpiry = enforceProposalExpiry;
|
|
32
|
+
exports.validateCapabilityOverlap = validateCapabilityOverlap;
|
|
33
|
+
exports.validateOverlapSubsetOfWire = validateOverlapSubsetOfWire;
|
|
34
|
+
exports.detectFinalizeAction = detectFinalizeAction;
|
|
35
|
+
exports.setProposalLifecycleLogger = setProposalLifecycleLogger;
|
|
36
|
+
exports.logDraftPersisted = logDraftPersisted;
|
|
37
|
+
exports.logFinalizeSucceeded = logFinalizeSucceeded;
|
|
38
|
+
exports.logExpired = logExpired;
|
|
39
|
+
exports.logConsumed = logConsumed;
|
|
40
|
+
const async_outcome_1 = require("../async-outcome");
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// D7 — expires_at enforcement
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
/**
|
|
45
|
+
* Validate a proposal is committed and within its hold window.
|
|
46
|
+
*
|
|
47
|
+
* Three failure modes mapped to spec error codes:
|
|
48
|
+
*
|
|
49
|
+
* - Record not found OR cross-tenant → `PROPOSAL_NOT_FOUND` (terminal).
|
|
50
|
+
* Cross-tenant probes return the same error as missing IDs (no
|
|
51
|
+
* principal-enumeration via id probing).
|
|
52
|
+
* - State !== `'committed'` → `PROPOSAL_NOT_COMMITTED` (correctable).
|
|
53
|
+
* The buyer needs to call `getProducts({ buying_mode: 'refine',
|
|
54
|
+
* refine: [{ action: 'finalize' }] })` first.
|
|
55
|
+
* - Committed but `now > expires_at + grace` → `PROPOSAL_EXPIRED`
|
|
56
|
+
* (correctable per AdCP 3.0.6 — the buyer re-discovers via
|
|
57
|
+
* `get_products` to obtain a fresh proposal).
|
|
58
|
+
*
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
async function enforceProposalExpiry(proposalId, args) {
|
|
62
|
+
const { proposalStore, expectedAccountId, graceSeconds = 0, now } = args;
|
|
63
|
+
const record = await proposalStore.get(proposalId, { expectedAccountId });
|
|
64
|
+
if (!record) {
|
|
65
|
+
throw new async_outcome_1.AdcpError('PROPOSAL_NOT_FOUND', {
|
|
66
|
+
recovery: 'terminal',
|
|
67
|
+
message: `Proposal ${JSON.stringify(proposalId)} not found. The buyer must call get_products ` +
|
|
68
|
+
`with buying_mode='refine' and refine=[{action:'finalize',...}] to obtain a ` +
|
|
69
|
+
`committed proposal_id before referencing it on create_media_buy.`,
|
|
70
|
+
field: 'proposal_id',
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
if (record.state !== 'committed') {
|
|
74
|
+
throw new async_outcome_1.AdcpError('PROPOSAL_NOT_COMMITTED', {
|
|
75
|
+
recovery: 'correctable',
|
|
76
|
+
message: `Proposal ${JSON.stringify(proposalId)} is in state ${JSON.stringify(record.state)}; ` +
|
|
77
|
+
`only committed proposals can be accepted via create_media_buy. Call get_products ` +
|
|
78
|
+
`with buying_mode='refine' and action='finalize' first.`,
|
|
79
|
+
field: 'proposal_id',
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
if (record.expiresAt) {
|
|
83
|
+
const current = now ?? new Date();
|
|
84
|
+
const deadline = record.expiresAt.getTime() + graceSeconds * 1000;
|
|
85
|
+
if (current.getTime() > deadline) {
|
|
86
|
+
logExpired({
|
|
87
|
+
proposalId,
|
|
88
|
+
accountId: record.accountId,
|
|
89
|
+
now: current,
|
|
90
|
+
expiresAt: record.expiresAt,
|
|
91
|
+
graceSeconds,
|
|
92
|
+
});
|
|
93
|
+
throw new async_outcome_1.AdcpError('PROPOSAL_EXPIRED', {
|
|
94
|
+
// Per AdCP 3.0.6 schemas/cache/3.0.6/enums/error-code.json,
|
|
95
|
+
// PROPOSAL_EXPIRED is `correctable` — the buyer re-discovers
|
|
96
|
+
// via `get_products` to obtain a fresh proposal (the hold
|
|
97
|
+
// window has lapsed but the buyer can re-request).
|
|
98
|
+
recovery: 'correctable',
|
|
99
|
+
message: `Proposal ${JSON.stringify(proposalId)} expired at ${record.expiresAt.toISOString()}; ` +
|
|
100
|
+
`create_media_buy must be called within the inventory hold window. Call get_products ` +
|
|
101
|
+
`with buying_mode='refine' and action='finalize' to request a fresh hold.`,
|
|
102
|
+
field: 'proposal_id',
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return record;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Pre-adapter validation seam: walk buyer's packages against each recipe's
|
|
110
|
+
* `capability_overlap` and reject mismatches.
|
|
111
|
+
*
|
|
112
|
+
* Called from the framework's `create_media_buy` and `update_media_buy`
|
|
113
|
+
* dispatch paths after recipes are hydrated from the {@link ProposalStore}.
|
|
114
|
+
* Per D4, the framework owns this gate so every adopter doesn't write the
|
|
115
|
+
* same intersection logic.
|
|
116
|
+
*
|
|
117
|
+
* Validation axes (per {@link CapabilityOverlap}):
|
|
118
|
+
*
|
|
119
|
+
* - `pricingModels` — checked against `package._resolved_pricing_model`
|
|
120
|
+
* or `package.pricing_model`.
|
|
121
|
+
* - `targetingDimensions` — checked against `package.targeting_overlay` keys.
|
|
122
|
+
* - `deliveryTypes` — checked against `package._resolved_delivery_type`
|
|
123
|
+
* or `package.delivery_type`.
|
|
124
|
+
* - `signalTypes` — checked against `package.signal_type`.
|
|
125
|
+
*
|
|
126
|
+
* Per the design's undefined-vs-empty-set semantics: `undefined` skips the
|
|
127
|
+
* gate; an explicit `Set` (including the empty set) is enforced.
|
|
128
|
+
*
|
|
129
|
+
* @public
|
|
130
|
+
*/
|
|
131
|
+
function validateCapabilityOverlap(args) {
|
|
132
|
+
const { packages, recipes, fieldPathPrefix = 'packages' } = args;
|
|
133
|
+
for (let i = 0; i < packages.length; i++) {
|
|
134
|
+
const pkg = packages[i];
|
|
135
|
+
const productId = pkg.product_id;
|
|
136
|
+
if (!productId)
|
|
137
|
+
continue;
|
|
138
|
+
const recipe = recipes.get(productId);
|
|
139
|
+
if (!recipe || !recipe.capability_overlap)
|
|
140
|
+
continue;
|
|
141
|
+
const overlap = recipe.capability_overlap;
|
|
142
|
+
if (overlap.pricingModels) {
|
|
143
|
+
const requested = pkg._resolved_pricing_model ?? pkg.pricing_model;
|
|
144
|
+
if (requested !== undefined && !overlap.pricingModels.has(String(requested))) {
|
|
145
|
+
throw new async_outcome_1.AdcpError('INVALID_REQUEST', {
|
|
146
|
+
recovery: 'terminal',
|
|
147
|
+
message: `Buyer requested pricing_model=${JSON.stringify(requested)} on package ` +
|
|
148
|
+
`${JSON.stringify(productId)}, but this product's recipe declares ` +
|
|
149
|
+
`capability_overlap.pricingModels=${JSON.stringify([...overlap.pricingModels].sort())}. ` +
|
|
150
|
+
`The seller did not enable that pricing model for this product.`,
|
|
151
|
+
field: `${fieldPathPrefix}[${i}].pricing_option_id`,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (overlap.targetingDimensions) {
|
|
156
|
+
const overlay = pkg.targeting_overlay;
|
|
157
|
+
const keys = overlay && typeof overlay === 'object' ? Object.keys(overlay) : [];
|
|
158
|
+
const disallowed = keys.filter(k => !overlap.targetingDimensions.has(k));
|
|
159
|
+
if (disallowed.length > 0) {
|
|
160
|
+
throw new async_outcome_1.AdcpError('INVALID_REQUEST', {
|
|
161
|
+
recovery: 'terminal',
|
|
162
|
+
message: `Buyer requested targeting dimensions ${JSON.stringify(disallowed.sort())} on ` +
|
|
163
|
+
`package ${JSON.stringify(productId)}, but this product's recipe declares ` +
|
|
164
|
+
`capability_overlap.targetingDimensions=` +
|
|
165
|
+
`${JSON.stringify([...overlap.targetingDimensions].sort())}. The seller did not ` +
|
|
166
|
+
`enable those targeting dimensions for this product.`,
|
|
167
|
+
field: `${fieldPathPrefix}[${i}].targeting_overlay`,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (overlap.deliveryTypes) {
|
|
172
|
+
const delivery = pkg._resolved_delivery_type ?? pkg.delivery_type;
|
|
173
|
+
if (delivery !== undefined && !overlap.deliveryTypes.has(String(delivery))) {
|
|
174
|
+
throw new async_outcome_1.AdcpError('INVALID_REQUEST', {
|
|
175
|
+
recovery: 'terminal',
|
|
176
|
+
message: `Buyer requested delivery_type=${JSON.stringify(delivery)} on package ` +
|
|
177
|
+
`${JSON.stringify(productId)}, but this product's recipe declares ` +
|
|
178
|
+
`capability_overlap.deliveryTypes=${JSON.stringify([...overlap.deliveryTypes].sort())}.`,
|
|
179
|
+
field: `${fieldPathPrefix}[${i}].delivery_type`,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (overlap.signalTypes) {
|
|
184
|
+
const signalType = pkg.signal_type;
|
|
185
|
+
if (signalType !== undefined && !overlap.signalTypes.has(String(signalType))) {
|
|
186
|
+
throw new async_outcome_1.AdcpError('INVALID_REQUEST', {
|
|
187
|
+
recovery: 'terminal',
|
|
188
|
+
message: `Buyer requested signal_type=${JSON.stringify(signalType)} on package ` +
|
|
189
|
+
`${JSON.stringify(productId)}, but this product's recipe declares ` +
|
|
190
|
+
`capability_overlap.signalTypes=${JSON.stringify([...overlap.signalTypes].sort())}.`,
|
|
191
|
+
field: `${fieldPathPrefix}[${i}].signal_type`,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Validate `recipe.capability_overlap` is a subset of the matching product's
|
|
199
|
+
* wire-declared capabilities.
|
|
200
|
+
*
|
|
201
|
+
* Called at `putDraft` time. Mismatches throw `INTERNAL_ERROR` — this is
|
|
202
|
+
* an adopter bug (the manager declared an overlap claiming capabilities the
|
|
203
|
+
* wire shape doesn't advertise), not a buyer bug.
|
|
204
|
+
*
|
|
205
|
+
* @public
|
|
206
|
+
*/
|
|
207
|
+
function validateOverlapSubsetOfWire(args) {
|
|
208
|
+
const productsById = new Map();
|
|
209
|
+
for (const p of args.products) {
|
|
210
|
+
if (p.product_id)
|
|
211
|
+
productsById.set(p.product_id, p);
|
|
212
|
+
}
|
|
213
|
+
for (const [productId, recipe] of args.recipes) {
|
|
214
|
+
if (!recipe.capability_overlap)
|
|
215
|
+
continue;
|
|
216
|
+
const product = productsById.get(productId);
|
|
217
|
+
if (!product)
|
|
218
|
+
continue; // missing-product is caught elsewhere
|
|
219
|
+
const overlap = recipe.capability_overlap;
|
|
220
|
+
if (overlap.pricingModels) {
|
|
221
|
+
const wirePricing = wirePricingModels(product);
|
|
222
|
+
const extras = [...overlap.pricingModels].filter(p => !wirePricing.has(p));
|
|
223
|
+
if (extras.length > 0) {
|
|
224
|
+
throw new async_outcome_1.AdcpError('INTERNAL_ERROR', {
|
|
225
|
+
recovery: 'terminal',
|
|
226
|
+
message: `Recipe for product ${JSON.stringify(productId)} declares ` +
|
|
227
|
+
`capability_overlap.pricingModels=${JSON.stringify([...overlap.pricingModels].sort())} ` +
|
|
228
|
+
`including ${JSON.stringify(extras.sort())}, but the wire product only advertises ` +
|
|
229
|
+
`${JSON.stringify([...wirePricing].sort())}. The recipe's overlap must be a subset ` +
|
|
230
|
+
`of the wire-declared capabilities; adopter declaration is inconsistent with the ` +
|
|
231
|
+
`product shape.`,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (overlap.deliveryTypes) {
|
|
236
|
+
const wireDelivery = wireDeliveryTypes(product);
|
|
237
|
+
const extras = [...overlap.deliveryTypes].filter(p => !wireDelivery.has(p));
|
|
238
|
+
// Only enforce when the wire declares something — products lacking a
|
|
239
|
+
// delivery_type field shouldn't trip the gate.
|
|
240
|
+
if (extras.length > 0 && wireDelivery.size > 0) {
|
|
241
|
+
throw new async_outcome_1.AdcpError('INTERNAL_ERROR', {
|
|
242
|
+
recovery: 'terminal',
|
|
243
|
+
message: `Recipe for product ${JSON.stringify(productId)} declares ` +
|
|
244
|
+
`capability_overlap.deliveryTypes=${JSON.stringify([...overlap.deliveryTypes].sort())} ` +
|
|
245
|
+
`including ${JSON.stringify(extras.sort())}, but the wire product only advertises ` +
|
|
246
|
+
`${JSON.stringify([...wireDelivery].sort())}.`,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function wirePricingModels(product) {
|
|
253
|
+
const out = new Set();
|
|
254
|
+
const pricing = product.pricing_options;
|
|
255
|
+
if (!pricing)
|
|
256
|
+
return out;
|
|
257
|
+
for (const opt of pricing) {
|
|
258
|
+
if (opt.pricing_model)
|
|
259
|
+
out.add(String(opt.pricing_model));
|
|
260
|
+
}
|
|
261
|
+
return out;
|
|
262
|
+
}
|
|
263
|
+
function wireDeliveryTypes(product) {
|
|
264
|
+
const dt = product.delivery_type;
|
|
265
|
+
return dt ? new Set([String(dt)]) : new Set();
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Return the first finalize-action refine entry from a
|
|
269
|
+
* `GetProductsRequest`, or `null` if no finalize entry exists.
|
|
270
|
+
*
|
|
271
|
+
* The index points at the entry's position in `refine[]` so the framework
|
|
272
|
+
* can produce indexed wire field paths (`refine[3].proposal_id`) on
|
|
273
|
+
* rejection — buyers parsing the error get a precise pointer.
|
|
274
|
+
*
|
|
275
|
+
* Per the spec, `buying_mode: 'refine'` carries a `refine[]` array of
|
|
276
|
+
* entries. Each entry has a `scope` (`request` / `product` / `proposal`)
|
|
277
|
+
* and an optional `action` (`include` / `omit` / `finalize`). v1.5 only
|
|
278
|
+
* intercepts `proposal`-scoped entries with `action: 'finalize'`.
|
|
279
|
+
*
|
|
280
|
+
* The framework processes ONE finalize entry per request; if the buyer
|
|
281
|
+
* sends multiple finalize entries, only the first is processed (rest fall
|
|
282
|
+
* through to the standard refine path).
|
|
283
|
+
*
|
|
284
|
+
* @public
|
|
285
|
+
*/
|
|
286
|
+
function detectFinalizeAction(req) {
|
|
287
|
+
const refine = req.refine;
|
|
288
|
+
if (!refine || refine.length === 0)
|
|
289
|
+
return null;
|
|
290
|
+
for (let index = 0; index < refine.length; index++) {
|
|
291
|
+
const entry = refine[index];
|
|
292
|
+
if (entry.scope === 'proposal' && entry.action === 'finalize') {
|
|
293
|
+
const proposalId = entry.proposal_id;
|
|
294
|
+
if (typeof proposalId === 'string' && proposalId.length > 0) {
|
|
295
|
+
const ask = typeof entry.ask === 'string' ? entry.ask : undefined;
|
|
296
|
+
return ask !== undefined ? { index, proposalId, ask } : { index, proposalId };
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
let logger = {
|
|
303
|
+
info: (message, fields) => {
|
|
304
|
+
if (fields) {
|
|
305
|
+
console.log(JSON.stringify({ message, ...fields }));
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
console.log(message);
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
/**
|
|
313
|
+
* Replace the module-level logger that proposal-lifecycle structured
|
|
314
|
+
* events (`proposal.draft_persisted`, `proposal.finalized`, `proposal.expired`,
|
|
315
|
+
* `proposal.consumed`) emit through. Adopters wire this to their existing
|
|
316
|
+
* logger (pino, bunyan, etc.) so lifecycle events route through the same
|
|
317
|
+
* pipeline as the rest of their server logs. Tests use it to capture
|
|
318
|
+
* structured emissions for assertion.
|
|
319
|
+
*
|
|
320
|
+
* @public
|
|
321
|
+
*/
|
|
322
|
+
function setProposalLifecycleLogger(next) {
|
|
323
|
+
logger = next;
|
|
324
|
+
}
|
|
325
|
+
/** `proposal.draft_persisted` event. */
|
|
326
|
+
function logDraftPersisted(args) {
|
|
327
|
+
logger.info('proposal.draft_persisted', {
|
|
328
|
+
event: 'proposal.draft_persisted',
|
|
329
|
+
proposal_id: args.proposalId,
|
|
330
|
+
account_id: args.accountId,
|
|
331
|
+
recipes_count: args.recipesCount,
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* `proposal.finalized` event. `path` is `'inline'` or `'handoff'`.
|
|
336
|
+
*/
|
|
337
|
+
function logFinalizeSucceeded(args) {
|
|
338
|
+
logger.info('proposal.finalized', {
|
|
339
|
+
event: 'proposal.finalized',
|
|
340
|
+
proposal_id: args.proposalId,
|
|
341
|
+
account_id: args.accountId,
|
|
342
|
+
expires_at: args.expiresAt.toISOString(),
|
|
343
|
+
path: args.path,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
/** `proposal.expired` event. */
|
|
347
|
+
function logExpired(args) {
|
|
348
|
+
logger.info('proposal.expired', {
|
|
349
|
+
event: 'proposal.expired',
|
|
350
|
+
proposal_id: args.proposalId,
|
|
351
|
+
account_id: args.accountId,
|
|
352
|
+
now: args.now.toISOString(),
|
|
353
|
+
expires_at: args.expiresAt.toISOString(),
|
|
354
|
+
grace_seconds: args.graceSeconds,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
/** `proposal.consumed` event. */
|
|
358
|
+
function logConsumed(args) {
|
|
359
|
+
logger.info('proposal.consumed', {
|
|
360
|
+
event: 'proposal.consumed',
|
|
361
|
+
proposal_id: args.proposalId,
|
|
362
|
+
account_id: args.accountId,
|
|
363
|
+
media_buy_id: args.mediaBuyId,
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../../../src/lib/server/decisioning/proposal/lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MockProposalManager — v1 default forwarder.
|
|
3
|
+
*
|
|
4
|
+
* Symmetric with the mock-mode dispatch pattern adopters use to point
|
|
5
|
+
* `DecisioningPlatform` upstreams at a running `bin/adcp.js mock-server`.
|
|
6
|
+
* Adopters who don't yet have proposal logic of their own start with this
|
|
7
|
+
* class pointed at the appropriate mock-server specialism; their first
|
|
8
|
+
* working seller agent runs against the mock fixtures with zero adopter
|
|
9
|
+
* code on the proposal side. They implement their own
|
|
10
|
+
* {@link ProposalManager} subtype incrementally as they replace
|
|
11
|
+
* mock-served slices with real assembly logic.
|
|
12
|
+
*
|
|
13
|
+
* The mock-server lifecycle is **not** managed by the SDK. Adopters or CI
|
|
14
|
+
* start it as needed (`bin/adcp.js mock-server sales-non-guaranteed`) and
|
|
15
|
+
* pass the resulting URL to this class's constructor.
|
|
16
|
+
*
|
|
17
|
+
* Ports `adcp-client-python.src/adcp/decisioning/proposal_manager.py`'s
|
|
18
|
+
* `MockProposalManager` (PR #504).
|
|
19
|
+
*
|
|
20
|
+
* **Runtime requirement**: uses `globalThis.fetch`, which lands as a built-in
|
|
21
|
+
* on Node 18+ (the package declares `"engines": { "node": ">=18.0.0" }`).
|
|
22
|
+
* Adopters running on older Node, on Bun without the global, or in any
|
|
23
|
+
* environment without a global `fetch` should pass an explicit `fetch`
|
|
24
|
+
* implementation via the `fetch` constructor option.
|
|
25
|
+
*
|
|
26
|
+
* @public
|
|
27
|
+
* @packageDocumentation
|
|
28
|
+
*/
|
|
29
|
+
import type { Account } from '../account';
|
|
30
|
+
import type { RequestContext } from '../context';
|
|
31
|
+
import type { GetProductsRequest, GetProductsResponse } from '../../../types/tools.generated';
|
|
32
|
+
import type { ProposalCapabilities, ProposalManager, ProposalSalesSpecialism, Recipe } from './types';
|
|
33
|
+
/**
|
|
34
|
+
* Construction options for {@link MockProposalManager}.
|
|
35
|
+
*
|
|
36
|
+
* @public
|
|
37
|
+
*/
|
|
38
|
+
export interface MockProposalManagerOptions {
|
|
39
|
+
/**
|
|
40
|
+
* URL of the running mock-server. The forwarder POSTs
|
|
41
|
+
* `GetProductsRequest` payloads to `${mockUpstreamUrl}/get_products`
|
|
42
|
+
* and (when refine is enabled) `${mockUpstreamUrl}/refine_products`.
|
|
43
|
+
*
|
|
44
|
+
* Required and non-empty.
|
|
45
|
+
*/
|
|
46
|
+
mockUpstreamUrl: string;
|
|
47
|
+
/**
|
|
48
|
+
* Which sales specialism this mock manager serves. Defaults to
|
|
49
|
+
* `sales-non-guaranteed` (the catalog-style mock-server fixture).
|
|
50
|
+
* Adopters wiring a guaranteed mock pass `sales-guaranteed` so the
|
|
51
|
+
* framework's capability projection matches the fixtures.
|
|
52
|
+
*/
|
|
53
|
+
salesSpecialism?: ProposalSalesSpecialism;
|
|
54
|
+
/**
|
|
55
|
+
* When true, the manager declares `refine` capability and forwards
|
|
56
|
+
* `buying_mode: 'refine'` requests to `/refine_products`. Default
|
|
57
|
+
* false — the framework falls through to `getProducts` for refine.
|
|
58
|
+
*/
|
|
59
|
+
refine?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Headers forwarded on every mock-server request (e.g. `X-Tenant-Id`).
|
|
62
|
+
*/
|
|
63
|
+
defaultHeaders?: Readonly<Record<string, string>>;
|
|
64
|
+
/**
|
|
65
|
+
* Per-request timeout in milliseconds. Default 30 seconds.
|
|
66
|
+
*/
|
|
67
|
+
timeoutMs?: number;
|
|
68
|
+
/**
|
|
69
|
+
* Optional `fetch` override for testing. Defaults to the global
|
|
70
|
+
* `fetch` (Node 18+).
|
|
71
|
+
*/
|
|
72
|
+
fetch?: typeof globalThis.fetch;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* v1 default forwarder. Dispatches `getProducts` / `refineProducts` to
|
|
76
|
+
* a running mock-server.
|
|
77
|
+
*
|
|
78
|
+
* @public
|
|
79
|
+
*/
|
|
80
|
+
export declare class MockProposalManager<TRecipe extends Recipe = Recipe, TCtxMeta = unknown> implements ProposalManager<TRecipe, TCtxMeta> {
|
|
81
|
+
readonly capabilities: ProposalCapabilities;
|
|
82
|
+
private readonly url;
|
|
83
|
+
private readonly headers;
|
|
84
|
+
private readonly timeoutMs;
|
|
85
|
+
private readonly fetchImpl;
|
|
86
|
+
constructor(options: MockProposalManagerOptions);
|
|
87
|
+
/** The configured mock-server URL — useful for diagnostics. */
|
|
88
|
+
get mockUpstreamUrl(): string;
|
|
89
|
+
getProducts(req: GetProductsRequest, _ctx: RequestContext<Account<TCtxMeta>>): Promise<GetProductsResponse>;
|
|
90
|
+
refineProducts(req: GetProductsRequest, _ctx: RequestContext<Account<TCtxMeta>>): Promise<GetProductsResponse>;
|
|
91
|
+
private forward;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=mock-manager.d.ts.map
|