@adcp/sdk 16.2.0 → 16.3.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/AGENTS.md +2 -0
- package/dist/lib/core/AgentClient.js +17 -1
- package/dist/lib/core/AgentClient.mjs +17 -1
- package/dist/lib/core/SingleAgentClient.js +13 -0
- package/dist/lib/core/SingleAgentClient.mjs +13 -0
- package/dist/lib/core/TaskExecutor.js +88 -13
- package/dist/lib/core/TaskExecutor.mjs +89 -14
- package/dist/lib/errors/index.d.mts +34 -0
- package/dist/lib/errors/index.d.ts +34 -0
- package/dist/lib/errors/index.js +11 -0
- package/dist/lib/errors/index.mjs +10 -0
- package/dist/lib/index.d.mts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +2 -0
- package/dist/lib/index.mjs +2 -0
- package/dist/lib/media-buy/compatibility.d.mts +1 -0
- package/dist/lib/media-buy/compatibility.d.ts +1 -0
- package/dist/lib/media-buy/compatibility.js +33 -10
- package/dist/lib/media-buy/compatibility.mjs +32 -14
- package/dist/lib/negotiation/buyer.js +11 -5
- package/dist/lib/negotiation/buyer.mjs +11 -5
- package/dist/lib/negotiation/types.d.mts +4 -2
- package/dist/lib/negotiation/types.d.ts +4 -2
- package/dist/lib/negotiation/verification.d.mts +15 -6
- package/dist/lib/negotiation/verification.d.ts +15 -6
- package/dist/lib/negotiation/verification.js +146 -27
- package/dist/lib/negotiation/verification.mjs +146 -28
- package/dist/lib/negotiation/version.d.mts +6 -0
- package/dist/lib/negotiation/version.d.ts +6 -0
- package/dist/lib/negotiation/version.js +60 -0
- package/dist/lib/negotiation/version.mjs +33 -0
- package/dist/lib/server/create-adcp-server.js +1 -1
- package/dist/lib/server/create-adcp-server.mjs +1 -1
- package/dist/lib/server/error-arm-tools.d.mts +10 -10
- package/dist/lib/server/error-arm-tools.d.ts +10 -10
- package/dist/lib/server/error-arm-tools.js +22 -58
- package/dist/lib/server/error-arm-tools.mjs +30 -65
- package/dist/lib/testing/compliance/comply.js +17 -0
- package/dist/lib/testing/compliance/comply.mjs +17 -0
- package/dist/lib/testing/index.d.mts +3 -0
- package/dist/lib/testing/index.d.ts +3 -0
- package/dist/lib/testing/index.js +44 -2
- package/dist/lib/testing/index.mjs +42 -0
- package/dist/lib/testing/storyboard/collection-selection.d.mts +259 -0
- package/dist/lib/testing/storyboard/collection-selection.d.ts +259 -0
- package/dist/lib/testing/storyboard/collection-selection.js +384 -0
- package/dist/lib/testing/storyboard/collection-selection.mjs +348 -0
- package/dist/lib/testing/storyboard/context.js +12 -6
- package/dist/lib/testing/storyboard/context.mjs +12 -6
- package/dist/lib/testing/storyboard/fixture-resolution.d.mts +39 -1
- package/dist/lib/testing/storyboard/fixture-resolution.d.ts +39 -1
- package/dist/lib/testing/storyboard/fixture-resolution.js +216 -12
- package/dist/lib/testing/storyboard/fixture-resolution.mjs +218 -12
- package/dist/lib/testing/storyboard/index.d.mts +9 -2
- package/dist/lib/testing/storyboard/index.d.ts +9 -2
- package/dist/lib/testing/storyboard/index.js +51 -2
- package/dist/lib/testing/storyboard/index.mjs +49 -1
- package/dist/lib/testing/storyboard/prepared-fixtures.d.mts +471 -0
- package/dist/lib/testing/storyboard/prepared-fixtures.d.ts +471 -0
- package/dist/lib/testing/storyboard/prepared-fixtures.js +434 -0
- package/dist/lib/testing/storyboard/prepared-fixtures.mjs +389 -0
- package/dist/lib/testing/storyboard/protected-context.d.mts +127 -0
- package/dist/lib/testing/storyboard/protected-context.d.ts +127 -0
- package/dist/lib/testing/storyboard/protected-context.js +301 -0
- package/dist/lib/testing/storyboard/protected-context.mjs +267 -0
- package/dist/lib/testing/storyboard/rejection-hints.js +13 -4
- package/dist/lib/testing/storyboard/rejection-hints.mjs +13 -4
- package/dist/lib/testing/storyboard/runner.d.mts +24 -0
- package/dist/lib/testing/storyboard/runner.d.ts +24 -0
- package/dist/lib/testing/storyboard/runner.js +1061 -105
- package/dist/lib/testing/storyboard/runner.mjs +1075 -106
- package/dist/lib/testing/storyboard/seeding.d.mts +15 -1
- package/dist/lib/testing/storyboard/seeding.d.ts +15 -1
- package/dist/lib/testing/storyboard/seeding.js +272 -12
- package/dist/lib/testing/storyboard/seeding.mjs +274 -13
- package/dist/lib/testing/storyboard/types.d.mts +207 -10
- package/dist/lib/testing/storyboard/types.d.ts +207 -10
- package/dist/lib/testing/storyboard/types.js +1 -1
- package/dist/lib/testing/storyboard/types.mjs +1 -1
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- package/dist/lib/testing/storyboard/validations.js +95 -0
- package/dist/lib/testing/storyboard/validations.mjs +95 -0
- package/dist/lib/validation/bundled-schema-store.js +5 -0
- package/dist/lib/validation/bundled-schema-store.mjs +4 -0
- package/dist/lib/validation/schema-loader.js +19 -2
- package/dist/lib/validation/schema-loader.mjs +22 -3
- package/dist/lib/version.d.mts +3 -3
- package/dist/lib/version.d.ts +3 -3
- package/dist/lib/version.js +3 -3
- package/dist/lib/version.mjs +3 -3
- package/docs/TYPE-SUMMARY.md +1 -1
- package/docs/guides/COLLECTION-FIXTURE-FOUNDATION.md +850 -0
- package/docs/guides/PROPOSAL-TERMS-VERIFICATION.md +66 -0
- package/docs/llms.txt +3 -2
- package/docs/migration-14.x-rc-worksheet.md +4 -4
- package/package.json +1 -1
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reusable fixture-preparation state, its binding identity, and the
|
|
3
|
+
* every-lookup authorization gate.
|
|
4
|
+
*
|
|
5
|
+
* `prepareStoryboardFixtures` (in `runner.ts`) resolves a storyboard's
|
|
6
|
+
* fixture graph once and returns a `PreparedStoryboardFixtures`. Both the
|
|
7
|
+
* full runner and the standalone step runner can then execute against that
|
|
8
|
+
* pinned selection instead of re-discovering — or, in the standalone case
|
|
9
|
+
* today, silently transmitting literal authored handles.
|
|
10
|
+
*
|
|
11
|
+
* Two boundaries live here, and they are deliberately independent:
|
|
12
|
+
*
|
|
13
|
+
* **1. Binding coherence (portable, SDK-owned).** Prepared state is pinned
|
|
14
|
+
* to the storyboard content, the resolved seller route, the exact schema
|
|
15
|
+
* artifact in use, the contract version, the account/sandbox scope, a
|
|
16
|
+
* nonsecret credential identity, and the run id. Reuse under a different
|
|
17
|
+
* binding is a terminal failure, not a silent re-pick: retrying must not be
|
|
18
|
+
* able to launder a failed preparation into a freshly discovered alternative.
|
|
19
|
+
*
|
|
20
|
+
* **2. Authorization (hosted, NOT implemented here).** Resolving a principal
|
|
21
|
+
* from a session, storing grants, and revoking them are host duties. This
|
|
22
|
+
* module mandates the integration shape — an authorizer consulted on *every*
|
|
23
|
+
* lookup, before any snapshot is disclosed and before any dependent wire
|
|
24
|
+
* call — and fails closed when a reference is supplied without one. It does
|
|
25
|
+
* not implement a grant service, and nothing here should be read as claiming
|
|
26
|
+
* that an SDK-local check substitutes for one.
|
|
27
|
+
*
|
|
28
|
+
* ## What is deliberately NOT authority
|
|
29
|
+
*
|
|
30
|
+
* An opaque or sealed reference, a successful decryption, a caller-supplied
|
|
31
|
+
* `context_provenance` map, a principal string in caller JSON, a
|
|
32
|
+
* seller-authored authorization boolean, or a structurally identical frozen
|
|
33
|
+
* object are all reachable from untrusted input. None of them produce the
|
|
34
|
+
* runtime capability this module requires. The capability is object identity
|
|
35
|
+
* held in a module-private `WeakSet`: a `structuredClone`, a JSON round-trip,
|
|
36
|
+
* or a hand-built look-alike is rejected, which is what stops "I have state
|
|
37
|
+
* that looks prepared" from becoming "I am authorized".
|
|
38
|
+
*
|
|
39
|
+
* ## Process scope, stated plainly
|
|
40
|
+
*
|
|
41
|
+
* Because the capability is a live object identity and the credential
|
|
42
|
+
* fingerprint is keyed by a per-process random HMAC key, prepared state is
|
|
43
|
+
* **not portable across processes**. That is a deliberate limit, not an
|
|
44
|
+
* oversight: a frozen JSON snapshot that survived a process boundary carries
|
|
45
|
+
* no evidence that its grant is still live. Multi-process and durable reuse
|
|
46
|
+
* require authenticated reconstruction, or a host-side reference lookup that
|
|
47
|
+
* re-checks live scope — see `docs/guides/COLLECTION-FIXTURE-FOUNDATION.md`.
|
|
48
|
+
*/
|
|
49
|
+
import type { CollectionSelectionWitness } from './collection-selection.mjs';
|
|
50
|
+
import type { FixtureBindingRegistry } from './fixture-resolution.mjs';
|
|
51
|
+
import type { ContextProvenanceEntry, FixtureResolutionCoverageGap, FixtureResolutionRecord, Storyboard, StoryboardPhaseResult } from './types.mjs';
|
|
52
|
+
/**
|
|
53
|
+
* Version of the prepared-state contract itself. A prepared state produced
|
|
54
|
+
* under one contract version is never consumed under another: an older
|
|
55
|
+
* runner must fail closed rather than reinterpret bindings it does not
|
|
56
|
+
* understand.
|
|
57
|
+
*/
|
|
58
|
+
export declare const PREPARED_FIXTURES_CONTRACT_VERSION = "1.0.0";
|
|
59
|
+
/** Identity of the schema artifact validation resolved against. */
|
|
60
|
+
export interface PreparedSchemaArtifact {
|
|
61
|
+
/** AdCP version the run pinned. */
|
|
62
|
+
adcp_version: string;
|
|
63
|
+
/** Bundle key the loader resolved that version to. */
|
|
64
|
+
bundle_key: string;
|
|
65
|
+
/** True when a caller-supplied external bundle was authoritative. */
|
|
66
|
+
external: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Digest over the bundle tree's file inventory (relative path, byte size,
|
|
69
|
+
* mtime) at the moment that root was FIRST resolved in this process.
|
|
70
|
+
*
|
|
71
|
+
* It detects reuse against a different resolved bundle root — the case a
|
|
72
|
+
* `withExternalSchemaRoot` scope or a version change produces. It does NOT
|
|
73
|
+
* detect in-place mutation of a root already observed: the digest is
|
|
74
|
+
* cached per root for the process lifetime, so prepared and current
|
|
75
|
+
* bindings would both read the same cached value. It is also not a
|
|
76
|
+
* publisher-signed content digest. Treat it as bundle identity at first
|
|
77
|
+
* observation, nothing stronger.
|
|
78
|
+
*/
|
|
79
|
+
digest: string;
|
|
80
|
+
}
|
|
81
|
+
/** Nonsecret binding identity. Never contains a credential. */
|
|
82
|
+
export interface PreparedFixtureBinding {
|
|
83
|
+
storyboard_id: string;
|
|
84
|
+
/** SHA-256 over the canonicalized storyboard document. */
|
|
85
|
+
storyboard_digest: string;
|
|
86
|
+
/**
|
|
87
|
+
* Resolved seller route(s), with credential material removed.
|
|
88
|
+
*
|
|
89
|
+
* A route URL can carry userinfo or query-string tokens, and this binding
|
|
90
|
+
* is handed to the host authorizer (which a host will reasonably log for
|
|
91
|
+
* audit) and exposed on the public accessor. The raw form must not
|
|
92
|
+
* survive. Diff fidelity is preserved by `agent_route_fingerprint`, so two
|
|
93
|
+
* routes differing only in credentials still refuse reuse.
|
|
94
|
+
*/
|
|
95
|
+
agent_urls: string[];
|
|
96
|
+
/**
|
|
97
|
+
* The ONE route preparation actually contacted, positionally.
|
|
98
|
+
*
|
|
99
|
+
* `agent_urls` is sorted and `agent_route_fingerprint` sorts by key, so
|
|
100
|
+
* neither records which of several routes the graph was pinned against.
|
|
101
|
+
* Diffed, so a state pinned from one seller cannot be reused by a run
|
|
102
|
+
* that would dispatch its pinned entities to another.
|
|
103
|
+
*/
|
|
104
|
+
fixture_agent_url: string;
|
|
105
|
+
/** Keyed fingerprint over the RAW routes, so redaction cannot merge two. */
|
|
106
|
+
agent_route_fingerprint: string;
|
|
107
|
+
schema_artifact: PreparedSchemaArtifact;
|
|
108
|
+
contract_version: string;
|
|
109
|
+
/**
|
|
110
|
+
* Resolved account scope the graph was prepared under, taken from the same
|
|
111
|
+
* `resolveAccount` the discovery call uses, so a run that switches account
|
|
112
|
+
* cannot inherit another account's pinned catalog.
|
|
113
|
+
*
|
|
114
|
+
* Today `resolveAccount` derives `operator` from `brand.domain`, so this
|
|
115
|
+
* is effectively the brand domain — one dimension, not two. Note also that
|
|
116
|
+
* an unbranded run falls back to the SDK's default brand, which means all
|
|
117
|
+
* unbranded runs share one scope. Multi-tenant hosts must not rely on this
|
|
118
|
+
* field alone for isolation; that is what the authorizer is for.
|
|
119
|
+
*/
|
|
120
|
+
account_scope: string;
|
|
121
|
+
/**
|
|
122
|
+
* The brand the graph was DISCOVERED under, canonicalized.
|
|
123
|
+
*
|
|
124
|
+
* Separate from `account_scope` because discovery resolves it separately:
|
|
125
|
+
* `context.brand` wins over the account's brand, which wins over the
|
|
126
|
+
* SDK default. A graph pinned against one advertiser's catalog must not be
|
|
127
|
+
* reused under another's, and the authorizer needs a field it can refuse
|
|
128
|
+
* on rather than two byte-identical payloads.
|
|
129
|
+
*/
|
|
130
|
+
brand_scope: string;
|
|
131
|
+
/**
|
|
132
|
+
* The account the STEP's request will actually carry, when the step
|
|
133
|
+
* authors one that overrides the context account.
|
|
134
|
+
*
|
|
135
|
+
* `resolveMediaBuyAccount` lets an authored `sample_request.account` with
|
|
136
|
+
* an `account_id` or `operator` win over `context.account`, so
|
|
137
|
+
* `account_scope` alone can describe an account the request never uses.
|
|
138
|
+
* Absent when the step authors no overriding identity — then
|
|
139
|
+
* `account_scope` is the effective one.
|
|
140
|
+
*
|
|
141
|
+
* NOT diffed, for the same reason `step_credential_fingerprint` is not:
|
|
142
|
+
* it is per-step, so a preparation (which has no step) would mismatch
|
|
143
|
+
* every step that sets it. It needs no diff to be safe — an authored
|
|
144
|
+
* account lives in the storyboard body, which `storyboard_digest`
|
|
145
|
+
* already pins. It is here so the authorizer is told the truth about
|
|
146
|
+
* which account the call is about to transact under.
|
|
147
|
+
*/
|
|
148
|
+
request_account_scope?: string;
|
|
149
|
+
/** Sandbox flag in scope. */
|
|
150
|
+
sandbox: boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Caller-declared nonsecret principal. Supplied via
|
|
153
|
+
* `options.prepared_fixtures_principal`; absent when the caller did not
|
|
154
|
+
* declare one, which a host authorizer may itself choose to refuse.
|
|
155
|
+
*/
|
|
156
|
+
principal?: string;
|
|
157
|
+
/**
|
|
158
|
+
* HMAC fingerprint of the transport credential under a per-process random
|
|
159
|
+
* key. It detects a credential change between preparation and reuse while
|
|
160
|
+
* disclosing nothing about the credential and remaining useless outside
|
|
161
|
+
* this process. Never a token, never reversible, never an authorization.
|
|
162
|
+
*/
|
|
163
|
+
credential_fingerprint: string;
|
|
164
|
+
/**
|
|
165
|
+
* Effective credential for the STEP about to execute, including its own
|
|
166
|
+
* `auth` directive. Present only when the step in scope DECLARES its own
|
|
167
|
+
* `auth`; a step that inherits the run credential produces no field, so an
|
|
168
|
+
* absent value means "inherits", not "no step".
|
|
169
|
+
*
|
|
170
|
+
* Deliberately NOT part of `BINDING_FIELDS`: preparation has no step, so
|
|
171
|
+
* diffing it would refuse every legitimate reuse. It exists so the host
|
|
172
|
+
* authorizer can see what the step will actually dispatch with — the
|
|
173
|
+
* `security_baseline` probes deliberately dispatch unauthenticated or
|
|
174
|
+
* with an invalid key — and refuse on its own terms. Like the run
|
|
175
|
+
* fingerprint it is an HMAC under a per-process key, never the credential.
|
|
176
|
+
*/
|
|
177
|
+
step_credential_fingerprint?: string;
|
|
178
|
+
/**
|
|
179
|
+
* Nonsecret companion to `step_credential_fingerprint`: whether the step
|
|
180
|
+
* dispatches with NO credential, with one it authored itself, or with the
|
|
181
|
+
* credential of the specialism route it is dispatched to. The fingerprint
|
|
182
|
+
* is keyed per process, so a host can see that it changed but not what it
|
|
183
|
+
* is; this is the value an authorizer can branch on.
|
|
184
|
+
*/
|
|
185
|
+
step_auth_kind?: 'none' | 'override' | 'routed';
|
|
186
|
+
/**
|
|
187
|
+
* `<specialism key>@<redacted url>` the step actually dispatches to, when
|
|
188
|
+
* the run uses per-specialism routing.
|
|
189
|
+
*
|
|
190
|
+
* `agent_urls` is the sorted set of EVERY route in the run and says
|
|
191
|
+
* nothing about which one this step uses, so an authorizer scoping a
|
|
192
|
+
* grant to one seller had no field to refuse on. Also NOT diffed —
|
|
193
|
+
* preparation has no step.
|
|
194
|
+
*/
|
|
195
|
+
step_route?: string;
|
|
196
|
+
/** Identity of the preparation run. */
|
|
197
|
+
run_id: string;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Why a lookup was refused. Surfaces verbatim as the `actual` of the
|
|
201
|
+
* `prepared_fixtures_authorization` validation, so this union IS the
|
|
202
|
+
* output contract a report consumer can switch on.
|
|
203
|
+
*/
|
|
204
|
+
export type PreparedFixturesRefusalCode = 'untrusted_state' | 'binding_mismatch' | 'authorizer_required' | 'authorizer_denied' | 'contract_version_mismatch'
|
|
205
|
+
/**
|
|
206
|
+
* Caller-supplied `context`, `context_provenance` or
|
|
207
|
+
* `response_derived_not_applicable_context_keys` carried a reserved or
|
|
208
|
+
* prototype-sensitive key. Raised by the runner's pre-contact screen
|
|
209
|
+
* rather than by `resolvePreparedFixtures`, but it grades through the
|
|
210
|
+
* same validation, so a consumer typing on this union would otherwise
|
|
211
|
+
* meet a value the union does not admit.
|
|
212
|
+
*/
|
|
213
|
+
| 'unauthorized_metadata';
|
|
214
|
+
export interface PreparedFixturesRefusal {
|
|
215
|
+
code: PreparedFixturesRefusalCode;
|
|
216
|
+
detail: string;
|
|
217
|
+
}
|
|
218
|
+
/** Context handed to the host authorizer on every lookup. */
|
|
219
|
+
export interface PreparedFixturesLookup {
|
|
220
|
+
/** Nonsecret binding recorded at preparation time. */
|
|
221
|
+
binding: PreparedFixtureBinding;
|
|
222
|
+
/** Nonsecret binding observed right now, after routing and auth overrides. */
|
|
223
|
+
current: PreparedFixtureBinding;
|
|
224
|
+
/** Storyboard step about to execute, when the lookup is per-step. */
|
|
225
|
+
step_id?: string;
|
|
226
|
+
/**
|
|
227
|
+
* Which gate asked.
|
|
228
|
+
*
|
|
229
|
+
* A run makes one `run` lookup, one `pass` lookup per pass, and one `step`
|
|
230
|
+
* lookup per step. A host implementing "every lookup is a fresh grant use"
|
|
231
|
+
* literally — consume-once token, nonce, strict counter — needs to tell
|
|
232
|
+
* them apart rather than seeing byte-identical payloads.
|
|
233
|
+
*/
|
|
234
|
+
gate?: 'run' | 'pass' | 'step';
|
|
235
|
+
/** Opaque reference the caller presented, when reuse came through one. */
|
|
236
|
+
reference?: string;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* A host authorizer's answer. `authorized` must be literally `true`.
|
|
240
|
+
*
|
|
241
|
+
* **`detail` is echoed to the caller** when the refusal came from DIRECT
|
|
242
|
+
* state — it is the only specific diagnostic a legitimate operator gets,
|
|
243
|
+
* which is why it is not swallowed. It is your text, so keep
|
|
244
|
+
* infrastructure addresses, scoped keys and credential material out of
|
|
245
|
+
* it. A refusal that came through an opaque REFERENCE never echoes it:
|
|
246
|
+
* a denial reading "not yours" would confirm the reference existed.
|
|
247
|
+
*/
|
|
248
|
+
export type PreparedFixturesDecision = {
|
|
249
|
+
authorized: true;
|
|
250
|
+
} | {
|
|
251
|
+
authorized: false;
|
|
252
|
+
detail: string;
|
|
253
|
+
};
|
|
254
|
+
/**
|
|
255
|
+
* Host-supplied authorization resolver, consulted on EVERY lookup.
|
|
256
|
+
*
|
|
257
|
+
* Implementations must resolve the principal/tenant/org and run from trusted
|
|
258
|
+
* server session state (never from the request body), re-check the current
|
|
259
|
+
* grant, revocation and expiry, and re-check effective per-step credential
|
|
260
|
+
* scope after any routing or auth override. A decision made at preparation
|
|
261
|
+
* time is not reusable: a grant revoked after a successful prior step must
|
|
262
|
+
* fail the next one.
|
|
263
|
+
*/
|
|
264
|
+
export type PreparedFixturesAuthorizer = (lookup: PreparedFixturesLookup) => PreparedFixturesDecision | Promise<PreparedFixturesDecision>;
|
|
265
|
+
/**
|
|
266
|
+
* A reference to prepared state held in the host's authenticated run scope.
|
|
267
|
+
*
|
|
268
|
+
* The SDK cannot resolve one on its own — it has no session, no tenant and
|
|
269
|
+
* no grant store — so a reference without a `resolve` hook fails closed.
|
|
270
|
+
*/
|
|
271
|
+
export interface PreparedFixturesReference {
|
|
272
|
+
/** Opaque host-owned identifier. Not authority by itself. */
|
|
273
|
+
ref: string;
|
|
274
|
+
/**
|
|
275
|
+
* Host resolver returning the in-process prepared state for `ref`. Invoked
|
|
276
|
+
* on every lookup, so the host sees each use and can refuse a revoked one.
|
|
277
|
+
*/
|
|
278
|
+
resolve: (ref: string) => PreparedStoryboardFixtures | undefined | Promise<PreparedStoryboardFixtures | undefined>;
|
|
279
|
+
}
|
|
280
|
+
/** Per-handle state the resolver pinned, exposed read-only. */
|
|
281
|
+
export interface PreparedFixtureSelection {
|
|
282
|
+
handle: string;
|
|
283
|
+
fixture_type: FixtureResolutionRecord['fixture_type'];
|
|
284
|
+
product_handle?: string;
|
|
285
|
+
seller_ids: NonNullable<FixtureResolutionRecord['seller_ids']>;
|
|
286
|
+
}
|
|
287
|
+
export interface PreparedStoryboardFixturesInit {
|
|
288
|
+
binding: PreparedFixtureBinding;
|
|
289
|
+
bindings?: FixtureBindingRegistry;
|
|
290
|
+
resolutions: FixtureResolutionRecord[];
|
|
291
|
+
coverageGaps: FixtureResolutionCoverageGap[];
|
|
292
|
+
captures: Record<string, unknown>;
|
|
293
|
+
captureProvenance: Record<string, ContextProvenanceEntry>;
|
|
294
|
+
witnesses: Record<string, CollectionSelectionWitness>;
|
|
295
|
+
/** Terminal preparation outcome, carried forward verbatim on reuse. */
|
|
296
|
+
disposition: PreparedFixturesDisposition;
|
|
297
|
+
phase?: StoryboardPhaseResult;
|
|
298
|
+
}
|
|
299
|
+
export type PreparedFixturesDisposition =
|
|
300
|
+
/** Every declared fixture resolved; captures are published. */
|
|
301
|
+
{
|
|
302
|
+
status: 'resolved';
|
|
303
|
+
}
|
|
304
|
+
/** A declared strategy ladder exhausted with no binding. */
|
|
305
|
+
| {
|
|
306
|
+
status: 'unsatisfied';
|
|
307
|
+
detail: string;
|
|
308
|
+
}
|
|
309
|
+
/** Discovery, schema validation or setup failed. Terminal. */
|
|
310
|
+
| {
|
|
311
|
+
status: 'failed';
|
|
312
|
+
detail: string;
|
|
313
|
+
}
|
|
314
|
+
/** The agent cannot be graded for this storyboard's fixtures. */
|
|
315
|
+
| {
|
|
316
|
+
status: 'unsupported';
|
|
317
|
+
detail: string;
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* Immutable prepared fixture state.
|
|
321
|
+
*
|
|
322
|
+
* Instances are produced only by `prepareStoryboardFixtures`. The public
|
|
323
|
+
* accessors (`binding`, `disposition`, `resolutions`, `coverageGaps`,
|
|
324
|
+
* `selections`, `captures`, `captureProvenance`, `witnesses`) hand back
|
|
325
|
+
* detached clones, so a consumer that mutates what it reads cannot reach the
|
|
326
|
+
* pinned selection. `phase` is cloned on ingestion as well as on read, so
|
|
327
|
+
* the object the constructor was handed is not the canonical copy either.
|
|
328
|
+
*/
|
|
329
|
+
export declare class PreparedStoryboardFixtures {
|
|
330
|
+
#private;
|
|
331
|
+
/** Nonsecret binding identity. Detached copy. */
|
|
332
|
+
get binding(): PreparedFixtureBinding;
|
|
333
|
+
get disposition(): PreparedFixturesDisposition;
|
|
334
|
+
/** Machine-readable per-handle resolution evidence. Detached copy. */
|
|
335
|
+
get resolutions(): FixtureResolutionRecord[];
|
|
336
|
+
/** Coverage gaps observed during preparation. Detached copy. */
|
|
337
|
+
get coverageGaps(): FixtureResolutionCoverageGap[];
|
|
338
|
+
/** Pinned seller identities per handle. Detached copy. */
|
|
339
|
+
get selections(): PreparedFixtureSelection[];
|
|
340
|
+
/** Reserved-namespace captures. Detached copy. */
|
|
341
|
+
get captures(): Record<string, unknown>;
|
|
342
|
+
/** Capture provenance. Detached copy. */
|
|
343
|
+
get captureProvenance(): Record<string, ContextProvenanceEntry>;
|
|
344
|
+
/** Retained collection witnesses per handle. Detached copy. */
|
|
345
|
+
get witnesses(): Record<string, CollectionSelectionWitness>;
|
|
346
|
+
/**
|
|
347
|
+
* Detached copy of the synthetic pre-flight phase, for attachment to a
|
|
348
|
+
* full run's report. A live reference would let a report consumer mutate
|
|
349
|
+
* the preparation's own evidence — including a failed or no-match
|
|
350
|
+
* disposition's raw failure detail.
|
|
351
|
+
*/
|
|
352
|
+
get phase(): StoryboardPhaseResult | undefined;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Pair prepared state with its authorizer, so neither can be supplied
|
|
356
|
+
* without the other.
|
|
357
|
+
*
|
|
358
|
+
* `prepared_fixtures` and `prepared_fixtures_authorizer` are both optional
|
|
359
|
+
* on `StoryboardRunOptions`, which means the one thing the guide calls a
|
|
360
|
+
* requirement rather than optional hardening compiles clean when omitted —
|
|
361
|
+
* every hosted integrator discovered it by running it. Spread the result
|
|
362
|
+
* and the compiler asks for the authorizer:
|
|
363
|
+
*
|
|
364
|
+
* ```ts
|
|
365
|
+
* const result = await runStoryboardStep(agentUrl, storyboard, stepId, {
|
|
366
|
+
* ...options,
|
|
367
|
+
* ...withPreparedFixtures(prepared, authorize),
|
|
368
|
+
* });
|
|
369
|
+
* ```
|
|
370
|
+
*
|
|
371
|
+
* The raw fields still work; this is ergonomics, not enforcement. The
|
|
372
|
+
* enforcement is the fail-closed refusal in `resolvePreparedFixtures`.
|
|
373
|
+
*/
|
|
374
|
+
export declare function withPreparedFixtures(state: PreparedStoryboardFixtures | PreparedFixturesReference, authorizer: PreparedFixturesAuthorizer): {
|
|
375
|
+
prepared_fixtures: PreparedStoryboardFixtures | PreparedFixturesReference;
|
|
376
|
+
prepared_fixtures_authorizer: PreparedFixturesAuthorizer;
|
|
377
|
+
};
|
|
378
|
+
/**
|
|
379
|
+
* True only for a state produced by this process's
|
|
380
|
+
* `prepareStoryboardFixtures`. A JSON-rehydrated copy, a `structuredClone`,
|
|
381
|
+
* a hand-built object with the same public shape, and a direct `new` call
|
|
382
|
+
* all return false.
|
|
383
|
+
*/
|
|
384
|
+
export declare function isTrustedPreparedFixtures(value: unknown): value is PreparedStoryboardFixtures;
|
|
385
|
+
/**
|
|
386
|
+
* SHA-256 over the canonicalized storyboard document.
|
|
387
|
+
*
|
|
388
|
+
* Deliberately NOT memoized by object identity. A `Storyboard` is a mutable
|
|
389
|
+
* plain object, and caching its digest would preserve the authorized value
|
|
390
|
+
* after a later edit to a request or a fixture declaration — defeating the
|
|
391
|
+
* exact detection this field exists for. The cost is ~1.5 ms on a large
|
|
392
|
+
* storyboard, paid per lookup, which is negligible against wire time and
|
|
393
|
+
* nowhere near worth a stale integrity check.
|
|
394
|
+
*/
|
|
395
|
+
export declare function digestStoryboard(storyboard: Storyboard): string;
|
|
396
|
+
/** Resolve the schema artifact identity currently in effect. */
|
|
397
|
+
export declare function resolveSchemaArtifact(adcpVersion?: string): PreparedSchemaArtifact;
|
|
398
|
+
export interface BuildPreparedBindingInput {
|
|
399
|
+
storyboard: Storyboard;
|
|
400
|
+
agentUrls: string[];
|
|
401
|
+
adcpVersion?: string;
|
|
402
|
+
accountScope: string;
|
|
403
|
+
brandScope: string;
|
|
404
|
+
/** Account the step's own request authors, when it overrides the context. */
|
|
405
|
+
requestAccountScope?: string;
|
|
406
|
+
/** `[specialism key, url]` pairs, when the run uses per-specialism routing. */
|
|
407
|
+
agentRouteMap?: Array<[string, string]>;
|
|
408
|
+
sandbox: boolean;
|
|
409
|
+
/** Effective step credential, when a step is in scope. */
|
|
410
|
+
stepCredential?: string;
|
|
411
|
+
/** Whether that step drops the credential entirely, overrides it, or inherits a route's. */
|
|
412
|
+
stepAuthKind?: 'none' | 'override' | 'routed';
|
|
413
|
+
/** `<specialism key>@<redacted url>` this step dispatches to, when routed. */
|
|
414
|
+
stepRoute?: string;
|
|
415
|
+
principal?: string;
|
|
416
|
+
credential: string;
|
|
417
|
+
runId?: string;
|
|
418
|
+
}
|
|
419
|
+
export declare function buildPreparedBinding(input: BuildPreparedBindingInput): PreparedFixtureBinding;
|
|
420
|
+
/**
|
|
421
|
+
* Compare a prepared binding against the binding observed right now.
|
|
422
|
+
*
|
|
423
|
+
* `run_id` is deliberately excluded: it identifies the preparation, and the
|
|
424
|
+
* whole point of reuse is that later steps share it. Everything else must
|
|
425
|
+
* match exactly — a different route, account, sandbox flag, schema artifact,
|
|
426
|
+
* credential or storyboard body means the pinned graph describes a different
|
|
427
|
+
* world than the one about to be called.
|
|
428
|
+
*/
|
|
429
|
+
export declare function diffPreparedBinding(prepared: PreparedFixtureBinding, current: PreparedFixtureBinding): string[];
|
|
430
|
+
export interface ResolvePreparedFixturesInput {
|
|
431
|
+
/** Direct in-process state, or a host reference. */
|
|
432
|
+
supplied: PreparedStoryboardFixtures | PreparedFixturesReference | undefined;
|
|
433
|
+
/** Binding observed now, after routing and per-step auth overrides. */
|
|
434
|
+
current: PreparedFixtureBinding;
|
|
435
|
+
/** Host authorizer. REQUIRED for any reuse; absence fails closed. */
|
|
436
|
+
authorizer?: PreparedFixturesAuthorizer;
|
|
437
|
+
/** Step about to execute, for per-step authorization. */
|
|
438
|
+
stepId?: string;
|
|
439
|
+
/** Which gate is asking. */
|
|
440
|
+
gate?: 'run' | 'pass' | 'step';
|
|
441
|
+
}
|
|
442
|
+
export type ResolvePreparedFixturesResult = {
|
|
443
|
+
ok: true;
|
|
444
|
+
state: PreparedStoryboardFixtures;
|
|
445
|
+
} | {
|
|
446
|
+
ok: false;
|
|
447
|
+
refusal: PreparedFixturesRefusal;
|
|
448
|
+
};
|
|
449
|
+
/**
|
|
450
|
+
* Resolve and authorize prepared state for ONE lookup.
|
|
451
|
+
*
|
|
452
|
+
* Called before every step that could consume prepared state — not once at
|
|
453
|
+
* run start. Ordering matters and is load-bearing:
|
|
454
|
+
*
|
|
455
|
+
* 1. Establish that the object is genuinely this process's prepared state.
|
|
456
|
+
* 2. Ask the host authorizer, which re-checks live grant and revocation.
|
|
457
|
+
* 3. Only then re-check binding coherence against the CURRENT effective
|
|
458
|
+
* route, account, sandbox, schema artifact and credential.
|
|
459
|
+
*
|
|
460
|
+
* The authorizer runs BEFORE the binding diff, not after. In the hosted
|
|
461
|
+
* reference flow the host resolver answers for any reference it holds, so
|
|
462
|
+
* diffing first would answer an unauthorized caller's enumerated reference
|
|
463
|
+
* with a mismatch report describing someone else's principal, routes,
|
|
464
|
+
* account and credential fingerprint — and turn the fingerprint into a
|
|
465
|
+
* credential-confirmation oracle. For the same reason the refusal detail
|
|
466
|
+
* names only the FIELDS that differ, never their values.
|
|
467
|
+
*
|
|
468
|
+
* Only after all three does any snapshot become readable. A refusal returns
|
|
469
|
+
* before the caller can read captures and before any dependent wire call.
|
|
470
|
+
*/
|
|
471
|
+
export declare function resolvePreparedFixtures(input: ResolvePreparedFixturesInput): Promise<ResolvePreparedFixturesResult | undefined>;
|