@adcp/sdk 6.11.0 → 6.13.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/auth/oauth/index.d.ts +1 -0
- package/dist/lib/auth/oauth/index.d.ts.map +1 -1
- package/dist/lib/auth/oauth/index.js +17 -1
- package/dist/lib/auth/oauth/index.js.map +1 -1
- package/dist/lib/auth/oauth/web-flow.d.ts +270 -0
- package/dist/lib/auth/oauth/web-flow.d.ts.map +1 -0
- package/dist/lib/auth/oauth/web-flow.js +413 -0
- package/dist/lib/auth/oauth/web-flow.js.map +1 -0
- 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 @@
|
|
|
1
|
+
{"version":3,"file":"mock-manager.d.ts","sourceRoot":"","sources":["../../../../../src/lib/server/decisioning/proposal/mock-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAC9F,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtG;;;;GAIG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;;;;OAMG;IACH,eAAe,EAAE,MAAM,CAAC;IAExB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,uBAAuB,CAAC;IAE1C;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAElD;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED;;;;;GAKG;AACH,qBAAa,mBAAmB,CAAC,OAAO,SAAS,MAAM,GAAG,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAE,YAAW,eAAe,CAC9G,OAAO,EACP,QAAQ,CACT;IACC,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAC;IAC5C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0B;gBAExC,OAAO,EAAE,0BAA0B;IAsB/C,+DAA+D;IAC/D,IAAI,eAAe,IAAI,MAAM,CAE5B;IAEK,WAAW,CAAC,GAAG,EAAE,kBAAkB,EAAE,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAI3G,cAAc,CAAC,GAAG,EAAE,kBAAkB,EAAE,IAAI,EAAE,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;YAatG,OAAO;CA2BtB"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MockProposalManager — v1 default forwarder.
|
|
4
|
+
*
|
|
5
|
+
* Symmetric with the mock-mode dispatch pattern adopters use to point
|
|
6
|
+
* `DecisioningPlatform` upstreams at a running `bin/adcp.js mock-server`.
|
|
7
|
+
* Adopters who don't yet have proposal logic of their own start with this
|
|
8
|
+
* class pointed at the appropriate mock-server specialism; their first
|
|
9
|
+
* working seller agent runs against the mock fixtures with zero adopter
|
|
10
|
+
* code on the proposal side. They implement their own
|
|
11
|
+
* {@link ProposalManager} subtype incrementally as they replace
|
|
12
|
+
* mock-served slices with real assembly logic.
|
|
13
|
+
*
|
|
14
|
+
* The mock-server lifecycle is **not** managed by the SDK. Adopters or CI
|
|
15
|
+
* start it as needed (`bin/adcp.js mock-server sales-non-guaranteed`) and
|
|
16
|
+
* pass the resulting URL to this class's constructor.
|
|
17
|
+
*
|
|
18
|
+
* Ports `adcp-client-python.src/adcp/decisioning/proposal_manager.py`'s
|
|
19
|
+
* `MockProposalManager` (PR #504).
|
|
20
|
+
*
|
|
21
|
+
* **Runtime requirement**: uses `globalThis.fetch`, which lands as a built-in
|
|
22
|
+
* on Node 18+ (the package declares `"engines": { "node": ">=18.0.0" }`).
|
|
23
|
+
* Adopters running on older Node, on Bun without the global, or in any
|
|
24
|
+
* environment without a global `fetch` should pass an explicit `fetch`
|
|
25
|
+
* implementation via the `fetch` constructor option.
|
|
26
|
+
*
|
|
27
|
+
* @public
|
|
28
|
+
* @packageDocumentation
|
|
29
|
+
*/
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.MockProposalManager = void 0;
|
|
32
|
+
/**
|
|
33
|
+
* v1 default forwarder. Dispatches `getProducts` / `refineProducts` to
|
|
34
|
+
* a running mock-server.
|
|
35
|
+
*
|
|
36
|
+
* @public
|
|
37
|
+
*/
|
|
38
|
+
class MockProposalManager {
|
|
39
|
+
capabilities;
|
|
40
|
+
url;
|
|
41
|
+
headers;
|
|
42
|
+
timeoutMs;
|
|
43
|
+
fetchImpl;
|
|
44
|
+
constructor(options) {
|
|
45
|
+
if (!options.mockUpstreamUrl || typeof options.mockUpstreamUrl !== 'string') {
|
|
46
|
+
throw new Error('MockProposalManager requires a non-empty `mockUpstreamUrl` pointing at a ' +
|
|
47
|
+
'running `bin/adcp.js mock-server <specialism>` instance.');
|
|
48
|
+
}
|
|
49
|
+
this.capabilities = {
|
|
50
|
+
salesSpecialism: options.salesSpecialism ?? 'sales-non-guaranteed',
|
|
51
|
+
refine: options.refine ?? false,
|
|
52
|
+
};
|
|
53
|
+
// Strip trailing slashes (loop-based, not regex) so we keep
|
|
54
|
+
// `${url}/get_products` clean without a quantifier-and-anchor
|
|
55
|
+
// pattern CodeQL flags as polynomial-ReDoS-adjacent.
|
|
56
|
+
let trimmed = options.mockUpstreamUrl;
|
|
57
|
+
while (trimmed.endsWith('/'))
|
|
58
|
+
trimmed = trimmed.slice(0, -1);
|
|
59
|
+
this.url = trimmed;
|
|
60
|
+
this.headers = options.defaultHeaders ?? {};
|
|
61
|
+
this.timeoutMs = options.timeoutMs ?? 30_000;
|
|
62
|
+
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
63
|
+
}
|
|
64
|
+
/** The configured mock-server URL — useful for diagnostics. */
|
|
65
|
+
get mockUpstreamUrl() {
|
|
66
|
+
return this.url;
|
|
67
|
+
}
|
|
68
|
+
async getProducts(req, _ctx) {
|
|
69
|
+
return this.forward('/get_products', req);
|
|
70
|
+
}
|
|
71
|
+
async refineProducts(req, _ctx) {
|
|
72
|
+
if (!this.capabilities.refine) {
|
|
73
|
+
// Adopter wired the manager without refine but the framework
|
|
74
|
+
// dispatched here anyway — surface the inconsistency rather than
|
|
75
|
+
// silently forwarding.
|
|
76
|
+
throw new Error('MockProposalManager.refineProducts called but capabilities.refine is false. ' +
|
|
77
|
+
'Pass `refine: true` to the constructor to enable refine forwarding.');
|
|
78
|
+
}
|
|
79
|
+
return this.forward('/refine_products', req);
|
|
80
|
+
}
|
|
81
|
+
async forward(path, body) {
|
|
82
|
+
const controller = new AbortController();
|
|
83
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
84
|
+
try {
|
|
85
|
+
const response = await this.fetchImpl(`${this.url}${path}`, {
|
|
86
|
+
method: 'POST',
|
|
87
|
+
headers: {
|
|
88
|
+
'content-type': 'application/json',
|
|
89
|
+
accept: 'application/json',
|
|
90
|
+
...this.headers,
|
|
91
|
+
},
|
|
92
|
+
body: JSON.stringify(body),
|
|
93
|
+
signal: controller.signal,
|
|
94
|
+
});
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
const text = await response.text().catch(() => '');
|
|
97
|
+
throw new Error(`MockProposalManager: mock-server returned ${response.status} for ${path}` +
|
|
98
|
+
(text ? `: ${text.slice(0, 500)}` : ''));
|
|
99
|
+
}
|
|
100
|
+
const json = (await response.json());
|
|
101
|
+
return json;
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
clearTimeout(timer);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
exports.MockProposalManager = MockProposalManager;
|
|
109
|
+
//# sourceMappingURL=mock-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-manager.js","sourceRoot":"","sources":["../../../../../src/lib/server/decisioning/proposal/mock-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ProposalStore — per-tenant proposal lifecycle persistence.
|
|
3
|
+
*
|
|
4
|
+
* The single ledger for proposal recipes across the entire lifecycle:
|
|
5
|
+
* draft (in-flight refine iterations) → committed (post-finalize, with
|
|
6
|
+
* `expires_at` hold window) → consumed (post-`create_media_buy`).
|
|
7
|
+
*
|
|
8
|
+
* Ports `adcp-client-python.src/adcp/decisioning/proposal_store.py`.
|
|
9
|
+
*
|
|
10
|
+
* State machine the framework drives:
|
|
11
|
+
*
|
|
12
|
+
* ```
|
|
13
|
+
* ┌──── releaseConsumption ────┐
|
|
14
|
+
* ▼ │
|
|
15
|
+
* putDraft ─► DRAFT ─► commit ─► COMMITTED ─► tryReserveConsumption ─► CONSUMING
|
|
16
|
+
* ▲ │
|
|
17
|
+
* │ │
|
|
18
|
+
* (refine finalizeConsumption
|
|
19
|
+
* iteration) │
|
|
20
|
+
* │ ▼
|
|
21
|
+
* └─ putDraft (overwrite while DRAFT) ─┘ CONSUMED
|
|
22
|
+
* (terminal)
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* The `COMMITTED → CONSUMING → CONSUMED` two-phase transition prevents the
|
|
26
|
+
* inventory double-spend race that a check-then-act sequence on `COMMITTED`
|
|
27
|
+
* would expose. Two parallel `create_media_buy(proposal_id=X)` calls cannot
|
|
28
|
+
* both reserve the proposal — the second `tryReserveConsumption` raises
|
|
29
|
+
* `PROPOSAL_NOT_COMMITTED` once the first transitions the record. Adapter
|
|
30
|
+
* dispatch runs against the reservation; on success the framework calls
|
|
31
|
+
* `finalizeConsumption`; on failure `releaseConsumption` rolls back to
|
|
32
|
+
* COMMITTED so the buyer can retry.
|
|
33
|
+
*
|
|
34
|
+
* Transitions outside this graph (commit-from-COMMITTED with mismatched
|
|
35
|
+
* payload, finalize-from-DRAFT, etc.) throw `AdcpError` with `INTERNAL_ERROR`
|
|
36
|
+
* — those are framework / adopter bugs, not buyer-facing rejections.
|
|
37
|
+
*
|
|
38
|
+
* @public
|
|
39
|
+
* @packageDocumentation
|
|
40
|
+
*/
|
|
41
|
+
import type { MaybePromise } from '../../create-adcp-server';
|
|
42
|
+
import type { Recipe } from './types';
|
|
43
|
+
/**
|
|
44
|
+
* Lifecycle states for a stored proposal.
|
|
45
|
+
*
|
|
46
|
+
* No `EXPIRED` member: the framework computes expiry from
|
|
47
|
+
* {@link ProposalRecord.expiresAt} + the current clock + the adopter's
|
|
48
|
+
* grace window. Storing expiry as a state would create a clock-driven
|
|
49
|
+
* write the framework doesn't actually need.
|
|
50
|
+
*
|
|
51
|
+
* @public
|
|
52
|
+
*/
|
|
53
|
+
export type ProposalState = 'draft' | 'committed' | 'consuming' | 'consumed';
|
|
54
|
+
/**
|
|
55
|
+
* The framework's per-proposal storage row.
|
|
56
|
+
*
|
|
57
|
+
* @public
|
|
58
|
+
*/
|
|
59
|
+
export interface ProposalRecord<TRecipe extends Recipe = Recipe> {
|
|
60
|
+
/** Stable identifier the buyer receives in the `proposals[]` wire array. */
|
|
61
|
+
proposalId: string;
|
|
62
|
+
/** Account that owns the proposal. Drives the cross-tenant check on `get`. */
|
|
63
|
+
accountId: string;
|
|
64
|
+
/** Current lifecycle state. */
|
|
65
|
+
state: ProposalState;
|
|
66
|
+
/**
|
|
67
|
+
* `productId -> Recipe` mapping. The {@link ProposalManager} returned these
|
|
68
|
+
* alongside products on `getProducts` / `refineProducts`; the framework
|
|
69
|
+
* persists them so `DecisioningPlatform.createMediaBuy` can hydrate
|
|
70
|
+
* `ctx.recipes` from this same record.
|
|
71
|
+
*/
|
|
72
|
+
recipes: ReadonlyMap<string, TRecipe>;
|
|
73
|
+
/**
|
|
74
|
+
* The wire `Proposal` shape. Stored so the framework can re-emit it on
|
|
75
|
+
* refine iterations or replay it post-finalize without round-tripping
|
|
76
|
+
* through the manager again.
|
|
77
|
+
*/
|
|
78
|
+
proposalPayload: Record<string, unknown>;
|
|
79
|
+
/**
|
|
80
|
+
* Set on `commit`. The inventory hold window; framework rejects
|
|
81
|
+
* `create_media_buy` calls past this deadline (plus the adopter's grace).
|
|
82
|
+
*/
|
|
83
|
+
expiresAt?: Date;
|
|
84
|
+
/**
|
|
85
|
+
* Set on `finalizeConsumption`. The accepted proposal's terminal binding
|
|
86
|
+
* to a media buy; reverse-index lookups via `getByMediaBuyId` use this.
|
|
87
|
+
*/
|
|
88
|
+
mediaBuyId?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Captured at `putDraft` time. Adopters whose Recipe subtypes add required
|
|
91
|
+
* fields later bump the schema and write a migration (or evict pre-bump
|
|
92
|
+
* records). Framework reads but does not enforce.
|
|
93
|
+
*/
|
|
94
|
+
recipeSchemaVersion?: number;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Per-tenant proposal lifecycle persistence.
|
|
98
|
+
*
|
|
99
|
+
* Methods may return `T` or `Promise<T>` — the framework awaits at call time.
|
|
100
|
+
* Mirrors the in-tree `MediaBuyStore` posture.
|
|
101
|
+
*
|
|
102
|
+
* @public
|
|
103
|
+
*/
|
|
104
|
+
export interface ProposalStore<TRecipe extends Recipe = Recipe> {
|
|
105
|
+
/**
|
|
106
|
+
* Drives the production-mode gate. `false` for {@link InMemoryProposalStore};
|
|
107
|
+
* `true` for adopter-supplied durable backings (Postgres / Redis).
|
|
108
|
+
*/
|
|
109
|
+
readonly isDurable: boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Store / replace a draft proposal.
|
|
112
|
+
*
|
|
113
|
+
* Refine iterations call this with the same `proposalId` to overwrite.
|
|
114
|
+
* Calling on a record currently in COMMITTED, CONSUMING, or CONSUMED is
|
|
115
|
+
* rejected.
|
|
116
|
+
*/
|
|
117
|
+
putDraft(args: {
|
|
118
|
+
proposalId: string;
|
|
119
|
+
accountId: string;
|
|
120
|
+
recipes: ReadonlyMap<string, TRecipe>;
|
|
121
|
+
proposalPayload: Record<string, unknown>;
|
|
122
|
+
}): MaybePromise<void>;
|
|
123
|
+
/**
|
|
124
|
+
* Look up a proposal record. Cross-tenant probes return `null` rather
|
|
125
|
+
* than the raw record — required to defeat principal-enumeration via
|
|
126
|
+
* `proposalId` probing. The dispatch path always passes the
|
|
127
|
+
* authenticated principal's `accountId`.
|
|
128
|
+
*
|
|
129
|
+
* **`expectedAccountId` is required.** Earlier preview made it optional
|
|
130
|
+
* for "framework-internal raw read" callers, but every call site that
|
|
131
|
+
* loads a record into a buyer-visible response path needs the tenant
|
|
132
|
+
* gate. Direct-debug callers that legitimately want a raw record across
|
|
133
|
+
* tenants should reach for a separate operator-tool surface, not bypass
|
|
134
|
+
* this gate. Closes a sharp edge an adopter would silently miss.
|
|
135
|
+
*/
|
|
136
|
+
get(proposalId: string, args: {
|
|
137
|
+
expectedAccountId: string;
|
|
138
|
+
}): MaybePromise<ProposalRecord<TRecipe> | null>;
|
|
139
|
+
/**
|
|
140
|
+
* Promote DRAFT → COMMITTED. Idempotent on re-call with equal `expiresAt`
|
|
141
|
+
* + `proposalPayload`. A second commit with different values raises
|
|
142
|
+
* `INTERNAL_ERROR`.
|
|
143
|
+
*/
|
|
144
|
+
commit(proposalId: string, args: {
|
|
145
|
+
expiresAt: Date;
|
|
146
|
+
proposalPayload: Record<string, unknown>;
|
|
147
|
+
}): MaybePromise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* Atomic CAS: COMMITTED → CONSUMING.
|
|
150
|
+
*
|
|
151
|
+
* The framework calls this BEFORE dispatching `createMediaBuy`. Holds
|
|
152
|
+
* the reservation until `finalizeConsumption` (success) or
|
|
153
|
+
* `releaseConsumption` (rollback). Two parallel callers cannot both
|
|
154
|
+
* reserve; the loser raises `PROPOSAL_NOT_COMMITTED`. SQL-backed
|
|
155
|
+
* implementations use `SELECT … FOR UPDATE` or equivalent.
|
|
156
|
+
*
|
|
157
|
+
* @throws AdcpError `PROPOSAL_NOT_FOUND` when no record exists,
|
|
158
|
+
* `PROPOSAL_NOT_COMMITTED` when state is not COMMITTED.
|
|
159
|
+
*/
|
|
160
|
+
tryReserveConsumption(proposalId: string, args: {
|
|
161
|
+
expectedAccountId: string;
|
|
162
|
+
}): MaybePromise<ProposalRecord<TRecipe>>;
|
|
163
|
+
/**
|
|
164
|
+
* Promote CONSUMING → CONSUMED and record the `mediaBuyId` back-reference
|
|
165
|
+
* for `getByMediaBuyId` lookups.
|
|
166
|
+
*/
|
|
167
|
+
finalizeConsumption(proposalId: string, args: {
|
|
168
|
+
mediaBuyId: string;
|
|
169
|
+
expectedAccountId: string;
|
|
170
|
+
}): MaybePromise<void>;
|
|
171
|
+
/**
|
|
172
|
+
* Rollback path: CONSUMING → COMMITTED. Idempotent on a record already
|
|
173
|
+
* in COMMITTED. Called when the adapter's `createMediaBuy` raises so
|
|
174
|
+
* the buyer can retry without `PROPOSAL_NOT_COMMITTED`.
|
|
175
|
+
*/
|
|
176
|
+
releaseConsumption(proposalId: string, args: {
|
|
177
|
+
expectedAccountId: string;
|
|
178
|
+
}): MaybePromise<void>;
|
|
179
|
+
/**
|
|
180
|
+
* Discard a proposal record. Idempotent — discarding an unknown id is
|
|
181
|
+
* a no-op (no throw).
|
|
182
|
+
*/
|
|
183
|
+
discard(proposalId: string): MaybePromise<void>;
|
|
184
|
+
/**
|
|
185
|
+
* Reverse-index lookup. Hydrate the (consumed) proposal that produced
|
|
186
|
+
* this `mediaBuyId` for the given tenant.
|
|
187
|
+
*
|
|
188
|
+
* `expectedAccountId` is required (no default) because `mediaBuyId` is
|
|
189
|
+
* adopter-controlled and can collide across tenants. SQL-backed impls
|
|
190
|
+
* add a uniqueness constraint on `(accountId, mediaBuyId)` where
|
|
191
|
+
* `mediaBuyId IS NOT NULL`.
|
|
192
|
+
*/
|
|
193
|
+
getByMediaBuyId(mediaBuyId: string, args: {
|
|
194
|
+
expectedAccountId: string;
|
|
195
|
+
}): MaybePromise<ProposalRecord<TRecipe> | null>;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Construction options for {@link InMemoryProposalStore}.
|
|
199
|
+
*
|
|
200
|
+
* @public
|
|
201
|
+
*/
|
|
202
|
+
export interface InMemoryProposalStoreOptions {
|
|
203
|
+
/**
|
|
204
|
+
* How long a draft proposal lives without a commit before being evicted.
|
|
205
|
+
* Default 24h. Pass as milliseconds.
|
|
206
|
+
*/
|
|
207
|
+
draftTtlMs?: number;
|
|
208
|
+
/**
|
|
209
|
+
* How long a committed (or consumed) proposal lives past its `expiresAt`
|
|
210
|
+
* before eviction. Default 7 days. Pass as milliseconds.
|
|
211
|
+
*/
|
|
212
|
+
committedGraceMs?: number;
|
|
213
|
+
/**
|
|
214
|
+
* Test-injectable clock. Defaults to `() => new Date()`.
|
|
215
|
+
*/
|
|
216
|
+
clock?: () => Date;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Process-local {@link ProposalStore} reference implementation.
|
|
220
|
+
*
|
|
221
|
+
* Storage is a plain `Map` — JS event-loop atomicity covers the critical
|
|
222
|
+
* sections (no preemption between awaits within a method body since there
|
|
223
|
+
* are no awaits). Adequate for local dev, CI, and tests; production
|
|
224
|
+
* deployments wire a durable backing implementing the same interface.
|
|
225
|
+
*
|
|
226
|
+
* Eviction:
|
|
227
|
+
*
|
|
228
|
+
* - Drafts older than `draftTtlMs` (default 24h) are evicted on every
|
|
229
|
+
* read / write.
|
|
230
|
+
* - Committed proposals more than `committedGraceMs` past `expiresAt`
|
|
231
|
+
* (default 7 days) are evicted.
|
|
232
|
+
*
|
|
233
|
+
* Eviction runs lazily — no background timer thread.
|
|
234
|
+
*
|
|
235
|
+
* Cross-tenant safety: `get` and `getByMediaBuyId` honor `expectedAccountId`
|
|
236
|
+
* — cross-tenant probes return `null`, not the raw record.
|
|
237
|
+
*
|
|
238
|
+
* @public
|
|
239
|
+
*/
|
|
240
|
+
export declare class InMemoryProposalStore<TRecipe extends Recipe = Recipe> implements ProposalStore<TRecipe> {
|
|
241
|
+
readonly isDurable = false;
|
|
242
|
+
private readonly records;
|
|
243
|
+
private readonly mediaBuyIndex;
|
|
244
|
+
private readonly creationTimes;
|
|
245
|
+
private readonly draftTtlMs;
|
|
246
|
+
private readonly committedGraceMs;
|
|
247
|
+
private readonly clock;
|
|
248
|
+
constructor(options?: InMemoryProposalStoreOptions);
|
|
249
|
+
private mediaBuyKey;
|
|
250
|
+
private evictExpired;
|
|
251
|
+
putDraft(args: {
|
|
252
|
+
proposalId: string;
|
|
253
|
+
accountId: string;
|
|
254
|
+
recipes: ReadonlyMap<string, TRecipe>;
|
|
255
|
+
proposalPayload: Record<string, unknown>;
|
|
256
|
+
}): void;
|
|
257
|
+
get(proposalId: string, args: {
|
|
258
|
+
expectedAccountId: string;
|
|
259
|
+
}): ProposalRecord<TRecipe> | null;
|
|
260
|
+
commit(proposalId: string, args: {
|
|
261
|
+
expiresAt: Date;
|
|
262
|
+
proposalPayload: Record<string, unknown>;
|
|
263
|
+
}): void;
|
|
264
|
+
tryReserveConsumption(proposalId: string, args: {
|
|
265
|
+
expectedAccountId: string;
|
|
266
|
+
}): ProposalRecord<TRecipe>;
|
|
267
|
+
finalizeConsumption(proposalId: string, args: {
|
|
268
|
+
mediaBuyId: string;
|
|
269
|
+
expectedAccountId: string;
|
|
270
|
+
}): void;
|
|
271
|
+
releaseConsumption(proposalId: string, args: {
|
|
272
|
+
expectedAccountId: string;
|
|
273
|
+
}): void;
|
|
274
|
+
discard(proposalId: string): void;
|
|
275
|
+
getByMediaBuyId(mediaBuyId: string, args: {
|
|
276
|
+
expectedAccountId: string;
|
|
277
|
+
}): ProposalRecord<TRecipe> | null;
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../../../src/lib/server/decisioning/proposal/store.ts"],"names":[],"mappings":"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"}
|