@adcp/sdk 13.0.0-rc.8 → 13.0.0-rc.9

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 (200) hide show
  1. package/dist/lib/adapters/roster-account-store.d.mts +9 -8
  2. package/dist/lib/adapters/roster-account-store.d.ts +9 -8
  3. package/dist/lib/adapters/roster-account-store.d.ts.map +1 -1
  4. package/dist/lib/adapters/roster-account-store.js +2 -1
  5. package/dist/lib/adapters/roster-account-store.js.map +1 -1
  6. package/dist/lib/adapters/roster-account-store.mjs +2 -1
  7. package/dist/lib/adapters/roster-account-store.mjs.map +1 -1
  8. package/dist/lib/net/address-guards.d.ts.map +1 -1
  9. package/dist/lib/net/address-guards.js +6 -0
  10. package/dist/lib/net/address-guards.js.map +1 -1
  11. package/dist/lib/net/address-guards.mjs +6 -0
  12. package/dist/lib/net/address-guards.mjs.map +1 -1
  13. package/dist/lib/net/ssrf-fetch.d.ts.map +1 -1
  14. package/dist/lib/net/ssrf-fetch.js +66 -53
  15. package/dist/lib/net/ssrf-fetch.js.map +1 -1
  16. package/dist/lib/net/ssrf-fetch.mjs +66 -53
  17. package/dist/lib/net/ssrf-fetch.mjs.map +1 -1
  18. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  19. package/dist/lib/server/account-mode.d.mts +2 -1
  20. package/dist/lib/server/account-mode.d.ts +2 -1
  21. package/dist/lib/server/account-mode.d.ts.map +1 -1
  22. package/dist/lib/server/account-mode.js +1 -0
  23. package/dist/lib/server/account-mode.js.map +1 -1
  24. package/dist/lib/server/account-mode.mjs +1 -0
  25. package/dist/lib/server/account-mode.mjs.map +1 -1
  26. package/dist/lib/server/create-adcp-server.d.mts +10 -6
  27. package/dist/lib/server/create-adcp-server.d.ts +10 -6
  28. package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
  29. package/dist/lib/server/create-adcp-server.js +2 -1
  30. package/dist/lib/server/create-adcp-server.js.map +1 -1
  31. package/dist/lib/server/create-adcp-server.mjs +2 -1
  32. package/dist/lib/server/create-adcp-server.mjs.map +1 -1
  33. package/dist/lib/server/decisioning/account.d.mts +16 -11
  34. package/dist/lib/server/decisioning/account.d.ts +16 -11
  35. package/dist/lib/server/decisioning/account.d.ts.map +1 -1
  36. package/dist/lib/server/decisioning/account.js.map +1 -1
  37. package/dist/lib/server/decisioning/account.mjs.map +1 -1
  38. package/dist/lib/server/decisioning/pagination.d.mts +2 -0
  39. package/dist/lib/server/decisioning/pagination.d.ts +2 -0
  40. package/dist/lib/server/decisioning/pagination.d.ts.map +1 -1
  41. package/dist/lib/server/decisioning/pagination.js.map +1 -1
  42. package/dist/lib/server/decisioning/runtime/from-platform.d.mts +20 -14
  43. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +20 -14
  44. package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
  45. package/dist/lib/server/decisioning/runtime/from-platform.js +32 -6
  46. package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
  47. package/dist/lib/server/decisioning/runtime/from-platform.mjs +32 -6
  48. package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
  49. package/dist/lib/server/decisioning/specialisms/sales.d.mts +16 -4
  50. package/dist/lib/server/decisioning/specialisms/sales.d.ts +16 -4
  51. package/dist/lib/server/decisioning/specialisms/sales.d.ts.map +1 -1
  52. package/dist/lib/server/decisioning/specialisms/sales.js.map +1 -1
  53. package/dist/lib/server/index.d.ts.map +1 -1
  54. package/dist/lib/server/index.js.map +1 -1
  55. package/dist/lib/server/index.mjs.map +1 -1
  56. package/dist/lib/server/legacy/v5/index.d.mts +2 -1
  57. package/dist/lib/server/legacy/v5/index.d.ts +2 -1
  58. package/dist/lib/server/legacy/v5/index.d.ts.map +1 -1
  59. package/dist/lib/server/legacy/v5/index.js.map +1 -1
  60. package/dist/lib/server/legacy/v5/index.mjs.map +1 -1
  61. package/dist/lib/testing/compliance/comply.d.mts +2 -0
  62. package/dist/lib/testing/compliance/comply.d.ts +2 -0
  63. package/dist/lib/testing/compliance/comply.d.ts.map +1 -1
  64. package/dist/lib/testing/compliance/comply.js +45 -14
  65. package/dist/lib/testing/compliance/comply.js.map +1 -1
  66. package/dist/lib/testing/compliance/comply.mjs +45 -14
  67. package/dist/lib/testing/compliance/comply.mjs.map +1 -1
  68. package/dist/lib/testing/compliance/index.d.mts +1 -1
  69. package/dist/lib/testing/compliance/index.d.ts +1 -1
  70. package/dist/lib/testing/compliance/index.d.ts.map +1 -1
  71. package/dist/lib/testing/compliance/index.js.map +1 -1
  72. package/dist/lib/testing/compliance/index.mjs.map +1 -1
  73. package/dist/lib/testing/compliance/storyboard-tracks.d.ts.map +1 -1
  74. package/dist/lib/testing/compliance/storyboard-tracks.js +9 -1
  75. package/dist/lib/testing/compliance/storyboard-tracks.js.map +1 -1
  76. package/dist/lib/testing/compliance/storyboard-tracks.mjs +9 -1
  77. package/dist/lib/testing/compliance/storyboard-tracks.mjs.map +1 -1
  78. package/dist/lib/testing/compliance/types.d.mts +26 -25
  79. package/dist/lib/testing/compliance/types.d.ts +26 -25
  80. package/dist/lib/testing/compliance/types.d.ts.map +1 -1
  81. package/dist/lib/testing/compliance/types.js.map +1 -1
  82. package/dist/lib/testing/index.d.mts +2 -2
  83. package/dist/lib/testing/index.d.ts +2 -2
  84. package/dist/lib/testing/index.d.ts.map +1 -1
  85. package/dist/lib/testing/index.js +16 -0
  86. package/dist/lib/testing/index.js.map +1 -1
  87. package/dist/lib/testing/index.mjs +16 -0
  88. package/dist/lib/testing/index.mjs.map +1 -1
  89. package/dist/lib/testing/scenarios/media-buy.d.ts.map +1 -1
  90. package/dist/lib/testing/scenarios/media-buy.js +20 -12
  91. package/dist/lib/testing/scenarios/media-buy.js.map +1 -1
  92. package/dist/lib/testing/scenarios/media-buy.mjs +20 -12
  93. package/dist/lib/testing/scenarios/media-buy.mjs.map +1 -1
  94. package/dist/lib/testing/storyboard/creative-assets.d.mts +23 -0
  95. package/dist/lib/testing/storyboard/creative-assets.d.ts +23 -0
  96. package/dist/lib/testing/storyboard/creative-assets.d.ts.map +1 -1
  97. package/dist/lib/testing/storyboard/creative-assets.js +322 -45
  98. package/dist/lib/testing/storyboard/creative-assets.js.map +1 -1
  99. package/dist/lib/testing/storyboard/creative-assets.mjs +321 -45
  100. package/dist/lib/testing/storyboard/creative-assets.mjs.map +1 -1
  101. package/dist/lib/testing/storyboard/index.d.mts +4 -1
  102. package/dist/lib/testing/storyboard/index.d.ts +4 -1
  103. package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
  104. package/dist/lib/testing/storyboard/index.js +20 -0
  105. package/dist/lib/testing/storyboard/index.js.map +1 -1
  106. package/dist/lib/testing/storyboard/index.mjs +19 -0
  107. package/dist/lib/testing/storyboard/index.mjs.map +1 -1
  108. package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.mts +21 -0
  109. package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.ts +22 -0
  110. package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.d.ts.map +1 -0
  111. package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.js +668 -0
  112. package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.js.map +1 -0
  113. package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.mjs +638 -0
  114. package/dist/lib/testing/storyboard/oauth-metadata-graph/grader.mjs.map +1 -0
  115. package/dist/lib/testing/storyboard/oauth-metadata-graph/index.d.mts +5 -0
  116. package/dist/lib/testing/storyboard/oauth-metadata-graph/index.d.ts +6 -0
  117. package/dist/lib/testing/storyboard/oauth-metadata-graph/index.d.ts.map +1 -0
  118. package/dist/lib/testing/storyboard/oauth-metadata-graph/index.js +44 -0
  119. package/dist/lib/testing/storyboard/oauth-metadata-graph/index.js.map +1 -0
  120. package/dist/lib/testing/storyboard/oauth-metadata-graph/index.mjs +20 -0
  121. package/dist/lib/testing/storyboard/oauth-metadata-graph/index.mjs.map +1 -0
  122. package/dist/lib/testing/storyboard/oauth-metadata-graph/types.d.mts +38 -0
  123. package/dist/lib/testing/storyboard/oauth-metadata-graph/types.d.ts +39 -0
  124. package/dist/lib/testing/storyboard/oauth-metadata-graph/types.d.ts.map +1 -0
  125. package/dist/lib/testing/storyboard/oauth-metadata-graph/types.js +17 -0
  126. package/dist/lib/testing/storyboard/oauth-metadata-graph/types.js.map +1 -0
  127. package/dist/lib/testing/storyboard/oauth-metadata-graph/types.mjs +1 -0
  128. package/dist/lib/testing/storyboard/oauth-metadata-graph/types.mjs.map +1 -0
  129. package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.d.mts +32 -0
  130. package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.d.ts +33 -0
  131. package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.d.ts.map +1 -0
  132. package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.js +105 -0
  133. package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.js.map +1 -0
  134. package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.mjs +80 -0
  135. package/dist/lib/testing/storyboard/oauth-metadata-graph/vector-loader.mjs.map +1 -0
  136. package/dist/lib/testing/storyboard/probes.d.ts.map +1 -1
  137. package/dist/lib/testing/storyboard/probes.js +2 -1
  138. package/dist/lib/testing/storyboard/probes.js.map +1 -1
  139. package/dist/lib/testing/storyboard/probes.mjs +2 -1
  140. package/dist/lib/testing/storyboard/probes.mjs.map +1 -1
  141. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
  142. package/dist/lib/testing/storyboard/runner.js +382 -69
  143. package/dist/lib/testing/storyboard/runner.js.map +1 -1
  144. package/dist/lib/testing/storyboard/runner.mjs +387 -70
  145. package/dist/lib/testing/storyboard/runner.mjs.map +1 -1
  146. package/dist/lib/testing/storyboard/seeding.js +3 -1
  147. package/dist/lib/testing/storyboard/seeding.js.map +1 -1
  148. package/dist/lib/testing/storyboard/seeding.mjs +3 -1
  149. package/dist/lib/testing/storyboard/seeding.mjs.map +1 -1
  150. package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -1
  151. package/dist/lib/testing/storyboard/task-map.js +16 -2
  152. package/dist/lib/testing/storyboard/task-map.js.map +1 -1
  153. package/dist/lib/testing/storyboard/task-map.mjs +16 -2
  154. package/dist/lib/testing/storyboard/task-map.mjs.map +1 -1
  155. package/dist/lib/testing/storyboard/trusted-match-context-replay.d.mts +11 -0
  156. package/dist/lib/testing/storyboard/trusted-match-context-replay.d.ts +12 -0
  157. package/dist/lib/testing/storyboard/trusted-match-context-replay.d.ts.map +1 -0
  158. package/dist/lib/testing/storyboard/trusted-match-context-replay.js +340 -0
  159. package/dist/lib/testing/storyboard/trusted-match-context-replay.js.map +1 -0
  160. package/dist/lib/testing/storyboard/trusted-match-context-replay.mjs +316 -0
  161. package/dist/lib/testing/storyboard/trusted-match-context-replay.mjs.map +1 -0
  162. package/dist/lib/testing/storyboard/types.d.mts +84 -15
  163. package/dist/lib/testing/storyboard/types.d.ts +84 -15
  164. package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
  165. package/dist/lib/testing/storyboard/types.js +2 -0
  166. package/dist/lib/testing/storyboard/types.js.map +1 -1
  167. package/dist/lib/testing/storyboard/types.mjs +2 -0
  168. package/dist/lib/testing/storyboard/types.mjs.map +1 -1
  169. package/dist/lib/testing/storyboard/validations.d.mts +3 -0
  170. package/dist/lib/testing/storyboard/validations.d.ts +3 -0
  171. package/dist/lib/testing/storyboard/validations.d.ts.map +1 -1
  172. package/dist/lib/testing/storyboard/validations.js +64 -24
  173. package/dist/lib/testing/storyboard/validations.js.map +1 -1
  174. package/dist/lib/testing/storyboard/validations.mjs +64 -24
  175. package/dist/lib/testing/storyboard/validations.mjs.map +1 -1
  176. package/dist/lib/types/server-payload-aliases.d.mts +8 -2
  177. package/dist/lib/types/server-payload-aliases.d.ts +8 -2
  178. package/dist/lib/types/server-payload-aliases.d.ts.map +1 -1
  179. package/dist/lib/types/server-payload-aliases.js.map +1 -1
  180. package/dist/lib/upstream-recorder/recorder.d.mts +7 -18
  181. package/dist/lib/upstream-recorder/recorder.d.ts +7 -18
  182. package/dist/lib/upstream-recorder/recorder.d.ts.map +1 -1
  183. package/dist/lib/upstream-recorder/recorder.js +17 -10
  184. package/dist/lib/upstream-recorder/recorder.js.map +1 -1
  185. package/dist/lib/upstream-recorder/recorder.mjs +12 -5
  186. package/dist/lib/upstream-recorder/recorder.mjs.map +1 -1
  187. package/dist/lib/utils/redact-secrets.d.ts.map +1 -1
  188. package/dist/lib/utils/redact-secrets.js +7 -1
  189. package/dist/lib/utils/redact-secrets.js.map +1 -1
  190. package/dist/lib/utils/redact-secrets.mjs +7 -1
  191. package/dist/lib/utils/redact-secrets.mjs.map +1 -1
  192. package/dist/lib/version.d.mts +3 -3
  193. package/dist/lib/version.d.ts +3 -3
  194. package/dist/lib/version.js +3 -3
  195. package/dist/lib/version.js.map +1 -1
  196. package/dist/lib/version.mjs +3 -3
  197. package/dist/lib/version.mjs.map +1 -1
  198. package/docs/guides/BUILD-AN-AGENT.md +4 -2
  199. package/docs/llms.txt +1 -1
  200. package/package.json +2 -2
@@ -0,0 +1,668 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var grader_exports = {};
20
+ __export(grader_exports, {
21
+ buildAuthorizationServerMetadataUrl: () => buildAuthorizationServerMetadataUrl,
22
+ buildProtectedResourceMetadataUrl: () => buildProtectedResourceMetadataUrl,
23
+ gradeOAuthMetadataGraph: () => gradeOAuthMetadataGraph,
24
+ gradeOAuthMetadataGraphWithTransport: () => gradeOAuthMetadataGraphWithTransport,
25
+ normalizeOAuthResourceForComparison: () => normalizeOAuthResourceForComparison,
26
+ redactOAuthUrlForOutput: () => redactOAuthUrlForOutput,
27
+ redactOAuthUrlsInText: () => redactOAuthUrlsInText
28
+ });
29
+ module.exports = __toCommonJS(grader_exports);
30
+ var import_address_guards = require('../../../net/address-guards.js');
31
+ var import_ssrf_fetch = require('../../../net/ssrf-fetch.js');
32
+ const LIMITS = Object.freeze({
33
+ authorizationServers: 16,
34
+ uniqueUrls: 64,
35
+ totalRequests: 64,
36
+ responseBytes: 2 * 1024 * 1024,
37
+ responseBytesPerRequest: 256 * 1024,
38
+ redirects: 3,
39
+ wholeRunMs: 6e4
40
+ });
41
+ const DIAGNOSTIC_ORDER = Object.freeze([
42
+ "oauth_graph_limit_exceeded",
43
+ "oauth_fetch_blocked",
44
+ "oauth_protected_resource_metadata_unavailable",
45
+ "oauth_protected_resource_metadata_invalid",
46
+ "oauth_resource_mismatch",
47
+ "oauth_authorization_servers_empty",
48
+ "oauth_authorization_server_url_invalid",
49
+ "oauth_authorization_server_metadata_unavailable",
50
+ "oauth_authorization_server_metadata_invalid",
51
+ "oauth_issuer_mismatch",
52
+ "oauth_endpoint_url_invalid",
53
+ "oauth_endpoint_unreachable",
54
+ "oauth_jwks_unavailable"
55
+ ]);
56
+ function normalizeOAuthResourceForComparison(value) {
57
+ const match = /^([A-Za-z][A-Za-z\d+.-]*):\/\/([^/?#]*)([\s\S]*)$/.exec(value);
58
+ if (!match) return value;
59
+ const scheme = match[1].toLowerCase();
60
+ const authority = match[2];
61
+ const remainder = match[3];
62
+ const at = authority.lastIndexOf("@");
63
+ const userinfo = at >= 0 ? authority.slice(0, at + 1) : "";
64
+ const hostAndPort = at >= 0 ? authority.slice(at + 1) : authority;
65
+ let host;
66
+ let port = "";
67
+ if (hostAndPort.startsWith("[")) {
68
+ const bracket = hostAndPort.indexOf("]");
69
+ if (bracket < 0) return value;
70
+ host = hostAndPort.slice(0, bracket + 1).toLowerCase();
71
+ const suffix = hostAndPort.slice(bracket + 1);
72
+ if (suffix && !/^:\d+$/.test(suffix)) return value;
73
+ port = suffix.slice(1);
74
+ } else {
75
+ const colon = hostAndPort.lastIndexOf(":");
76
+ if (colon >= 0) {
77
+ const suffix = hostAndPort.slice(colon + 1);
78
+ if (!/^\d+$/.test(suffix)) return value;
79
+ host = hostAndPort.slice(0, colon).toLowerCase();
80
+ port = suffix;
81
+ } else {
82
+ host = hostAndPort.toLowerCase();
83
+ }
84
+ }
85
+ if (!host) return value;
86
+ const defaultPort = scheme === "https" ? "443" : scheme === "http" ? "80" : void 0;
87
+ const renderedPort = port && port !== defaultPort ? `:${port}` : "";
88
+ return `${scheme}://${userinfo}${host}${renderedPort}${remainder}`;
89
+ }
90
+ function redactOAuthUrlForOutput(value) {
91
+ try {
92
+ const u = new URL(value);
93
+ if (u.username || u.password) {
94
+ u.username = "REDACTED";
95
+ u.password = "REDACTED";
96
+ }
97
+ for (const key of [...u.searchParams.keys()]) u.searchParams.set(key, "REDACTED");
98
+ if (u.hash) u.hash = "#REDACTED";
99
+ return u.href;
100
+ } catch {
101
+ return "[invalid URL]";
102
+ }
103
+ }
104
+ function redactOAuthUrlsInText(value) {
105
+ return value.replace(/https?:\/\/[^\s"'<>]+/gi, (url) => redactOAuthUrlForOutput(url));
106
+ }
107
+ function buildProtectedResourceMetadataUrl(agentUrl) {
108
+ const u = new URL(agentUrl);
109
+ return `${u.origin}/.well-known/oauth-protected-resource${u.pathname}`;
110
+ }
111
+ function buildAuthorizationServerMetadataUrl(issuer) {
112
+ const u = new URL(issuer);
113
+ const issuerPath = u.pathname === "/" ? "" : u.pathname;
114
+ return `${u.origin}/.well-known/oauth-authorization-server${issuerPath}`;
115
+ }
116
+ async function gradeOAuthMetadataGraph(agentUrl, options = {}) {
117
+ return gradeOAuthMetadataGraphWithTransport(agentUrl, options);
118
+ }
119
+ async function gradeOAuthMetadataGraphWithTransport(agentUrl, options = {}) {
120
+ const timeoutSignal = AbortSignal.timeout(LIMITS.wholeRunMs);
121
+ const signal = options.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;
122
+ const trustedDevelopmentOrigin = options.allowHttp === true ? parseOrigin(agentUrl) : void 0;
123
+ const graphOptions = { ...options, trustedDevelopmentOrigin };
124
+ const state = {
125
+ totalRequests: 0,
126
+ totalResponseBytes: 0,
127
+ uniqueUrls: /* @__PURE__ */ new Set(),
128
+ cache: /* @__PURE__ */ new Map(),
129
+ responses: /* @__PURE__ */ new Map(),
130
+ observations: []
131
+ };
132
+ const findings = [];
133
+ let protectedResourceUrl;
134
+ try {
135
+ protectedResourceUrl = buildProtectedResourceMetadataUrl(agentUrl);
136
+ } catch {
137
+ protectedResourceUrl = redactOAuthUrlForOutput(agentUrl);
138
+ findings.push(finding("oauth_protected_resource_metadata_invalid", "Agent URL is not an absolute URL."));
139
+ return finish(protectedResourceUrl, emptyProbe(protectedResourceUrl), state, findings);
140
+ }
141
+ const protectedResource = await fetchDocument(protectedResourceUrl, graphOptions, signal, state, {
142
+ followRedirects: true,
143
+ kind: "protected_resource_metadata"
144
+ });
145
+ if (protectedResource.blocked) {
146
+ findings.push(fetchFailureFinding("oauth_fetch_blocked", protectedResource.result, void 0));
147
+ return finish(protectedResourceUrl, protectedResource.result, state, findings);
148
+ }
149
+ if (protectedResource.limitExceeded) {
150
+ findings.push(fetchFailureFinding("oauth_graph_limit_exceeded", protectedResource.result, void 0));
151
+ return finish(protectedResourceUrl, protectedResource.result, state, findings);
152
+ }
153
+ if (protectedResource.result.error || protectedResource.result.status !== 200) {
154
+ findings.push(
155
+ fetchFailureFinding("oauth_protected_resource_metadata_unavailable", protectedResource.result, void 0)
156
+ );
157
+ return finish(protectedResourceUrl, protectedResource.result, state, findings);
158
+ }
159
+ const prm = asObject(protectedResource.result.body);
160
+ if (!prm || !isJsonContentType(protectedResource.result.headers["content-type"])) {
161
+ findings.push(
162
+ finding(
163
+ "oauth_protected_resource_metadata_invalid",
164
+ "Protected-resource metadata must be an application/json object.",
165
+ protectedResource.result.url
166
+ )
167
+ );
168
+ return finish(protectedResourceUrl, protectedResource.result, state, findings);
169
+ }
170
+ const resource = prm.resource;
171
+ if (typeof resource !== "string" || !isAllowedAbsoluteUrl(resource, trustedDevelopmentOrigin, false)) {
172
+ findings.push(
173
+ finding(
174
+ "oauth_protected_resource_metadata_invalid",
175
+ "Protected-resource metadata resource must be an absolute HTTPS URI.",
176
+ protectedResource.result.url,
177
+ "resource"
178
+ )
179
+ );
180
+ } else if (normalizeOAuthResourceForComparison(resource) !== normalizeOAuthResourceForComparison(agentUrl)) {
181
+ findings.push(
182
+ finding(
183
+ "oauth_resource_mismatch",
184
+ "Protected-resource metadata resource does not match the agent endpoint.",
185
+ protectedResource.result.url,
186
+ "resource"
187
+ )
188
+ );
189
+ }
190
+ const authorizationServers = prm.authorization_servers;
191
+ if (!Array.isArray(authorizationServers) || authorizationServers.length === 0) {
192
+ findings.push(
193
+ finding(
194
+ "oauth_authorization_servers_empty",
195
+ "authorization_servers must be a non-empty array of issuer URI strings.",
196
+ protectedResource.result.url,
197
+ "authorization_servers"
198
+ )
199
+ );
200
+ return finish(protectedResourceUrl, protectedResource.result, state, findings);
201
+ }
202
+ if (authorizationServers.length > LIMITS.authorizationServers) {
203
+ findings.push(
204
+ finding(
205
+ "oauth_graph_limit_exceeded",
206
+ `authorization_servers exceeds the graph limit of ${LIMITS.authorizationServers}.`,
207
+ protectedResource.result.url,
208
+ "authorization_servers"
209
+ )
210
+ );
211
+ return finish(protectedResourceUrl, protectedResource.result, state, findings);
212
+ }
213
+ for (let index = 0; index < authorizationServers.length; index++) {
214
+ const issuer = authorizationServers[index];
215
+ if (typeof issuer !== "string" || !isIssuerUrl(issuer, trustedDevelopmentOrigin)) {
216
+ findings.push(
217
+ finding(
218
+ "oauth_authorization_server_url_invalid",
219
+ "Authorization-server identifier must be an absolute HTTPS issuer URI without userinfo, query, or fragment.",
220
+ typeof issuer === "string" ? issuer : protectedResource.result.url,
221
+ `authorization_servers[${index}]`,
222
+ index
223
+ )
224
+ );
225
+ continue;
226
+ }
227
+ const metadataUrl = buildAuthorizationServerMetadataUrl(issuer);
228
+ const metadata = await fetchDocument(metadataUrl, graphOptions, signal, state, {
229
+ followRedirects: true,
230
+ kind: "authorization_server_metadata",
231
+ authorizationServerIndex: index
232
+ });
233
+ if (metadata.blocked) {
234
+ findings.push(fetchFailureFinding("oauth_fetch_blocked", metadata.result, index));
235
+ continue;
236
+ }
237
+ if (metadata.limitExceeded) {
238
+ findings.push(fetchFailureFinding("oauth_graph_limit_exceeded", metadata.result, index));
239
+ continue;
240
+ }
241
+ if (metadata.result.error || metadata.result.status !== 200) {
242
+ findings.push(fetchFailureFinding("oauth_authorization_server_metadata_unavailable", metadata.result, index));
243
+ continue;
244
+ }
245
+ const document = asObject(metadata.result.body);
246
+ if (!document || !isJsonContentType(metadata.result.headers["content-type"])) {
247
+ findings.push(
248
+ finding(
249
+ "oauth_authorization_server_metadata_invalid",
250
+ "Authorization-server metadata must be an application/json object.",
251
+ metadata.result.url,
252
+ void 0,
253
+ index
254
+ )
255
+ );
256
+ continue;
257
+ }
258
+ const issuerField = document.issuer;
259
+ if (typeof issuerField !== "string" || !isIssuerUrl(issuerField, trustedDevelopmentOrigin)) {
260
+ findings.push(
261
+ finding(
262
+ "oauth_authorization_server_metadata_invalid",
263
+ "Authorization-server metadata issuer is missing or invalid.",
264
+ metadata.result.url,
265
+ "issuer",
266
+ index
267
+ )
268
+ );
269
+ } else if (issuerField !== issuer) {
270
+ findings.push(
271
+ finding(
272
+ "oauth_issuer_mismatch",
273
+ "Authorization-server metadata issuer is not exactly equal to the advertised issuer.",
274
+ metadata.result.url,
275
+ "issuer",
276
+ index
277
+ )
278
+ );
279
+ }
280
+ const shape = validateAuthorizationServerShape(document);
281
+ if (!shape.ok) {
282
+ findings.push(
283
+ finding("oauth_authorization_server_metadata_invalid", shape.message, metadata.result.url, shape.field, index)
284
+ );
285
+ continue;
286
+ }
287
+ const endpointEntries = [
288
+ {
289
+ field: "authorization_endpoint",
290
+ kind: "authorization_endpoint",
291
+ probe: shape.needsAuthorizationEndpoint,
292
+ followRedirects: false
293
+ },
294
+ { field: "token_endpoint", kind: "token_endpoint", probe: shape.needsTokenEndpoint, followRedirects: false },
295
+ { field: "jwks_uri", kind: "jwks_uri", probe: document.jwks_uri !== void 0, followRedirects: true },
296
+ { field: "registration_endpoint", kind: "authorization_endpoint", probe: false, followRedirects: false }
297
+ ];
298
+ let endpointShapeFailed = false;
299
+ for (const endpoint of endpointEntries) {
300
+ const raw = document[endpoint.field];
301
+ if (raw === void 0) continue;
302
+ if (typeof raw !== "string" || !isAllowedAbsoluteUrl(raw, trustedDevelopmentOrigin, true)) {
303
+ findings.push(
304
+ finding(
305
+ "oauth_endpoint_url_invalid",
306
+ `${endpoint.field} must be an absolute HTTPS URL without credentials or a fragment.`,
307
+ metadata.result.url,
308
+ endpoint.field,
309
+ index
310
+ )
311
+ );
312
+ endpointShapeFailed = true;
313
+ }
314
+ }
315
+ if (endpointShapeFailed) continue;
316
+ for (const endpoint of endpointEntries) {
317
+ if (!endpoint.probe) continue;
318
+ const url = document[endpoint.field];
319
+ const probed = await fetchDocument(url, graphOptions, signal, state, {
320
+ followRedirects: endpoint.followRedirects,
321
+ kind: endpoint.kind,
322
+ authorizationServerIndex: index
323
+ });
324
+ if (probed.blocked) {
325
+ findings.push(fetchFailureFinding("oauth_fetch_blocked", probed.result, index));
326
+ continue;
327
+ }
328
+ if (probed.limitExceeded) {
329
+ findings.push(fetchFailureFinding("oauth_graph_limit_exceeded", probed.result, index));
330
+ continue;
331
+ }
332
+ if (endpoint.field === "jwks_uri") {
333
+ const jwks = asObject(probed.result.body);
334
+ if (probed.result.error || probed.result.status !== 200 || !isJsonContentType(probed.result.headers["content-type"]) || !jwks || !Array.isArray(jwks.keys)) {
335
+ findings.push(fetchFailureFinding("oauth_jwks_unavailable", probed.result, index));
336
+ }
337
+ } else if ((endpoint.field === "authorization_endpoint" || endpoint.field === "token_endpoint") && !endpointReachable(endpoint.field, probed.result)) {
338
+ findings.push(fetchFailureFinding("oauth_endpoint_unreachable", probed.result, index));
339
+ }
340
+ }
341
+ }
342
+ return finish(protectedResourceUrl, protectedResource.result, state, findings);
343
+ }
344
+ function validateAuthorizationServerShape(document) {
345
+ const grants = document.grant_types_supported;
346
+ if (grants !== void 0 && !isNonEmptyStringArray(grants)) {
347
+ return {
348
+ ok: false,
349
+ message: "grant_types_supported must be a non-empty string array when present.",
350
+ field: "grant_types_supported"
351
+ };
352
+ }
353
+ const effectiveGrants = grants === void 0 ? ["authorization_code", "implicit"] : grants;
354
+ const responseTypes = document.response_types_supported;
355
+ if (responseTypes !== void 0 && !isNonEmptyStringArray(responseTypes)) {
356
+ return {
357
+ ok: false,
358
+ message: "response_types_supported must be a non-empty string array when present.",
359
+ field: "response_types_supported"
360
+ };
361
+ }
362
+ const responseTypeUsesAuthorization = Array.isArray(responseTypes) ? responseTypes.some((value) => value.split(/\s+/).some((part) => part === "code" || part === "token")) : false;
363
+ const needsAuthorizationEndpoint = effectiveGrants.some((grant) => grant === "authorization_code" || grant === "implicit") || responseTypeUsesAuthorization;
364
+ const needsTokenEndpoint = !(effectiveGrants.length === 1 && effectiveGrants[0] === "implicit");
365
+ if (needsAuthorizationEndpoint && !isNonEmptyStringArray(responseTypes)) {
366
+ return {
367
+ ok: false,
368
+ message: "response_types_supported is required when the authorization endpoint is used.",
369
+ field: "response_types_supported"
370
+ };
371
+ }
372
+ if (needsAuthorizationEndpoint && typeof document.authorization_endpoint !== "string") {
373
+ return {
374
+ ok: false,
375
+ message: "authorization_endpoint is required for the effective grant and response-type set.",
376
+ field: "authorization_endpoint"
377
+ };
378
+ }
379
+ if (needsTokenEndpoint && typeof document.token_endpoint !== "string") {
380
+ return {
381
+ ok: false,
382
+ message: "token_endpoint is required unless the effective grant set is implicit-only.",
383
+ field: "token_endpoint"
384
+ };
385
+ }
386
+ return { ok: true, needsAuthorizationEndpoint, needsTokenEndpoint };
387
+ }
388
+ function endpointReachable(field, result) {
389
+ if (result.error) return false;
390
+ const status = result.status;
391
+ if (field === "token_endpoint") return status > 0 && status < 500 && status !== 410;
392
+ if (status >= 200 && status < 400) return true;
393
+ return status === 400 || status === 401 || status === 403 || status === 405 || status === 429;
394
+ }
395
+ async function fetchDocument(initialUrl, options, signal, state, fetchOptions) {
396
+ const cacheKey = `${fetchOptions.followRedirects ? "follow" : "manual"} ${initialUrl}`;
397
+ const cached = state.cache.get(cacheKey);
398
+ if (cached) return cached;
399
+ let current = initialUrl;
400
+ let redirects = 0;
401
+ while (true) {
402
+ throwIfCallerAborted(options.signal);
403
+ if (signal.aborted) {
404
+ const outcome = failedFetch(current, "OAuth metadata graph exceeded its whole-run timeout.");
405
+ outcome.limitExceeded = true;
406
+ state.cache.set(cacheKey, outcome);
407
+ return outcome;
408
+ }
409
+ let response = state.responses.get(current);
410
+ if (!response) {
411
+ if (!state.uniqueUrls.has(current) && state.uniqueUrls.size >= LIMITS.uniqueUrls) {
412
+ const outcome = failedFetch(current, `OAuth metadata graph exceeded ${LIMITS.uniqueUrls} unique URLs.`);
413
+ outcome.limitExceeded = true;
414
+ state.cache.set(cacheKey, outcome);
415
+ return outcome;
416
+ }
417
+ state.uniqueUrls.add(current);
418
+ if (state.totalRequests >= LIMITS.totalRequests) {
419
+ const outcome = failedFetch(current, `OAuth metadata graph exceeded ${LIMITS.totalRequests} requests.`);
420
+ outcome.limitExceeded = true;
421
+ state.cache.set(cacheKey, outcome);
422
+ return outcome;
423
+ }
424
+ state.totalRequests++;
425
+ try {
426
+ response = options.transport ? await options.transport.fetch(current, { signal, maxBodyBytes: LIMITS.responseBytesPerRequest }) : await defaultTransportFetch(current, options.trustedDevelopmentOrigin, signal, options.trustedFetchFn);
427
+ if (response.connectedPeerAddress && isBlockedAddress(
428
+ response.connectedPeerAddress,
429
+ isTrustedDevelopmentUrl(current, options.trustedDevelopmentOrigin)
430
+ )) {
431
+ const outcome = failedFetch(current, "Connected peer address was rejected by the SSRF policy.");
432
+ outcome.blocked = true;
433
+ state.cache.set(cacheKey, outcome);
434
+ return outcome;
435
+ }
436
+ } catch (error) {
437
+ throwIfCallerAborted(options.signal);
438
+ const outcome = failedFetch(current, safeFetchError(error));
439
+ if (signal.aborted || error instanceof import_ssrf_fetch.SsrfRefusedError && error.code === "body_exceeds_limit") {
440
+ outcome.limitExceeded = true;
441
+ } else {
442
+ outcome.blocked = error instanceof import_ssrf_fetch.SsrfRefusedError && !["dns_lookup_failed", "dns_empty"].includes(error.code);
443
+ }
444
+ state.cache.set(cacheKey, outcome);
445
+ return outcome;
446
+ }
447
+ state.totalResponseBytes += response.body.byteLength;
448
+ if (state.totalResponseBytes > LIMITS.responseBytes) {
449
+ const outcome = failedFetch(current, `OAuth metadata graph exceeded ${LIMITS.responseBytes} response bytes.`);
450
+ outcome.limitExceeded = true;
451
+ state.cache.set(cacheKey, outcome);
452
+ return outcome;
453
+ }
454
+ state.responses.set(current, response);
455
+ }
456
+ const result = {
457
+ url: redactOAuthUrlForOutput(current),
458
+ status: response.status,
459
+ headers: response.headers,
460
+ body: decodeBody(response.body, response.headers["content-type"])
461
+ };
462
+ state.observations.push({
463
+ kind: fetchOptions.kind,
464
+ url: result.url,
465
+ status: result.status,
466
+ ...fetchOptions.authorizationServerIndex !== void 0 && {
467
+ authorization_server_index: fetchOptions.authorizationServerIndex
468
+ }
469
+ });
470
+ if (!fetchOptions.followRedirects || !isRedirectStatus(response.status)) {
471
+ const outcome = { result, bytes: response.body.byteLength };
472
+ state.cache.set(cacheKey, outcome);
473
+ return outcome;
474
+ }
475
+ const location = response.headers.location;
476
+ if (!location) {
477
+ const outcome = { result, bytes: response.body.byteLength };
478
+ state.cache.set(cacheKey, outcome);
479
+ return outcome;
480
+ }
481
+ if (redirects >= LIMITS.redirects) {
482
+ const outcome = failedFetch(current, `OAuth metadata redirect count exceeded ${LIMITS.redirects}.`);
483
+ outcome.limitExceeded = true;
484
+ state.cache.set(cacheKey, outcome);
485
+ return outcome;
486
+ }
487
+ let next;
488
+ try {
489
+ next = new URL(location, current).href;
490
+ } catch {
491
+ const outcome = failedFetch(current, "OAuth metadata redirect Location was not a valid URL.");
492
+ outcome.blocked = true;
493
+ state.cache.set(cacheKey, outcome);
494
+ return outcome;
495
+ }
496
+ if (!isAllowedAbsoluteUrl(next, options.trustedDevelopmentOrigin, true)) {
497
+ const outcome = failedFetch(next, "OAuth metadata redirect target violated the URL policy.");
498
+ outcome.blocked = true;
499
+ state.cache.set(cacheKey, outcome);
500
+ return outcome;
501
+ }
502
+ redirects++;
503
+ current = next;
504
+ }
505
+ }
506
+ async function defaultTransportFetch(url, trustedDevelopmentOrigin, signal, trustedFetchFn) {
507
+ const result = await (0, import_ssrf_fetch.ssrfSafeFetch)(url, {
508
+ method: "GET",
509
+ headers: { accept: "application/json", "accept-encoding": "identity" },
510
+ allowPrivateIp: isTrustedDevelopmentUrl(url, trustedDevelopmentOrigin),
511
+ signal,
512
+ timeoutMs: 1e4,
513
+ maxBodyBytes: LIMITS.responseBytesPerRequest,
514
+ ...trustedFetchFn && { trustedFetchFn }
515
+ });
516
+ return {
517
+ status: result.status,
518
+ headers: result.headers,
519
+ body: result.body,
520
+ connectedPeerAddress: result.connectionPinned ? result.pinnedAddress : void 0
521
+ };
522
+ }
523
+ function finish(protectedResourceUrl, protectedResourceResult, state, findings) {
524
+ const sorted = findings.slice().sort((a, b) => {
525
+ const codeOrder = DIAGNOSTIC_ORDER.indexOf(a.code) - DIAGNOSTIC_ORDER.indexOf(b.code);
526
+ if (codeOrder !== 0) return codeOrder;
527
+ return (a.authorization_server_index ?? -1) - (b.authorization_server_index ?? -1);
528
+ });
529
+ const first = sorted[0];
530
+ return {
531
+ success: first === void 0,
532
+ protected_resource_url: redactOAuthUrlForOutput(protectedResourceUrl),
533
+ protected_resource_result: sanitizeProtectedResourceResult(protectedResourceResult),
534
+ observations: state.observations,
535
+ findings: sorted,
536
+ ...first && { error_code: first.code, error: first.message },
537
+ total_requests: state.totalRequests,
538
+ total_response_bytes: state.totalResponseBytes
539
+ };
540
+ }
541
+ function finding(code, message, url, field, authorizationServerIndex) {
542
+ return {
543
+ code,
544
+ message,
545
+ ...url && { url: redactOAuthUrlForOutput(url) },
546
+ ...field && { field },
547
+ ...authorizationServerIndex !== void 0 && { authorization_server_index: authorizationServerIndex }
548
+ };
549
+ }
550
+ function fetchFailureFinding(code, result, authorizationServerIndex) {
551
+ return finding(code, result.error ?? `HTTP ${result.status}`, result.url, void 0, authorizationServerIndex);
552
+ }
553
+ function failedFetch(url, error) {
554
+ return { result: { ...emptyProbe(redactOAuthUrlForOutput(url)), error }, bytes: 0 };
555
+ }
556
+ function emptyProbe(url) {
557
+ return { url, status: 0, headers: {}, body: null };
558
+ }
559
+ function safeFetchError(error) {
560
+ if (error instanceof import_ssrf_fetch.SsrfRefusedError) return `SSRF fetch refused (${error.code}).`;
561
+ if (error instanceof Error) {
562
+ if (error.name === "AbortError" || /timeout/i.test(error.message)) return "OAuth metadata fetch timed out.";
563
+ return "OAuth metadata fetch failed.";
564
+ }
565
+ return "OAuth metadata fetch failed.";
566
+ }
567
+ function throwIfCallerAborted(signal) {
568
+ if (!signal?.aborted) return;
569
+ if (signal.reason instanceof Error) throw signal.reason;
570
+ const error = new Error(signal.reason == null ? "The operation was aborted" : String(signal.reason));
571
+ error.name = "AbortError";
572
+ throw error;
573
+ }
574
+ function isIssuerUrl(value, trustedDevelopmentOrigin) {
575
+ try {
576
+ const u = new URL(value);
577
+ return (u.protocol === "https:" || isTrustedDevelopmentUrl(value, trustedDevelopmentOrigin)) && !u.username && !u.password && !u.search && !u.hash;
578
+ } catch {
579
+ return false;
580
+ }
581
+ }
582
+ function isAllowedAbsoluteUrl(value, trustedDevelopmentOrigin, rejectCredentialsAndFragment) {
583
+ try {
584
+ const u = new URL(value);
585
+ if (u.protocol !== "https:" && !isTrustedDevelopmentUrl(value, trustedDevelopmentOrigin)) return false;
586
+ if (rejectCredentialsAndFragment && (u.username || u.password || u.hash)) return false;
587
+ return true;
588
+ } catch {
589
+ return false;
590
+ }
591
+ }
592
+ function parseOrigin(value) {
593
+ try {
594
+ return new URL(value).origin;
595
+ } catch {
596
+ return void 0;
597
+ }
598
+ }
599
+ function isTrustedDevelopmentUrl(value, trustedDevelopmentOrigin) {
600
+ return trustedDevelopmentOrigin !== void 0 && parseOrigin(value) === trustedDevelopmentOrigin;
601
+ }
602
+ function isRedirectStatus(status) {
603
+ return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
604
+ }
605
+ function sanitizeProtectedResourceResult(result) {
606
+ const body = asObject(result.body);
607
+ let safeBody = result.body;
608
+ if (body) {
609
+ const safeRecord = { ...body };
610
+ if (typeof body.resource === "string") {
611
+ safeRecord.resource = redactOAuthUrlForOutput(body.resource);
612
+ }
613
+ if (Array.isArray(body.authorization_servers)) {
614
+ safeRecord.authorization_servers = body.authorization_servers.map(
615
+ (value) => typeof value === "string" ? redactOAuthUrlForOutput(value) : value
616
+ );
617
+ }
618
+ safeBody = safeRecord;
619
+ }
620
+ const allowedHeaders = /* @__PURE__ */ new Set(["content-type", "content-length", "content-encoding", "location"]);
621
+ const headers = Object.fromEntries(
622
+ Object.entries(result.headers).filter(([key]) => allowedHeaders.has(key.toLowerCase())).map(([key, value]) => [
623
+ key.toLowerCase(),
624
+ key.toLowerCase() === "location" ? redactOAuthUrlForOutput(value) : value
625
+ ])
626
+ );
627
+ return {
628
+ ...result,
629
+ url: redactOAuthUrlForOutput(result.url),
630
+ headers,
631
+ body: safeBody
632
+ };
633
+ }
634
+ function isBlockedAddress(address, allowPrivate) {
635
+ return (0, import_address_guards.isAlwaysBlocked)(address) || !allowPrivate && (0, import_address_guards.isPrivateIp)(address);
636
+ }
637
+ function isNonEmptyStringArray(value) {
638
+ return Array.isArray(value) && value.length > 0 && value.every((item) => typeof item === "string" && item.length > 0);
639
+ }
640
+ function asObject(value) {
641
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
642
+ }
643
+ function isJsonContentType(value) {
644
+ return typeof value === "string" && /^(application\/json|[^;]+\+json)(?:;|$)/i.test(value.trim());
645
+ }
646
+ function decodeBody(body, contentType) {
647
+ if (body.byteLength === 0) return null;
648
+ const text = Buffer.from(body.buffer, body.byteOffset, body.byteLength).toString("utf8");
649
+ if (isJsonContentType(contentType)) {
650
+ try {
651
+ return JSON.parse(text);
652
+ } catch {
653
+ return text;
654
+ }
655
+ }
656
+ return text;
657
+ }
658
+ // Annotate the CommonJS export names for ESM import in node:
659
+ 0 && (module.exports = {
660
+ buildAuthorizationServerMetadataUrl,
661
+ buildProtectedResourceMetadataUrl,
662
+ gradeOAuthMetadataGraph,
663
+ gradeOAuthMetadataGraphWithTransport,
664
+ normalizeOAuthResourceForComparison,
665
+ redactOAuthUrlForOutput,
666
+ redactOAuthUrlsInText
667
+ });
668
+ //# sourceMappingURL=grader.js.map