@adcp/sdk 6.10.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/async-outcome.d.ts +17 -0
- package/dist/lib/server/decisioning/async-outcome.d.ts.map +1 -1
- package/dist/lib/server/decisioning/async-outcome.js +23 -18
- package/dist/lib/server/decisioning/async-outcome.js.map +1 -1
- package/dist/lib/server/decisioning/context.d.ts +27 -2
- package/dist/lib/server/decisioning/context.d.ts.map +1 -1
- package/dist/lib/server/decisioning/index.d.ts +4 -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 +204 -19
- package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.js +5 -2
- package/dist/lib/server/decisioning/runtime/postgres-task-registry.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/task-registry.d.ts +5 -0
- package/dist/lib/server/decisioning/runtime/task-registry.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/task-registry.js +4 -1
- package/dist/lib/server/decisioning/runtime/task-registry.js.map +1 -1
- package/dist/lib/server/decisioning/runtime/to-context.d.ts.map +1 -1
- package/dist/lib/server/decisioning/runtime/to-context.js +10 -2
- package/dist/lib/server/decisioning/runtime/to-context.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/server/test-controller.d.ts +2 -0
- package/dist/lib/server/test-controller.d.ts.map +1 -1
- package/dist/lib/server/test-controller.js +6 -11
- package/dist/lib/server/test-controller.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/comply-controller.d.ts +2 -0
- package/dist/lib/testing/comply-controller.d.ts.map +1 -1
- package/dist/lib/testing/comply-controller.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,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ProposalManager — primitives for the two-platform composition.
|
|
4
|
+
*
|
|
5
|
+
* Splits proposal assembly (`get_products`, refine, finalize) from media-buy
|
|
6
|
+
* execution (`create_media_buy`, lifecycle), mirroring `adcp-client-python`'s
|
|
7
|
+
* v1.5 ProposalManager. Either side can be mock-backed independently.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
* @packageDocumentation
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.maybeHydrateRecipesForMediaBuyId = exports.releaseProposalReservation = exports.finalizeProposalConsumption = exports.maybeReserveProposalForCreateMediaBuy = exports.maybePersistDraftAfterGetProducts = exports.maybeInterceptFinalize = exports.logConsumed = exports.logExpired = exports.logFinalizeSucceeded = exports.logDraftPersisted = exports.setProposalLifecycleLogger = exports.detectFinalizeAction = exports.validateOverlapSubsetOfWire = exports.validateCapabilityOverlap = exports.enforceProposalExpiry = exports.MockProposalManager = exports.InMemoryProposalStore = exports.validateProposalCapabilities = void 0;
|
|
14
|
+
var types_1 = require("./types");
|
|
15
|
+
Object.defineProperty(exports, "validateProposalCapabilities", { enumerable: true, get: function () { return types_1.validateProposalCapabilities; } });
|
|
16
|
+
var store_1 = require("./store");
|
|
17
|
+
Object.defineProperty(exports, "InMemoryProposalStore", { enumerable: true, get: function () { return store_1.InMemoryProposalStore; } });
|
|
18
|
+
var mock_manager_1 = require("./mock-manager");
|
|
19
|
+
Object.defineProperty(exports, "MockProposalManager", { enumerable: true, get: function () { return mock_manager_1.MockProposalManager; } });
|
|
20
|
+
var lifecycle_1 = require("./lifecycle");
|
|
21
|
+
Object.defineProperty(exports, "enforceProposalExpiry", { enumerable: true, get: function () { return lifecycle_1.enforceProposalExpiry; } });
|
|
22
|
+
Object.defineProperty(exports, "validateCapabilityOverlap", { enumerable: true, get: function () { return lifecycle_1.validateCapabilityOverlap; } });
|
|
23
|
+
Object.defineProperty(exports, "validateOverlapSubsetOfWire", { enumerable: true, get: function () { return lifecycle_1.validateOverlapSubsetOfWire; } });
|
|
24
|
+
Object.defineProperty(exports, "detectFinalizeAction", { enumerable: true, get: function () { return lifecycle_1.detectFinalizeAction; } });
|
|
25
|
+
Object.defineProperty(exports, "setProposalLifecycleLogger", { enumerable: true, get: function () { return lifecycle_1.setProposalLifecycleLogger; } });
|
|
26
|
+
Object.defineProperty(exports, "logDraftPersisted", { enumerable: true, get: function () { return lifecycle_1.logDraftPersisted; } });
|
|
27
|
+
Object.defineProperty(exports, "logFinalizeSucceeded", { enumerable: true, get: function () { return lifecycle_1.logFinalizeSucceeded; } });
|
|
28
|
+
Object.defineProperty(exports, "logExpired", { enumerable: true, get: function () { return lifecycle_1.logExpired; } });
|
|
29
|
+
Object.defineProperty(exports, "logConsumed", { enumerable: true, get: function () { return lifecycle_1.logConsumed; } });
|
|
30
|
+
var dispatch_1 = require("./dispatch");
|
|
31
|
+
Object.defineProperty(exports, "maybeInterceptFinalize", { enumerable: true, get: function () { return dispatch_1.maybeInterceptFinalize; } });
|
|
32
|
+
Object.defineProperty(exports, "maybePersistDraftAfterGetProducts", { enumerable: true, get: function () { return dispatch_1.maybePersistDraftAfterGetProducts; } });
|
|
33
|
+
Object.defineProperty(exports, "maybeReserveProposalForCreateMediaBuy", { enumerable: true, get: function () { return dispatch_1.maybeReserveProposalForCreateMediaBuy; } });
|
|
34
|
+
Object.defineProperty(exports, "finalizeProposalConsumption", { enumerable: true, get: function () { return dispatch_1.finalizeProposalConsumption; } });
|
|
35
|
+
Object.defineProperty(exports, "releaseProposalReservation", { enumerable: true, get: function () { return dispatch_1.releaseProposalReservation; } });
|
|
36
|
+
Object.defineProperty(exports, "maybeHydrateRecipesForMediaBuyId", { enumerable: true, get: function () { return dispatch_1.maybeHydrateRecipesForMediaBuyId; } });
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/lib/server/decisioning/proposal/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAYH,iCAAuD;AAA9C,qHAAA,4BAA4B,OAAA;AAIrC,iCAAgD;AAAvC,8GAAA,qBAAqB,OAAA;AAE9B,+CAAqD;AAA5C,mHAAA,mBAAmB,OAAA;AAG5B,yCAUqB;AATnB,kHAAA,qBAAqB,OAAA;AACrB,sHAAA,yBAAyB,OAAA;AACzB,wHAAA,2BAA2B,OAAA;AAC3B,iHAAA,oBAAoB,OAAA;AACpB,uHAAA,0BAA0B,OAAA;AAC1B,8GAAA,iBAAiB,OAAA;AACjB,iHAAA,oBAAoB,OAAA;AACpB,uGAAA,UAAU,OAAA;AACV,wGAAA,WAAW,OAAA;AAIb,uCAOoB;AANlB,kHAAA,sBAAsB,OAAA;AACtB,6HAAA,iCAAiC,OAAA;AACjC,iIAAA,qCAAqC,OAAA;AACrC,uHAAA,2BAA2B,OAAA;AAC3B,sHAAA,0BAA0B,OAAA;AAC1B,4HAAA,gCAAgC,OAAA"}
|
|
@@ -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":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;;AA4BH,sDAyDC;AA8CD,8DA2EC;AAYD,kEAgDC;AAoDD,oDAcC;AAqCD,gEAEC;AAGD,8CAOC;AAKD,oDAaC;AAGD,gCAeC;AAGD,kCAOC;AAzaD,oDAA6C;AAK7C,8EAA8E;AAC9E,8BAA8B;AAC9B,8EAA8E;AAE9E;;;;;;;;;;;;;;;;GAgBG;AACI,KAAK,UAAU,qBAAqB,CACzC,UAAkB,EAClB,IAKC;IAED,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,YAAY,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IACzE,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,iBAAiB,EAAE,CAAC,CAAC;IAC1E,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,yBAAS,CAAC,oBAAoB,EAAE;YACxC,QAAQ,EAAE,UAAU;YACpB,OAAO,EACL,YAAY,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,+CAA+C;gBACrF,6EAA6E;gBAC7E,kEAAkE;YACpE,KAAK,EAAE,aAAa;SACrB,CAAC,CAAC;IACL,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;QACjC,MAAM,IAAI,yBAAS,CAAC,wBAAwB,EAAE;YAC5C,QAAQ,EAAE,aAAa;YACvB,OAAO,EACL,YAAY,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,gBAAgB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI;gBACtF,mFAAmF;gBACnF,wDAAwD;YAC1D,KAAK,EAAE,aAAa;SACrB,CAAC,CAAC;IACL,CAAC;IACD,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,MAAM,OAAO,GAAG,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,YAAY,GAAG,IAAI,CAAC;QAClE,IAAI,OAAO,CAAC,OAAO,EAAE,GAAG,QAAQ,EAAE,CAAC;YACjC,UAAU,CAAC;gBACT,UAAU;gBACV,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,GAAG,EAAE,OAAO;gBACZ,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,YAAY;aACb,CAAC,CAAC;YACH,MAAM,IAAI,yBAAS,CAAC,kBAAkB,EAAE;gBACtC,4DAA4D;gBAC5D,6DAA6D;gBAC7D,0DAA0D;gBAC1D,mDAAmD;gBACnD,QAAQ,EAAE,aAAa;gBACvB,OAAO,EACL,YAAY,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,eAAe,MAAM,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI;oBACvF,sFAAsF;oBACtF,0EAA0E;gBAC5E,KAAK,EAAE,aAAa;aACrB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAuBD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,SAAgB,yBAAyB,CAAyB,IAIjE;IACC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC;IACjE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;QACzB,MAAM,SAAS,GAAG,GAAG,CAAC,UAAU,CAAC;QACjC,IAAI,CAAC,SAAS;YAAE,SAAS;QACzB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,kBAAkB;YAAE,SAAS;QACpD,MAAM,OAAO,GAAG,MAAM,CAAC,kBAAkB,CAAC;QAE1C,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,GAAG,CAAC,uBAAuB,IAAI,GAAG,CAAC,aAAa,CAAC;YACnE,IAAI,SAAS,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;gBAC7E,MAAM,IAAI,yBAAS,CAAC,iBAAiB,EAAE;oBACrC,QAAQ,EAAE,UAAU;oBACpB,OAAO,EACL,iCAAiC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,cAAc;wBACxE,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,uCAAuC;wBACnE,oCAAoC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI;wBACzF,gEAAgE;oBAClE,KAAK,EAAE,GAAG,eAAe,IAAI,CAAC,qBAAqB;iBACpD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,GAAG,CAAC,iBAAiB,CAAC;YACtC,MAAM,IAAI,GAAG,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAChF,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,mBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1E,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,MAAM,IAAI,yBAAS,CAAC,iBAAiB,EAAE;oBACrC,QAAQ,EAAE,UAAU;oBACpB,OAAO,EACL,wCAAwC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,MAAM;wBAC/E,WAAW,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,uCAAuC;wBAC3E,yCAAyC;wBACzC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC,IAAI,EAAE,CAAC,uBAAuB;wBACjF,qDAAqD;oBACvD,KAAK,EAAE,GAAG,eAAe,IAAI,CAAC,qBAAqB;iBACpD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,GAAG,CAAC,uBAAuB,IAAI,GAAG,CAAC,aAAa,CAAC;YAClE,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;gBAC3E,MAAM,IAAI,yBAAS,CAAC,iBAAiB,EAAE;oBACrC,QAAQ,EAAE,UAAU;oBACpB,OAAO,EACL,iCAAiC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,cAAc;wBACvE,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,uCAAuC;wBACnE,oCAAoC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG;oBAC1F,KAAK,EAAE,GAAG,eAAe,IAAI,CAAC,iBAAiB;iBAChD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YACxB,MAAM,UAAU,GAAG,GAAG,CAAC,WAAW,CAAC;YACnC,IAAI,UAAU,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;gBAC7E,MAAM,IAAI,yBAAS,CAAC,iBAAiB,EAAE;oBACrC,QAAQ,EAAE,UAAU;oBACpB,OAAO,EACL,+BAA+B,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,cAAc;wBACvE,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,uCAAuC;wBACnE,kCAAkC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG;oBACtF,KAAK,EAAE,GAAG,eAAe,IAAI,CAAC,eAAe;iBAC9C,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,2BAA2B,CAAyB,IAGnE;IACC,MAAM,YAAY,GAAG,IAAI,GAAG,EAAmB,CAAC;IAChD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC,CAAC,UAAU;YAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IACtD,CAAC;IACD,KAAK,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,kBAAkB;YAAE,SAAS;QACzC,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO;YAAE,SAAS,CAAC,sCAAsC;QAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,kBAAkB,CAAC;QAE1C,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;YAC1B,MAAM,WAAW,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;YAC/C,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3E,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,MAAM,IAAI,yBAAS,CAAC,gBAAgB,EAAE;oBACpC,QAAQ,EAAE,UAAU;oBACpB,OAAO,EACL,sBAAsB,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,YAAY;wBAC3D,oCAAoC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG;wBACxF,aAAa,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,yCAAyC;wBACnF,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,IAAI,EAAE,CAAC,0CAA0C;wBACpF,kFAAkF;wBAClF,gBAAgB;iBACnB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;YAC1B,MAAM,YAAY,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;YAChD,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5E,qEAAqE;YACrE,+CAA+C;YAC/C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,YAAY,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBAC/C,MAAM,IAAI,yBAAS,CAAC,gBAAgB,EAAE;oBACpC,QAAQ,EAAE,UAAU;oBACpB,OAAO,EACL,sBAAsB,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,YAAY;wBAC3D,oCAAoC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG;wBACxF,aAAa,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,yCAAyC;wBACnF,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG;iBACjD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAgB;IACzC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,MAAM,OAAO,GAAI,OAA2E,CAAC,eAAe,CAAC;IAC7G,IAAI,CAAC,OAAO;QAAE,OAAO,GAAG,CAAC;IACzB,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,IAAI,GAAG,CAAC,aAAa;YAAE,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAgB;IACzC,MAAM,EAAE,GAAI,OAAsC,CAAC,aAAa,CAAC;IACjE,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;AAChD,CAAC;AAkBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAgB,oBAAoB,CAAC,GAAuB;IAC1D,MAAM,MAAM,GAAI,GAA2D,CAAC,MAAM,CAAC;IACnF,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAChD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QACnD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAE,CAAC;QAC7B,IAAI,KAAK,CAAC,KAAK,KAAK,UAAU,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC9D,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,CAAC;YACrC,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5D,MAAM,GAAG,GAAG,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;gBAClE,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;YAChF,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAiBD,IAAI,MAAM,GAA4B;IACpC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxB,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC;QACtD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;CACF,CAAC;AAEF;;;;;;;;;GASG;AACH,SAAgB,0BAA0B,CAAC,IAA6B;IACtE,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC;AAED,wCAAwC;AACxC,SAAgB,iBAAiB,CAAC,IAAqE;IACrG,MAAM,CAAC,IAAI,CAAC,0BAA0B,EAAE;QACtC,KAAK,EAAE,0BAA0B;QACjC,WAAW,EAAE,IAAI,CAAC,UAAU;QAC5B,UAAU,EAAE,IAAI,CAAC,SAAS;QAC1B,aAAa,EAAE,IAAI,CAAC,YAAY;KACjC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAgB,oBAAoB,CAAC,IAKpC;IACC,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE;QAChC,KAAK,EAAE,oBAAoB;QAC3B,WAAW,EAAE,IAAI,CAAC,UAAU;QAC5B,UAAU,EAAE,IAAI,CAAC,SAAS;QAC1B,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;QACxC,IAAI,EAAE,IAAI,CAAC,IAAI;KAChB,CAAC,CAAC;AACL,CAAC;AAED,gCAAgC;AAChC,SAAgB,UAAU,CAAC,IAM1B;IACC,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE;QAC9B,KAAK,EAAE,kBAAkB;QACzB,WAAW,EAAE,IAAI,CAAC,UAAU;QAC5B,UAAU,EAAE,IAAI,CAAC,SAAS;QAC1B,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE;QAC3B,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;QACxC,aAAa,EAAE,IAAI,CAAC,YAAY;KACjC,CAAC,CAAC;AACL,CAAC;AAED,iCAAiC;AACjC,SAAgB,WAAW,CAAC,IAAmE;IAC7F,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE;QAC/B,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE,IAAI,CAAC,UAAU;QAC5B,UAAU,EAAE,IAAI,CAAC,SAAS;QAC1B,YAAY,EAAE,IAAI,CAAC,UAAU;KAC9B,CAAC,CAAC;AACL,CAAC"}
|