@adcp/sdk 5.25.0 → 6.0.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.
Files changed (298) hide show
  1. package/README.md +45 -7
  2. package/dist/lib/compliance-fixtures/index.d.ts +1 -1
  3. package/dist/lib/compliance-fixtures/index.js +1 -1
  4. package/dist/lib/conformance/runners.d.ts.map +1 -1
  5. package/dist/lib/conformance/runners.js +13 -1
  6. package/dist/lib/conformance/runners.js.map +1 -1
  7. package/dist/lib/core/AgentClient.d.ts.map +1 -1
  8. package/dist/lib/core/SingleAgentClient.d.ts.map +1 -1
  9. package/dist/lib/core/SingleAgentClient.js +15 -0
  10. package/dist/lib/core/SingleAgentClient.js.map +1 -1
  11. package/dist/lib/core/TaskExecutor.d.ts +7 -0
  12. package/dist/lib/core/TaskExecutor.d.ts.map +1 -1
  13. package/dist/lib/core/TaskExecutor.js +9 -2
  14. package/dist/lib/core/TaskExecutor.js.map +1 -1
  15. package/dist/lib/index.d.ts +1 -1
  16. package/dist/lib/index.d.ts.map +1 -1
  17. package/dist/lib/index.js +7 -8
  18. package/dist/lib/index.js.map +1 -1
  19. package/dist/lib/protocols/index.d.ts +3 -1
  20. package/dist/lib/protocols/index.d.ts.map +1 -1
  21. package/dist/lib/protocols/index.js +23 -14
  22. package/dist/lib/protocols/index.js.map +1 -1
  23. package/dist/lib/schemas/index.d.ts +1 -1
  24. package/dist/lib/schemas/index.js +1 -1
  25. package/dist/lib/server/create-adcp-server.d.ts +142 -11
  26. package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
  27. package/dist/lib/server/create-adcp-server.js +211 -2
  28. package/dist/lib/server/create-adcp-server.js.map +1 -1
  29. package/dist/lib/server/ctx-metadata/backends/memory.d.ts +27 -0
  30. package/dist/lib/server/ctx-metadata/backends/memory.d.ts.map +1 -0
  31. package/dist/lib/server/ctx-metadata/backends/memory.js +72 -0
  32. package/dist/lib/server/ctx-metadata/backends/memory.js.map +1 -0
  33. package/dist/lib/server/ctx-metadata/backends/pg.d.ts +62 -0
  34. package/dist/lib/server/ctx-metadata/backends/pg.d.ts.map +1 -0
  35. package/dist/lib/server/ctx-metadata/backends/pg.js +145 -0
  36. package/dist/lib/server/ctx-metadata/backends/pg.js.map +1 -0
  37. package/dist/lib/server/ctx-metadata/index.d.ts +15 -0
  38. package/dist/lib/server/ctx-metadata/index.d.ts.map +1 -0
  39. package/dist/lib/server/ctx-metadata/index.js +28 -0
  40. package/dist/lib/server/ctx-metadata/index.js.map +1 -0
  41. package/dist/lib/server/ctx-metadata/store.d.ts +177 -0
  42. package/dist/lib/server/ctx-metadata/store.d.ts.map +1 -0
  43. package/dist/lib/server/ctx-metadata/store.js +327 -0
  44. package/dist/lib/server/ctx-metadata/store.js.map +1 -0
  45. package/dist/lib/server/ctx-metadata/wire-shape.d.ts +55 -0
  46. package/dist/lib/server/ctx-metadata/wire-shape.d.ts.map +1 -0
  47. package/dist/lib/server/ctx-metadata/wire-shape.js +121 -0
  48. package/dist/lib/server/ctx-metadata/wire-shape.js.map +1 -0
  49. package/dist/lib/server/decisioning/account.d.ts +309 -0
  50. package/dist/lib/server/decisioning/account.d.ts.map +1 -0
  51. package/dist/lib/server/decisioning/account.js +102 -0
  52. package/dist/lib/server/decisioning/account.js.map +1 -0
  53. package/dist/lib/server/decisioning/admin-router.d.ts +75 -0
  54. package/dist/lib/server/decisioning/admin-router.d.ts.map +1 -0
  55. package/dist/lib/server/decisioning/admin-router.js +120 -0
  56. package/dist/lib/server/decisioning/admin-router.js.map +1 -0
  57. package/dist/lib/server/decisioning/assembly-helpers.d.ts +204 -0
  58. package/dist/lib/server/decisioning/assembly-helpers.d.ts.map +1 -0
  59. package/dist/lib/server/decisioning/assembly-helpers.js +173 -0
  60. package/dist/lib/server/decisioning/assembly-helpers.js.map +1 -0
  61. package/dist/lib/server/decisioning/async-outcome.d.ts +154 -0
  62. package/dist/lib/server/decisioning/async-outcome.d.ts.map +1 -0
  63. package/dist/lib/server/decisioning/async-outcome.js +239 -0
  64. package/dist/lib/server/decisioning/async-outcome.js.map +1 -0
  65. package/dist/lib/server/decisioning/capabilities.d.ts +251 -0
  66. package/dist/lib/server/decisioning/capabilities.d.ts.map +1 -0
  67. package/dist/lib/server/decisioning/capabilities.js +16 -0
  68. package/dist/lib/server/decisioning/capabilities.js.map +1 -0
  69. package/dist/lib/server/decisioning/context.d.ts +212 -0
  70. package/dist/lib/server/decisioning/context.d.ts.map +1 -0
  71. package/dist/lib/server/decisioning/context.js +26 -0
  72. package/dist/lib/server/decisioning/context.js.map +1 -0
  73. package/dist/lib/server/decisioning/errors-typed.d.ts +104 -0
  74. package/dist/lib/server/decisioning/errors-typed.d.ts.map +1 -0
  75. package/dist/lib/server/decisioning/errors-typed.js +304 -0
  76. package/dist/lib/server/decisioning/errors-typed.js.map +1 -0
  77. package/dist/lib/server/decisioning/helpers.d.ts +131 -0
  78. package/dist/lib/server/decisioning/helpers.d.ts.map +1 -0
  79. package/dist/lib/server/decisioning/helpers.js +134 -0
  80. package/dist/lib/server/decisioning/helpers.js.map +1 -0
  81. package/dist/lib/server/decisioning/index.d.ts +46 -0
  82. package/dist/lib/server/decisioning/index.d.ts.map +1 -0
  83. package/dist/lib/server/decisioning/index.js +120 -0
  84. package/dist/lib/server/decisioning/index.js.map +1 -0
  85. package/dist/lib/server/decisioning/list-helpers.d.ts +53 -0
  86. package/dist/lib/server/decisioning/list-helpers.d.ts.map +1 -0
  87. package/dist/lib/server/decisioning/list-helpers.js +96 -0
  88. package/dist/lib/server/decisioning/list-helpers.js.map +1 -0
  89. package/dist/lib/server/decisioning/manifest-helpers.d.ts +56 -0
  90. package/dist/lib/server/decisioning/manifest-helpers.d.ts.map +1 -0
  91. package/dist/lib/server/decisioning/manifest-helpers.js +78 -0
  92. package/dist/lib/server/decisioning/manifest-helpers.js.map +1 -0
  93. package/dist/lib/server/decisioning/pagination.d.ts +21 -0
  94. package/dist/lib/server/decisioning/pagination.d.ts.map +1 -0
  95. package/dist/lib/server/decisioning/pagination.js +12 -0
  96. package/dist/lib/server/decisioning/pagination.js.map +1 -0
  97. package/dist/lib/server/decisioning/platform.d.ts +188 -0
  98. package/dist/lib/server/decisioning/platform.d.ts.map +1 -0
  99. package/dist/lib/server/decisioning/platform.js +19 -0
  100. package/dist/lib/server/decisioning/platform.js.map +1 -0
  101. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +510 -0
  102. package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -0
  103. package/dist/lib/server/decisioning/runtime/from-platform.js +2196 -0
  104. package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -0
  105. package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts +114 -0
  106. package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts.map +1 -0
  107. package/dist/lib/server/decisioning/runtime/postgres-task-registry.js +247 -0
  108. package/dist/lib/server/decisioning/runtime/postgres-task-registry.js.map +1 -0
  109. package/dist/lib/server/decisioning/runtime/protocol-for-tool.d.ts +32 -0
  110. package/dist/lib/server/decisioning/runtime/protocol-for-tool.d.ts.map +1 -0
  111. package/dist/lib/server/decisioning/runtime/protocol-for-tool.js +127 -0
  112. package/dist/lib/server/decisioning/runtime/protocol-for-tool.js.map +1 -0
  113. package/dist/lib/server/decisioning/runtime/task-registry.d.ts +105 -0
  114. package/dist/lib/server/decisioning/runtime/task-registry.d.ts.map +1 -0
  115. package/dist/lib/server/decisioning/runtime/task-registry.js +96 -0
  116. package/dist/lib/server/decisioning/runtime/task-registry.js.map +1 -0
  117. package/dist/lib/server/decisioning/runtime/to-context.d.ts +54 -0
  118. package/dist/lib/server/decisioning/runtime/to-context.d.ts.map +1 -0
  119. package/dist/lib/server/decisioning/runtime/to-context.js +166 -0
  120. package/dist/lib/server/decisioning/runtime/to-context.js.map +1 -0
  121. package/dist/lib/server/decisioning/runtime/validate-platform.d.ts +20 -0
  122. package/dist/lib/server/decisioning/runtime/validate-platform.d.ts.map +1 -0
  123. package/dist/lib/server/decisioning/runtime/validate-platform.js +93 -0
  124. package/dist/lib/server/decisioning/runtime/validate-platform.js.map +1 -0
  125. package/dist/lib/server/decisioning/specialisms/audiences.d.ts +72 -0
  126. package/dist/lib/server/decisioning/specialisms/audiences.d.ts.map +1 -0
  127. package/dist/lib/server/decisioning/specialisms/audiences.js +15 -0
  128. package/dist/lib/server/decisioning/specialisms/audiences.js.map +1 -0
  129. package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts +92 -0
  130. package/dist/lib/server/decisioning/specialisms/brand-rights.d.ts.map +1 -0
  131. package/dist/lib/server/decisioning/specialisms/brand-rights.js +28 -0
  132. package/dist/lib/server/decisioning/specialisms/brand-rights.js.map +1 -0
  133. package/dist/lib/server/decisioning/specialisms/campaign-governance.d.ts +67 -0
  134. package/dist/lib/server/decisioning/specialisms/campaign-governance.d.ts.map +1 -0
  135. package/dist/lib/server/decisioning/specialisms/campaign-governance.js +31 -0
  136. package/dist/lib/server/decisioning/specialisms/campaign-governance.js.map +1 -0
  137. package/dist/lib/server/decisioning/specialisms/content-standards.d.ts +78 -0
  138. package/dist/lib/server/decisioning/specialisms/content-standards.d.ts.map +1 -0
  139. package/dist/lib/server/decisioning/specialisms/content-standards.js +35 -0
  140. package/dist/lib/server/decisioning/specialisms/content-standards.js.map +1 -0
  141. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts +81 -0
  142. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts.map +1 -0
  143. package/dist/lib/server/decisioning/specialisms/creative-ad-server.js +28 -0
  144. package/dist/lib/server/decisioning/specialisms/creative-ad-server.js.map +1 -0
  145. package/dist/lib/server/decisioning/specialisms/creative.d.ts +144 -0
  146. package/dist/lib/server/decisioning/specialisms/creative.d.ts.map +1 -0
  147. package/dist/lib/server/decisioning/specialisms/creative.js +19 -0
  148. package/dist/lib/server/decisioning/specialisms/creative.js.map +1 -0
  149. package/dist/lib/server/decisioning/specialisms/lists.d.ts +61 -0
  150. package/dist/lib/server/decisioning/specialisms/lists.d.ts.map +1 -0
  151. package/dist/lib/server/decisioning/specialisms/lists.js +30 -0
  152. package/dist/lib/server/decisioning/specialisms/lists.js.map +1 -0
  153. package/dist/lib/server/decisioning/specialisms/sales.d.ts +163 -0
  154. package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -0
  155. package/dist/lib/server/decisioning/specialisms/sales.js +64 -0
  156. package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -0
  157. package/dist/lib/server/decisioning/specialisms/signals.d.ts +64 -0
  158. package/dist/lib/server/decisioning/specialisms/signals.d.ts.map +1 -0
  159. package/dist/lib/server/decisioning/specialisms/signals.js +28 -0
  160. package/dist/lib/server/decisioning/specialisms/signals.js.map +1 -0
  161. package/dist/lib/server/decisioning/start-time.d.ts +76 -0
  162. package/dist/lib/server/decisioning/start-time.d.ts.map +1 -0
  163. package/dist/lib/server/decisioning/start-time.js +81 -0
  164. package/dist/lib/server/decisioning/start-time.js.map +1 -0
  165. package/dist/lib/server/decisioning/status-changes.d.ts +165 -0
  166. package/dist/lib/server/decisioning/status-changes.d.ts.map +1 -0
  167. package/dist/lib/server/decisioning/status-changes.js +131 -0
  168. package/dist/lib/server/decisioning/status-changes.js.map +1 -0
  169. package/dist/lib/server/decisioning/status-mappers.d.ts +46 -0
  170. package/dist/lib/server/decisioning/status-mappers.d.ts.map +1 -0
  171. package/dist/lib/server/decisioning/status-mappers.js +46 -0
  172. package/dist/lib/server/decisioning/status-mappers.js.map +1 -0
  173. package/dist/lib/server/decisioning/tenant-registry.d.ts +289 -0
  174. package/dist/lib/server/decisioning/tenant-registry.d.ts.map +1 -0
  175. package/dist/lib/server/decisioning/tenant-registry.js +503 -0
  176. package/dist/lib/server/decisioning/tenant-registry.js.map +1 -0
  177. package/dist/lib/server/express-adapter.d.ts +1 -1
  178. package/dist/lib/server/express-adapter.js +1 -1
  179. package/dist/lib/server/governance.d.ts +1 -1
  180. package/dist/lib/server/governance.js +1 -1
  181. package/dist/lib/server/idempotency/store.d.ts +1 -1
  182. package/dist/lib/server/idempotency/store.js +1 -1
  183. package/dist/lib/server/index.d.ts +9 -2
  184. package/dist/lib/server/index.d.ts.map +1 -1
  185. package/dist/lib/server/index.js +79 -4
  186. package/dist/lib/server/index.js.map +1 -1
  187. package/dist/lib/server/legacy/v5/index.d.ts +38 -0
  188. package/dist/lib/server/legacy/v5/index.d.ts.map +1 -0
  189. package/dist/lib/server/legacy/v5/index.js +60 -0
  190. package/dist/lib/server/legacy/v5/index.js.map +1 -0
  191. package/dist/lib/server/normalize-errors.d.ts +88 -0
  192. package/dist/lib/server/normalize-errors.d.ts.map +1 -0
  193. package/dist/lib/server/normalize-errors.js +146 -0
  194. package/dist/lib/server/normalize-errors.js.map +1 -0
  195. package/dist/lib/server/pick-safe-details.d.ts +90 -0
  196. package/dist/lib/server/pick-safe-details.d.ts.map +1 -0
  197. package/dist/lib/server/pick-safe-details.js +148 -0
  198. package/dist/lib/server/pick-safe-details.js.map +1 -0
  199. package/dist/lib/server/postgres-state-store.d.ts +1 -1
  200. package/dist/lib/server/postgres-state-store.js +1 -1
  201. package/dist/lib/server/responses.d.ts +38 -0
  202. package/dist/lib/server/responses.d.ts.map +1 -1
  203. package/dist/lib/server/responses.js +38 -0
  204. package/dist/lib/server/responses.js.map +1 -1
  205. package/dist/lib/server/state-store.d.ts +1 -1
  206. package/dist/lib/server/state-store.js +1 -1
  207. package/dist/lib/server/test-controller.d.ts +10 -3
  208. package/dist/lib/server/test-controller.d.ts.map +1 -1
  209. package/dist/lib/server/test-controller.js +10 -3
  210. package/dist/lib/server/test-controller.js.map +1 -1
  211. package/dist/lib/testing/comply-controller.d.ts +47 -1
  212. package/dist/lib/testing/comply-controller.d.ts.map +1 -1
  213. package/dist/lib/testing/comply-controller.js +11 -4
  214. package/dist/lib/testing/comply-controller.js.map +1 -1
  215. package/dist/lib/testing/index.d.ts +1 -1
  216. package/dist/lib/testing/index.d.ts.map +1 -1
  217. package/dist/lib/testing/index.js.map +1 -1
  218. package/dist/lib/testing/personas/index.d.ts +143 -0
  219. package/dist/lib/testing/personas/index.d.ts.map +1 -0
  220. package/dist/lib/testing/personas/index.js +190 -0
  221. package/dist/lib/testing/personas/index.js.map +1 -0
  222. package/dist/lib/testing/storyboard/index.d.ts +1 -1
  223. package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
  224. package/dist/lib/testing/storyboard/index.js +3 -2
  225. package/dist/lib/testing/storyboard/index.js.map +1 -1
  226. package/dist/lib/testing/storyboard/runner.d.ts +13 -0
  227. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
  228. package/dist/lib/testing/storyboard/runner.js +179 -7
  229. package/dist/lib/testing/storyboard/runner.js.map +1 -1
  230. package/dist/lib/types/adcp.d.ts.map +1 -1
  231. package/dist/lib/types/adcp.js +1 -0
  232. package/dist/lib/types/adcp.js.map +1 -1
  233. package/dist/lib/types/asset-instances.d.ts +1 -0
  234. package/dist/lib/types/asset-instances.d.ts.map +1 -1
  235. package/dist/lib/types/core.generated.d.ts +203 -98
  236. package/dist/lib/types/core.generated.d.ts.map +1 -1
  237. package/dist/lib/types/core.generated.js +1 -1
  238. package/dist/lib/types/index.d.ts +1 -0
  239. package/dist/lib/types/index.d.ts.map +1 -1
  240. package/dist/lib/types/index.js.map +1 -1
  241. package/dist/lib/types/schemas.generated.d.ts +599 -159
  242. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  243. package/dist/lib/types/schemas.generated.js +175 -94
  244. package/dist/lib/types/schemas.generated.js.map +1 -1
  245. package/dist/lib/types/tools.generated.d.ts +315 -46
  246. package/dist/lib/types/tools.generated.d.ts.map +1 -1
  247. package/dist/lib/utils/capabilities.d.ts +1 -1
  248. package/dist/lib/utils/capabilities.d.ts.map +1 -1
  249. package/dist/lib/utils/capabilities.js +6 -0
  250. package/dist/lib/utils/capabilities.js.map +1 -1
  251. package/dist/lib/validation/schema-validator.d.ts +13 -0
  252. package/dist/lib/validation/schema-validator.d.ts.map +1 -1
  253. package/dist/lib/validation/schema-validator.js +240 -3
  254. package/dist/lib/validation/schema-validator.js.map +1 -1
  255. package/dist/lib/version.d.ts +3 -3
  256. package/dist/lib/version.d.ts.map +1 -1
  257. package/dist/lib/version.js +3 -3
  258. package/dist/lib/version.js.map +1 -1
  259. package/docs/guides/BUILD-AN-AGENT.md +30 -5
  260. package/docs/llms.txt +28 -17
  261. package/examples/README.md +3 -1
  262. package/examples/decisioning-platform-broadcast-tv.ts +300 -0
  263. package/examples/decisioning-platform-identity-graph.ts +214 -0
  264. package/examples/decisioning-platform-mock-seller.ts +332 -0
  265. package/examples/decisioning-platform-multi-tenant.ts +128 -0
  266. package/examples/decisioning-platform-programmatic.ts +254 -0
  267. package/examples/signals-agent.ts +1 -1
  268. package/package.json +13 -2
  269. package/skills/build-brand-rights-agent/SKILL.md +10 -3
  270. package/skills/build-creative-agent/SKILL.md +94 -64
  271. package/skills/build-decisioning-creative-template/SKILL.md +554 -0
  272. package/skills/build-decisioning-platform/SKILL.md +304 -0
  273. package/skills/build-decisioning-platform/advanced/BRAND-RIGHTS.md +25 -0
  274. package/skills/build-decisioning-platform/advanced/COMPLIANCE.md +23 -0
  275. package/skills/build-decisioning-platform/advanced/GOVERNANCE.md +24 -0
  276. package/skills/build-decisioning-platform/advanced/HITL.md +34 -0
  277. package/skills/build-decisioning-platform/advanced/IDEMPOTENCY.md +52 -0
  278. package/skills/build-decisioning-platform/advanced/MULTI-TENANT.md +47 -0
  279. package/skills/build-decisioning-platform/advanced/OAUTH.md +22 -0
  280. package/skills/build-decisioning-platform/advanced/REFERENCE.md +991 -0
  281. package/skills/build-decisioning-platform/advanced/SANDBOX.md +24 -0
  282. package/skills/build-decisioning-platform/advanced/STATE-MACHINE.md +52 -0
  283. package/skills/build-decisioning-signal-marketplace/SKILL.md +269 -0
  284. package/skills/build-generative-seller-agent/SKILL.md +89 -53
  285. package/skills/build-governance-agent/SKILL.md +76 -45
  286. package/skills/build-retail-media-agent/SKILL.md +87 -62
  287. package/skills/build-seller-agent/SKILL.md +384 -255
  288. package/skills/build-seller-agent/deployment.md +5 -3
  289. package/skills/build-seller-agent/specialisms/audience-sync.md +0 -2
  290. package/skills/build-seller-agent/specialisms/sales-broadcast-tv.md +0 -2
  291. package/skills/build-seller-agent/specialisms/sales-guaranteed.md +0 -2
  292. package/skills/build-seller-agent/specialisms/sales-non-guaranteed.md +0 -2
  293. package/skills/build-seller-agent/specialisms/sales-proposal-mode.md +0 -2
  294. package/skills/build-seller-agent/specialisms/sales-social.md +0 -2
  295. package/skills/build-seller-agent/specialisms/signed-requests.md +0 -2
  296. package/skills/build-si-agent/SKILL.md +40 -32
  297. package/skills/build-signals-agent/SKILL.md +139 -92
  298. package/skills/call-adcp-agent.previous/SKILL.md +5 -0
@@ -0,0 +1,304 @@
1
+ ---
2
+ name: build-decisioning-platform
3
+ description: Build an AdCP sales agent (publisher / SSP / retail-media network). Implement 5 functions, throw 8 typed errors, run it. Framework handles idempotency, HITL, signing, multi-tenant, schema validation.
4
+ ---
5
+
6
+ # Build a sales agent
7
+
8
+ Implement 6 functions. The framework does the rest.
9
+
10
+ ## What you're building
11
+
12
+ A `DecisioningPlatform` for the `sales-non-guaranteed` (or `sales-guaranteed`) specialism. Buyers call your AdCP server to discover products, create media buys, push creatives, update buys, and pull delivery reports. You translate those calls to your platform (GAM, FreeWheel, Kevel, your own ad server, whatever).
13
+
14
+ ## Imports cheat sheet
15
+
16
+ For 95% of sales agents, these are the only `@adcp/sdk/server` imports you need:
17
+
18
+ ```ts
19
+ import {
20
+ // Server entry + persistence
21
+ createAdcpServerFromPlatform, getAllAdcpMigrations, serve,
22
+ // Wire-shape helpers (eliminate 30+ lines of boilerplate per Product)
23
+ buildProduct, buildPackage, buildPricingOption,
24
+ // Typed errors — pick from this catalog instead of `throw new AdcpError(...)`
25
+ PackageNotFoundError, MediaBuyNotFoundError, ProductNotFoundError,
26
+ BudgetTooLowError, BackwardsTimeRangeError, InvalidStateError,
27
+ RateLimitedError, UnsupportedFeatureError,
28
+ // Types
29
+ type DecisioningPlatform, type SalesPlatform,
30
+ } from '@adcp/sdk/server';
31
+ ```
32
+
33
+ For other agent shapes:
34
+ - **Creative agent (template / generative):** swap `SalesPlatform` for `CreativeBuilderPlatform`
35
+ - **Signals agent:** swap for `SignalsPlatform`
36
+ - **Brand-rights agent:** swap for `BrandRightsPlatform`
37
+ - **Multi-tenant host:** add `createTenantRegistry`
38
+
39
+ The full export list is in `@adcp/sdk/server`. Many surfaces are marked `@deprecated` (legacy v5 response builders, old MCP task helpers) — your IDE will strikethrough them. Trust the strikethrough.
40
+
41
+ ## When you need...
42
+
43
+ - HITL flows (operator approval, async creative review) → `advanced/HITL.md`
44
+ - Multi-tenant hosting → `advanced/MULTI-TENANT.md`
45
+ - OAuth / OIDC authentication → `advanced/OAUTH.md`
46
+ - Sandbox / test-mode routing → `advanced/SANDBOX.md`
47
+ - Compliance test scenarios (`comply_test_controller`) → `advanced/COMPLIANCE.md`
48
+ - Campaign governance specialism → `advanced/GOVERNANCE.md`
49
+ - Brand rights specialism → `advanced/BRAND-RIGHTS.md`
50
+ - Replay TTL / idempotency principal tuning → `advanced/IDEMPOTENCY.md`
51
+ - State machine transitions (`pending_creatives` → `active`) → `advanced/STATE-MACHINE.md`
52
+ - Postgres operations / sizing / indices / cleanup → `../../docs/guides/POSTGRES.md`
53
+ - Edge cases / full reference → `advanced/REFERENCE.md`
54
+
55
+ ## The 6 functions
56
+
57
+ ```ts
58
+ import {
59
+ createAdcpServerFromPlatform,
60
+ createCtxMetadataStore, memoryCtxMetadataStore,
61
+ PackageNotFoundError, MediaBuyNotFoundError, ProductNotFoundError,
62
+ BudgetTooLowError, BackwardsTimeRangeError, InvalidStateError,
63
+ type DecisioningPlatform, type SalesPlatform,
64
+ } from '@adcp/sdk/server';
65
+
66
+ class MyPlatform implements DecisioningPlatform {
67
+ capabilities = {
68
+ adcp_version: '3.0.0',
69
+ specialisms: ['sales-non-guaranteed'] as const,
70
+ pricingModels: ['cpm'] as const,
71
+ channels: ['display', 'video'] as const, // strict literal-union — TS catches typos
72
+ formats: [{ format_id: 'display_300x250' }],
73
+ idempotency: { replay_ttl_seconds: 86400 },
74
+ };
75
+
76
+ accounts = {
77
+ resolution: 'derived' as const, // single tenant; framework returns the same Account every call
78
+ resolve: async () => ({ id: 'pub_main', operator: 'mypub', ctx_metadata: {} }),
79
+ upsert: async () => ({ ok: true, items: [] }),
80
+ list: async () => ({ items: [], nextCursor: null }),
81
+ };
82
+
83
+ sales: SalesPlatform = {
84
+ // 1. Catalog lookup. Brief in, products out.
85
+ getProducts: async (req, ctx) => {
86
+ const products = await this.platform.searchInventory(req.brief, req.promoted_offering);
87
+ return {
88
+ products: products.map(p => ({
89
+ product_id: p.id,
90
+ name: p.name,
91
+ format_ids: p.formatIds.map(id => ({ id })),
92
+ delivery_type: 'non_guaranteed',
93
+ pricing_options: [{ pricing_option_id: `${p.id}-cpm`, model: 'cpm', floor: { amount: p.floor, currency: 'USD' } }],
94
+ ctx_metadata: { gam: { ad_unit_ids: p.adUnitIds } }, // stashed; framework round-trips
95
+ })),
96
+ };
97
+ },
98
+
99
+ // 2. Create a buy. Sync path; HITL is `ctx.handoffToTask` (see advanced/HITL.md).
100
+ // SDK auto-hydrates each pkg.product with the resolved Product (incl. ctx_metadata)
101
+ // from the prior getProducts call — no separate lookup needed.
102
+ //
103
+ // CONTRACT — `pkg.product` is `undefined` when SDK has no record of that product_id.
104
+ // That's NOT authoritative "doesn't exist" — the SDK store is a cache, and your
105
+ // publisher's DB might still have it. Decision tree when undefined:
106
+ // - Have your own product DB → look up there; throw `ProductNotFoundError(pkg.product_id)`
107
+ // only if YOUR DB also returns nothing.
108
+ // - Pure-SDK store (no own DB) → throw `ProductNotFoundError(pkg.product_id)` immediately.
109
+ // - Either way: never let `undefined` flow downstream silently.
110
+ createMediaBuy: async (req, ctx) => {
111
+ if (new Date(req.start_time) >= new Date(req.end_time)) throw new BackwardsTimeRangeError();
112
+ if (req.total_budget?.amount < 1000) throw new BudgetTooLowError({ floor: 1000, currency: 'USD' });
113
+
114
+ const lineItems = [];
115
+ for (const pkg of req.packages) {
116
+ if (!pkg.product) throw new ProductNotFoundError(pkg.product_id);
117
+ // pkg.product is the full Product from getProducts, with adapter-internal config attached:
118
+ const adUnits = pkg.product.ctx_metadata?.gam?.ad_unit_ids ?? [];
119
+ const formats = pkg.product.format_ids;
120
+ lineItems.push(await this.platform.createLineItem(pkg, { adUnits, formats }));
121
+ }
122
+ const order = await this.platform.createOrder(req, lineItems);
123
+
124
+ // Stash your platform's IDs so subsequent updateMediaBuy can hydrate them too.
125
+ return {
126
+ media_buy_id: order.id,
127
+ status: 'pending_creatives', // creative state machine — see advanced/STATE-MACHINE.md
128
+ ctx_metadata: { gam_order_id: order.gamOrderId }, // SDK persists; subsequent updateMediaBuy gets req.ctx_metadata.gam_order_id
129
+ packages: order.lineItems.map(li => ({
130
+ package_id: li.id,
131
+ status: 'pending_creatives',
132
+ buyer_ref: li.buyerRef,
133
+ ctx_metadata: { gam_line_item_id: li.gamLineItemId },
134
+ })),
135
+ };
136
+ },
137
+
138
+ // 3. Update a buy. SDK auto-hydrates the resolved MediaBuy (and its packages,
139
+ // each with ctx_metadata) at req.mediaBuy when present in the store from a
140
+ // prior createMediaBuy / getMediaBuys call. Falls back gracefully if absent
141
+ // (publisher uses their own DB).
142
+ // (6.2 will pre-read state + decompose into atomic verbs; track adcp-client#1071.)
143
+ updateMediaBuy: async (mediaBuyId, patch, ctx) => {
144
+ const orderMeta = await ctx.ctxMetadata?.mediaBuy(mediaBuyId);
145
+ if (!orderMeta) throw new MediaBuyNotFoundError(mediaBuyId);
146
+
147
+ for (const pkg of patch.packages ?? []) {
148
+ const pkgMeta = await ctx.ctxMetadata?.package(pkg.package_id);
149
+ if (!pkgMeta) throw new PackageNotFoundError(pkg.package_id);
150
+ await this.platform.updateLineItem(pkgMeta.gam_line_item_id, pkg);
151
+ }
152
+ const order = await this.platform.getOrder(orderMeta.gam_order_id);
153
+ return this.toMediaBuy(order);
154
+ },
155
+
156
+ // 4. Push creatives. Returns one row per creative with action + status.
157
+ syncCreatives: async (creatives, ctx) => {
158
+ const out = [];
159
+ for (const c of creatives) {
160
+ const native = await this.platform.upsertCreative(c);
161
+ await ctx.ctxMetadata?.set('creative', c.creative_id, { gam_creative_id: native.id });
162
+ out.push({ creative_id: c.creative_id, action: 'created', status: 'approved' });
163
+ }
164
+ return out;
165
+ },
166
+
167
+ // 5. List buys this account owns. REQUIRED — non-negotiable. Every seller
168
+ // needs to support reading back what they created. SDK auto-stores
169
+ // returned buys for hydration on subsequent updateMediaBuy calls.
170
+ //
171
+ // WRITE-ONLY ADOPTERS (proposal-mode push-channel sellers, retail-media
172
+ // flows that deliver via webhook): return `{ media_buys: [] }`. Never
173
+ // lie — empty array is truthful "no buys to enumerate via this surface."
174
+ // Buyers asking for a list get an empty answer. Don't omit the method
175
+ // or stub-throw; just return empty.
176
+ getMediaBuys: async (req, ctx) => {
177
+ const buys = await this.platform.listOrders({ accountId: ctx.account.id, status: req.status });
178
+ return {
179
+ media_buys: buys.map(buy => ({
180
+ media_buy_id: buy.id,
181
+ status: this.statusMappers.mediaBuy(buy.nativeStatus),
182
+ buyer_ref: buy.buyerRef,
183
+ total_budget: { amount: buy.budgetAmount, currency: buy.currency }, // REQUIRED on the wire shape
184
+ start_time: buy.startTime,
185
+ end_time: buy.endTime,
186
+ packages: buy.lineItems.map(li => ({
187
+ package_id: li.id,
188
+ status: this.statusMappers.mediaBuy(li.nativeStatus),
189
+ buyer_ref: li.buyerRef,
190
+ ctx_metadata: { gam_line_item_id: li.gamLineItemId }, // round-trip publisher state
191
+ })),
192
+ ctx_metadata: { gam_order_id: buy.gamOrderId },
193
+ })),
194
+ };
195
+ },
196
+
197
+ // 6. Delivery report.
198
+ getMediaBuyDelivery: async (filter, ctx) => ({ deliveries: await this.platform.fetchReports(filter) }),
199
+ };
200
+
201
+ constructor(private platform: MyAdServer) {}
202
+ }
203
+ ```
204
+
205
+ That's the agent. Five functions. The framework wires the wire protocol around it (MCP tools, A2A skill manifest, idempotency, schema validation, HITL task envelopes, RFC 9421 webhook signing, multi-tenant routing).
206
+
207
+ ## Errors you throw — pick from the import list
208
+
209
+ ```ts
210
+ import {
211
+ PackageNotFoundError, // wrong package_id on update
212
+ MediaBuyNotFoundError, // wrong media_buy_id
213
+ ProductNotFoundError, // wrong product_id on create
214
+ ProductUnavailableError, // product exists but sold out
215
+ CreativeNotFoundError, // wrong creative_id
216
+ CreativeRejectedError, // brand-safety failed, etc.
217
+ BudgetTooLowError, // under floor (correctable — buyer raises)
218
+ BudgetExhaustedError, // pacing burst hit cap
219
+ IdempotencyConflictError, // same key, different payload
220
+ InvalidRequestError, // generic field-level bad input
221
+ InvalidStateError, // illegal transition (paused → archived violations)
222
+ BackwardsTimeRangeError, // start_time >= end_time
223
+ AuthRequiredError, // need auth, then retry
224
+ PermissionDeniedError, // auth present, lacks scope
225
+ RateLimitedError, // throttled (clamps retry_after to [1, 3600])
226
+ UnsupportedFeatureError, // tool unimplemented
227
+ ComplianceUnsatisfiedError, // brand-safety attestation missing
228
+ GovernanceDeniedError, // spending authority revoked
229
+ PolicyViolationError, // categorical content rejection
230
+ } from '@adcp/sdk/server';
231
+ ```
232
+
233
+ Each class encodes the right `code` / `recovery` / `field` shape. **Don't throw generic `Error`** — the framework catches that and maps to `SERVICE_UNAVAILABLE`, which the buyer can't pattern-match.
234
+
235
+ ## Persisting platform state — `ctx.ctxMetadata`
236
+
237
+ Your platform has IDs (GAM order_id, line_item_id) that AdCP doesn't model. Stash them once, read them on subsequent calls. The framework round-trips per `(account.id, kind, id)` and strips from buyer-facing wire payloads.
238
+
239
+ ```ts
240
+ // Wire a store at server construction:
241
+ import { createCtxMetadataStore, memoryCtxMetadataStore, pgCtxMetadataStore, getCtxMetadataMigration } from '@adcp/sdk/server';
242
+
243
+ await pool.query(getCtxMetadataMigration()); // Postgres only
244
+ const ctxMetadata = createCtxMetadataStore({ backend: pgCtxMetadataStore(pool) });
245
+
246
+ // Stash in any handler return:
247
+ await ctx.ctxMetadata?.set('product', productId, { gam: { ad_unit_ids: [...] } });
248
+
249
+ // Read in a later handler:
250
+ const meta = await ctx.ctxMetadata?.product(productId);
251
+ ```
252
+
253
+ **Memory backend:** fine for dev; use Postgres in cluster — silent loss after rolling restart produces "package not found" errors that look like publisher bugs and run for weeks.
254
+
255
+ **Account scoping is automatic.** `ctx.ctxMetadata` binds to `ctx.account.id` per request. No-account tools (`provide_performance_feedback`, `list_creative_formats`) get `ctx.ctxMetadata = undefined` — branch defensively.
256
+
257
+ ## Run it
258
+
259
+ ```ts
260
+ import { Pool } from 'pg';
261
+ import {
262
+ createAdcpServerFromPlatform,
263
+ getAllAdcpMigrations,
264
+ serve,
265
+ } from '@adcp/sdk/server';
266
+
267
+ const pool = new Pool({ connectionString: process.env.DATABASE_URL });
268
+ await pool.query(getAllAdcpMigrations()); // one DDL call, all 3 tables
269
+
270
+ const platform = new MyPlatform(myAdServer);
271
+ const server = createAdcpServerFromPlatform(platform, {
272
+ name: 'My Sales Agent',
273
+ version: '1.0.0',
274
+ pool, // wires idempotency + ctxMetadata + taskRegistry
275
+ });
276
+
277
+ serve(() => server, { port: process.env.PORT });
278
+ ```
279
+
280
+ That's the whole bootstrap. **One pool, one migration, three persistence concerns wired by the framework.**
281
+
282
+ For dev / single-process: omit `pool` entirely. Framework defaults to in-memory backends. Don't ship that to production — silent state loss after rolling restart produces "package not found" errors that look like publisher bugs and run for weeks.
283
+
284
+ ## Operator checklist
285
+
286
+ Things you set up once at deploy time:
287
+
288
+ - [ ] `DATABASE_URL` env var pointing at your Postgres instance
289
+ - [ ] Run `getAllAdcpMigrations()` once per database (idempotent — safe to re-run)
290
+ - [ ] OAuth provider config — see `advanced/OAUTH.md` if buyers authenticate via OIDC
291
+ - [ ] `ADCP_VERSION` env (default `3.0.0`) if pinning a specific spec version
292
+
293
+ ## See also
294
+
295
+ - `advanced/HITL.md` — long-running tools (creative review, manual approval). Use `ctx.handoffToTask(fn)`.
296
+ - `advanced/MULTI-TENANT.md` — `TenantRegistry` for one-process-many-publishers.
297
+ - `advanced/OAUTH.md` — auth providers (OIDC client_credentials, etc.).
298
+ - `advanced/SANDBOX.md` — test-mode routing via `AccountReference.sandbox`.
299
+ - `advanced/COMPLIANCE.md` — `comply_test_controller` for storyboard-driven QA.
300
+ - `advanced/GOVERNANCE.md` — `campaign-governance` specialism.
301
+ - `advanced/BRAND-RIGHTS.md` — `brand-rights` specialism.
302
+ - `advanced/IDEMPOTENCY.md` — replay TTL / principal resolver tuning.
303
+ - `advanced/STATE-MACHINE.md` — `pending_creatives` → `pending_start` → `active` transitions.
304
+ - `advanced/REFERENCE.md` — full reference (everything above + edge cases + design rationale).
@@ -0,0 +1,25 @@
1
+ # Brand rights specialism
2
+
3
+ If you claim `brand-rights`, implement `BrandRightsPlatform`. Buyers call to discover brand identity, query rights, and acquire rights for creative production.
4
+
5
+ ```ts
6
+ class MyPlatform implements DecisioningPlatform {
7
+ capabilities = {
8
+ specialisms: ['brand-rights'] as const,
9
+ brand: { /* BrandCapabilities — see REFERENCE.md for shape */ },
10
+ ...
11
+ };
12
+
13
+ brandRights: BrandRightsPlatform = {
14
+ getBrandIdentity: async (req, ctx) => { ... },
15
+ getRights: async (req, ctx) => { ... },
16
+ acquireRights: async (req, ctx) => {
17
+ // Returns one of three native arms — Acquired / PendingApproval / Rejected
18
+ },
19
+ };
20
+ }
21
+ ```
22
+
23
+ Async delivery for the `PendingApproval` arm rides the buyer's `push_notification_config.url`. There's no polling tool for `acquire_rights` — webhook is the only delivery channel.
24
+
25
+ See `REFERENCE.md` for the full brand-rights section + the 3-arm wire shape.
@@ -0,0 +1,23 @@
1
+ # Compliance testing — `comply_test_controller`
2
+
3
+ Adopters who claim `compliance_testing` capability get a wire tool the AdCP storyboard runner uses to drive deterministic test scenarios (seed products, force creative statuses, simulate delivery, etc.).
4
+
5
+ ```ts
6
+ import { createComplyController } from '@adcp/sdk/testing';
7
+
8
+ createAdcpServerFromPlatform(platform, {
9
+ name: '...', version: '...',
10
+ complyTest: {
11
+ sandboxGate: (input) => input.account?.sandbox === true, // ONLY in sandbox accounts
12
+ seed: { product: async (input) => seedProductFixture(input) },
13
+ force: { creative_status: async (input) => forceStatus(input) },
14
+ simulate: { delivery: async (input) => simulateDelivery(input) },
15
+ },
16
+ });
17
+ ```
18
+
19
+ Framework auto-projects `capabilities.compliance_testing.scenarios` to `get_adcp_capabilities` based on which adapters you wired.
20
+
21
+ Production agents typically gate registration on `process.env.ADCP_SANDBOX === '1'` so the tool isn't reachable in prod tools/list.
22
+
23
+ See `REFERENCE.md` for the full compliance-testing section.
@@ -0,0 +1,24 @@
1
+ # Campaign governance specialism
2
+
3
+ If you claim `governance-spend-authority` or `governance-delivery-monitor`, implement `CampaignGovernancePlatform`. Buyers call governance tools to delegate spending authority, monitor delivery against caps, and revoke authority when caps are breached.
4
+
5
+ ```ts
6
+ class MyPlatform implements DecisioningPlatform {
7
+ capabilities = {
8
+ specialisms: ['sales-non-guaranteed', 'governance-spend-authority'] as const,
9
+ ...
10
+ };
11
+
12
+ campaignGovernance: CampaignGovernancePlatform = {
13
+ grantSpendAuthority: async (req, ctx) => { /* mint a JWS */ },
14
+ revokeSpendAuthority: async (req, ctx) => { /* revoke + emit status change */ },
15
+ getDeliveryAttestation: async (req, ctx) => { /* aggregate delivery vs cap */ },
16
+ };
17
+ }
18
+ ```
19
+
20
+ Framework owns JWS verification on inbound `governance_context` tokens; you receive `ctx.state.governanceContext()` already verified, plan-bound, and seller-bound.
21
+
22
+ Throw `GovernanceDeniedError` for revoked authority, `ComplianceUnsatisfiedError` for delivery cap breaches.
23
+
24
+ See `REFERENCE.md` for the full governance section.
@@ -0,0 +1,34 @@
1
+ # HITL — long-running tools
2
+
3
+ When a tool can't return synchronously (operator approval, expensive report, brand-safety review), promote the call to a background task with `ctx.handoffToTask(fn)`. Framework returns the spec-defined `Submitted` envelope to the buyer immediately and runs `fn` in the background.
4
+
5
+ ## Pattern
6
+
7
+ ```ts
8
+ import { AdcpError } from '@adcp/sdk/server';
9
+
10
+ createMediaBuy: async (req, ctx) => {
11
+ if (this.requiresOperatorApproval(req)) {
12
+ return ctx.handoffToTask(async (taskCtx) => {
13
+ await taskCtx.update({ message: 'Awaiting trafficker' });
14
+ const order = await this.runApprovalFlow(req); // can take hours
15
+ return { media_buy_id: order.id, status: 'pending_creatives', packages: ... };
16
+ });
17
+ }
18
+ return await this.commitSync(req);
19
+ }
20
+ ```
21
+
22
+ ## What the framework does
23
+
24
+ 1. Detects the `TaskHandoff` marker on your return.
25
+ 2. Allocates a `task_id`, returns `{ task_id, status: 'submitted' }` to the buyer.
26
+ 3. Runs your handoff `fn` in the background.
27
+ 4. `fn`'s return value becomes the task's terminal `result`. Thrown `AdcpError` becomes terminal `error`.
28
+ 5. Buyer polls `tasks_get` OR receives a webhook (if they passed `push_notification_config.url` in the request).
29
+
30
+ ## When a tool is HITL-capable
31
+
32
+ Only tools whose wire response defines a `Submitted` arm: `create_media_buy`, `sync_creatives`. Other tools (`update_media_buy`, `get_products`) are sync-only — operator re-approval flows surface eventual transitions via `publishStatusChange(...)` rather than HITL on the call itself.
33
+
34
+ See `REFERENCE.md` for the full HITL section + hybrid-seller patterns + `taskHandoff.notify` semantics.
@@ -0,0 +1,52 @@
1
+ # Idempotency — replay TTL and principal resolver
2
+
3
+ Framework handles replay/dedup automatically. You don't write idempotency logic in your handlers.
4
+
5
+ ## What you don't have to do
6
+
7
+ - Hash request payloads
8
+ - Cache responses
9
+ - Detect replay-with-same-payload vs replay-with-different-payload conflicts
10
+ - Translate replays into the `replayed: true` envelope marker
11
+
12
+ The framework owns all of this via `createIdempotencyStore` (memory or Postgres backend). Run `getIdempotencyMigration()` once per database in production.
13
+
14
+ ## When you might need to override
15
+
16
+ The framework synthesizes a default `resolveIdempotencyPrincipal` from `auth.client_id ?? sessionKey ?? account.id`. That covers the standard case (multi-tenant: each authenticated buyer gets its own idempotency namespace; single-tenant: one shared namespace).
17
+
18
+ Override only if your auth shape is unusual:
19
+
20
+ ```ts
21
+ createAdcpServerFromPlatform(platform, {
22
+ name: '...', version: '...',
23
+ resolveIdempotencyPrincipal: (ctx) => ctx.authInfo?.subjectClaim ?? ctx.account?.id,
24
+ });
25
+ ```
26
+
27
+ ## Replay TTL
28
+
29
+ Default is 86400s (24h). Spec range: 3600 (1h) to 604800 (7d). Out-of-range throws at construction.
30
+
31
+ ```ts
32
+ const idempotency = createIdempotencyStore({
33
+ backend: pgBackend(pool),
34
+ ttlSeconds: 86400, // 24h
35
+ });
36
+ createAdcpServerFromPlatform(platform, { name: '...', version: '...', idempotency, ... });
37
+ ```
38
+
39
+ Capability projection automatic: framework declares `replay_ttl_seconds` on `get_adcp_capabilities` so buyers can reason about retry safety.
40
+
41
+ ## Conflict semantics
42
+
43
+ If a buyer reuses an idempotency_key with a different payload, framework throws `IDEMPOTENCY_CONFLICT` automatically — you don't catch this. Buyer corrects with a fresh key.
44
+
45
+ Production-only flag: in tests / dev, your handler may throw `IdempotencyConflictError` directly to simulate the path:
46
+
47
+ ```ts
48
+ import { IdempotencyConflictError } from '@adcp/sdk/server';
49
+ throw new IdempotencyConflictError({ details: { test_simulation: true } });
50
+ ```
51
+
52
+ See `REFERENCE.md` for the full idempotency section.
@@ -0,0 +1,47 @@
1
+ # Multi-tenant hosting — TenantRegistry
2
+
3
+ When one process hosts many publishers (typical SaaS deployment), use `createTenantRegistry` — wraps `createAdcpServerFromPlatform` with per-tenant config, health gates, and JWKS validation.
4
+
5
+ ```ts
6
+ import { createTenantRegistry, serve } from '@adcp/sdk/server';
7
+
8
+ const registry = createTenantRegistry({
9
+ resolveTenant: async (req) => {
10
+ // Map host header / OAuth subject / path prefix to a tenant id
11
+ return { tenantId: extractTenantFromHost(req.headers.host) };
12
+ },
13
+ buildPlatform: async (tenantId) => {
14
+ // Load tenant config from your DB
15
+ const tenantConfig = await loadTenant(tenantId);
16
+ return new MyPlatform(tenantConfig);
17
+ },
18
+ // Health gates: 'healthy' / 'unverified' / 'disabled'
19
+ // Disabled tenants get 503 SERVICE_UNAVAILABLE without invoking the platform.
20
+ });
21
+
22
+ serve(registry.host, { port: process.env.PORT });
23
+ ```
24
+
25
+ ## Per-tenant config
26
+
27
+ Each tenant can override `capabilities.config` independently:
28
+
29
+ ```ts
30
+ buildPlatform: async (tenantId) => {
31
+ const cfg = await loadTenant(tenantId);
32
+ return {
33
+ capabilities: {
34
+ ...,
35
+ config: { networkId: cfg.gamNetworkId, manualApprovalOperations: cfg.approvalOps },
36
+ },
37
+ accounts: { ... },
38
+ sales: { ... },
39
+ };
40
+ };
41
+ ```
42
+
43
+ ## Per-tenant ctxMetadata
44
+
45
+ Each `createAdcpServerFromPlatform` call gets its own `ctxMetadataStore` instance — multi-tenant hosts pass per-tenant store handles, not a shared one. Account scoping handles the rest (`account.id` in the storage key).
46
+
47
+ See `REFERENCE.md` for the full multi-tenant section + admin router for ops visibility.
@@ -0,0 +1,22 @@
1
+ # OAuth provider wiring
2
+
3
+ If buyers authenticate via OIDC `client_credentials`, wire an introspection callback so the framework resolves `auth.client_id` from incoming bearer tokens.
4
+
5
+ ```ts
6
+ import { serve, verifyIntrospection } from '@adcp/sdk/server';
7
+
8
+ serve(() => server, {
9
+ port,
10
+ authenticate: verifyIntrospection({
11
+ introspectionUrl: process.env.OIDC_INTROSPECTION_URL,
12
+ clientId: process.env.OIDC_CLIENT_ID,
13
+ clientSecret: process.env.OIDC_CLIENT_SECRET,
14
+ }),
15
+ });
16
+ ```
17
+
18
+ Framework projects `auth.client_id` → `ctx.authInfo.clientId` in your handlers, and into the default idempotency principal resolver.
19
+
20
+ For multi-tenant deployments where each tenant has its own OIDC issuer, see `MULTI-TENANT.md` (resolveTenant uses the issuer to route).
21
+
22
+ See `REFERENCE.md` for full OAuth section.