@adcp/sdk 15.0.0 → 15.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/adcp-grade.js +46 -2
- package/bin/adcp.js +7 -2
- package/dist/lib/canonical-references/index.d.mts +19 -1
- package/dist/lib/canonical-references/index.d.ts +19 -1
- package/dist/lib/canonical-references/index.js +81 -9
- package/dist/lib/canonical-references/index.mjs +80 -9
- package/dist/lib/client/core.d.mts +1 -0
- package/dist/lib/client/core.d.ts +1 -0
- package/dist/lib/core/AgentClient.d.mts +9 -1
- package/dist/lib/core/AgentClient.d.ts +9 -1
- package/dist/lib/core/AgentClient.js +10 -0
- package/dist/lib/core/AgentClient.mjs +10 -0
- package/dist/lib/core/SingleAgentClient.d.mts +13 -2
- package/dist/lib/core/SingleAgentClient.d.ts +13 -2
- package/dist/lib/core/SingleAgentClient.js +23 -5
- package/dist/lib/core/SingleAgentClient.mjs +23 -5
- package/dist/lib/index.d.mts +1 -1
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/reporting/gcs/adapter.d.mts +31 -0
- package/dist/lib/reporting/gcs/adapter.d.ts +31 -0
- package/dist/lib/reporting/gcs/adapter.js +342 -0
- package/dist/lib/reporting/gcs/adapter.mjs +325 -0
- package/dist/lib/reporting/gcs/bucket-policy.d.mts +3 -0
- package/dist/lib/reporting/gcs/bucket-policy.d.ts +3 -0
- package/dist/lib/reporting/gcs/bucket-policy.js +31 -0
- package/dist/lib/reporting/gcs/bucket-policy.mjs +7 -0
- package/dist/lib/reporting/gcs/errors.d.mts +5 -0
- package/dist/lib/reporting/gcs/errors.d.ts +5 -0
- package/dist/lib/reporting/gcs/errors.js +41 -0
- package/dist/lib/reporting/gcs/errors.mjs +16 -0
- package/dist/lib/reporting/gcs/fence.d.mts +36 -0
- package/dist/lib/reporting/gcs/fence.d.ts +36 -0
- package/dist/lib/reporting/gcs/fence.js +250 -0
- package/dist/lib/reporting/gcs/fence.mjs +230 -0
- package/dist/lib/reporting/gcs/index.d.mts +7 -0
- package/dist/lib/reporting/gcs/index.d.ts +7 -0
- package/dist/lib/reporting/gcs/index.js +41 -0
- package/dist/lib/reporting/gcs/index.mjs +12 -0
- package/dist/lib/reporting/gcs/io.d.mts +7 -0
- package/dist/lib/reporting/gcs/io.d.ts +7 -0
- package/dist/lib/reporting/gcs/io.js +95 -0
- package/dist/lib/reporting/gcs/io.mjs +69 -0
- package/dist/lib/reporting/gcs/reader.d.mts +43 -0
- package/dist/lib/reporting/gcs/reader.d.ts +43 -0
- package/dist/lib/reporting/gcs/reader.js +193 -0
- package/dist/lib/reporting/gcs/reader.mjs +169 -0
- package/dist/lib/reporting/gcs/validation.d.mts +5 -0
- package/dist/lib/reporting/gcs/validation.d.ts +5 -0
- package/dist/lib/reporting/gcs/validation.js +49 -0
- package/dist/lib/reporting/gcs/validation.mjs +25 -0
- package/dist/lib/reporting/ledger/handler.d.mts +1 -0
- package/dist/lib/reporting/ledger/handler.d.ts +1 -0
- package/dist/lib/reporting/ledger/index.d.mts +1 -0
- package/dist/lib/reporting/ledger/index.d.ts +1 -0
- package/dist/lib/reporting/ledger/index.js +2 -0
- package/dist/lib/reporting/ledger/index.mjs +1 -0
- package/dist/lib/reporting/ledger/managed-postgres.d.mts +16 -1
- package/dist/lib/reporting/ledger/managed-postgres.d.ts +16 -1
- package/dist/lib/reporting/ledger/managed-postgres.js +243 -2
- package/dist/lib/reporting/ledger/managed-postgres.mjs +248 -2
- package/dist/lib/reporting/ledger/object-writes.d.mts +69 -0
- package/dist/lib/reporting/ledger/object-writes.d.ts +69 -0
- package/dist/lib/reporting/ledger/object-writes.js +147 -0
- package/dist/lib/reporting/ledger/object-writes.mjs +114 -0
- package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
- package/dist/lib/server/a2a-adapter.d.mts +50 -1
- package/dist/lib/server/a2a-adapter.d.ts +50 -1
- package/dist/lib/server/a2a-adapter.js +230 -7
- package/dist/lib/server/a2a-adapter.mjs +237 -7
- package/dist/lib/server/auth-signature.d.mts +84 -46
- package/dist/lib/server/auth-signature.d.ts +84 -46
- package/dist/lib/server/auth-signature.js +48 -14
- package/dist/lib/server/auth-signature.mjs +58 -15
- package/dist/lib/server/create-adcp-server.js +5 -16
- package/dist/lib/server/create-adcp-server.mjs +5 -16
- package/dist/lib/server/index.d.mts +1 -1
- package/dist/lib/server/index.d.ts +1 -1
- package/dist/lib/server/index.js +2 -0
- package/dist/lib/server/index.mjs +3 -1
- package/dist/lib/signing/agent-fetch.js +3 -33
- package/dist/lib/signing/agent-fetch.mjs +3 -33
- package/dist/lib/signing/middleware.d.mts +9 -1
- package/dist/lib/signing/middleware.d.ts +9 -1
- package/dist/lib/signing/operation-resolution.d.mts +37 -0
- package/dist/lib/signing/operation-resolution.d.ts +37 -0
- package/dist/lib/signing/operation-resolution.js +154 -0
- package/dist/lib/signing/operation-resolution.mjs +125 -0
- package/dist/lib/signing/postgres-replay-store.d.mts +1 -1
- package/dist/lib/signing/postgres-replay-store.d.ts +1 -1
- package/dist/lib/signing/redis-replay-store.d.mts +1 -1
- package/dist/lib/signing/redis-replay-store.d.ts +1 -1
- package/dist/lib/signing/server.d.mts +1 -0
- package/dist/lib/signing/server.d.ts +1 -0
- package/dist/lib/signing/server.js +7 -0
- package/dist/lib/signing/server.mjs +8 -0
- package/dist/lib/signing/verifier.d.mts +36 -1
- package/dist/lib/signing/verifier.d.ts +36 -1
- package/dist/lib/signing/verifier.js +66 -34
- package/dist/lib/signing/verifier.mjs +61 -34
- package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.d.mts +12 -0
- package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.d.ts +12 -0
- package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.js +29 -2
- package/dist/lib/testing/storyboard/request-signing/a2a-dispatch.mjs +27 -1
- package/dist/lib/testing/storyboard/request-signing/a2a-operation-resolution.d.mts +61 -0
- package/dist/lib/testing/storyboard/request-signing/a2a-operation-resolution.d.ts +61 -0
- package/dist/lib/testing/storyboard/request-signing/a2a-operation-resolution.js +298 -0
- package/dist/lib/testing/storyboard/request-signing/a2a-operation-resolution.mjs +276 -0
- package/dist/lib/testing/storyboard/request-signing/grader.d.mts +31 -1
- package/dist/lib/testing/storyboard/request-signing/grader.d.ts +31 -1
- package/dist/lib/testing/storyboard/request-signing/grader.js +11 -0
- package/dist/lib/testing/storyboard/request-signing/grader.mjs +11 -0
- package/dist/lib/testing/storyboard/request-signing/index.d.mts +5 -4
- package/dist/lib/testing/storyboard/request-signing/index.d.ts +5 -4
- package/dist/lib/testing/storyboard/request-signing/index.js +13 -0
- package/dist/lib/testing/storyboard/request-signing/index.mjs +18 -2
- package/dist/lib/testing/storyboard/request-signing/types.d.mts +43 -0
- package/dist/lib/testing/storyboard/request-signing/types.d.ts +43 -0
- package/dist/lib/testing/storyboard/request-signing/types.js +3 -0
- package/dist/lib/testing/storyboard/request-signing/types.mjs +2 -0
- package/dist/lib/testing/storyboard/request-signing/vector-loader.d.mts +42 -1
- package/dist/lib/testing/storyboard/request-signing/vector-loader.d.ts +42 -1
- package/dist/lib/testing/storyboard/request-signing/vector-loader.js +100 -1
- package/dist/lib/testing/storyboard/request-signing/vector-loader.mjs +104 -3
- package/dist/lib/testing/storyboard/validations.d.mts +1 -1
- package/dist/lib/testing/storyboard/validations.d.ts +1 -1
- 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 +2 -2
- package/docs/guides/BUILD-AN-AGENT.md +9 -4
- package/docs/guides/CREATIVE-DELIVERY.md +34 -0
- package/docs/guides/REPORTING-GCS-FENCE.md +52 -0
- package/docs/guides/REPORTING-GCS-MANAGED.md +56 -0
- package/docs/guides/REPORTING-OPERATIONS.md +4 -0
- package/docs/guides/SIGNING-GUIDE.md +20 -6
- package/docs/guides/VALIDATE-YOUR-AGENT.md +4 -0
- package/docs/llms.txt +2 -2
- package/docs/migration-14.x-rc-worksheet.md +5 -4
- package/docs/migration-buyer-agent-registry.md +1 -1
- package/package.json +19 -1
- package/skills/build-seller-agent/specialisms/signed-requests.md +2 -0
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import { RequestSignatureError } from "../signing/errors.mjs";
|
|
2
2
|
import { InMemoryReplayStore } from "../signing/replay.mjs";
|
|
3
3
|
import { InMemoryRevocationStore } from "../signing/revocation.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
isUnresolvableOperation,
|
|
6
|
+
resolveRequestOperation,
|
|
7
|
+
describeUnresolvable
|
|
8
|
+
} from "../signing/operation-resolution.mjs";
|
|
9
|
+
import {
|
|
10
|
+
assertUnsignedOperationNotRequired,
|
|
11
|
+
assertUnsignedProtocolMethodNotRequired,
|
|
12
|
+
assertUnsignedWebhookAuthenticationAbsent,
|
|
13
|
+
unresolvableOperationError,
|
|
14
|
+
verifyRequestSignature
|
|
15
|
+
} from "../signing/verifier.mjs";
|
|
5
16
|
import { markVerifiedHttpSig } from "./decisioning/buyer-agent.mjs";
|
|
6
17
|
import {
|
|
7
18
|
AuthError,
|
|
@@ -91,8 +102,18 @@ function principalForVerifiedSigner(signer, makePrincipal) {
|
|
|
91
102
|
}
|
|
92
103
|
function requireSignatureWhenPresent(signatureAuth, fallbackAuth, options = {}) {
|
|
93
104
|
const requiredFor = new Set(options.requiredFor ?? []);
|
|
94
|
-
const
|
|
105
|
+
const unsignedCapability = {
|
|
106
|
+
required_for: [...requiredFor],
|
|
107
|
+
...options.protocolMethodsRequiredFor ? { protocol_methods_required_for: [...options.protocolMethodsRequiredFor] } : {}
|
|
108
|
+
};
|
|
109
|
+
const resolveOperation = options.resolveOperation ?? (requiredFor.size > 0 || unsignedCapability.protocol_methods_required_for ? adcpOperationResolver : void 0);
|
|
95
110
|
const combined = async (req) => {
|
|
111
|
+
const request = req;
|
|
112
|
+
const operation = resolveOperation?.(request);
|
|
113
|
+
if (isUnresolvableOperation(operation)) {
|
|
114
|
+
logUnresolvable(request);
|
|
115
|
+
throw signatureAuthError(unresolvableOperationError());
|
|
116
|
+
}
|
|
96
117
|
if (hasSignatureHeader(req)) {
|
|
97
118
|
const result = await signatureAuth(req);
|
|
98
119
|
if (result === null) {
|
|
@@ -100,6 +121,12 @@ function requireSignatureWhenPresent(signatureAuth, fallbackAuth, options = {})
|
|
|
100
121
|
}
|
|
101
122
|
return result;
|
|
102
123
|
}
|
|
124
|
+
const body = bodyText(request);
|
|
125
|
+
try {
|
|
126
|
+
assertUnsignedWebhookAuthenticationAbsent(body);
|
|
127
|
+
} catch (err) {
|
|
128
|
+
throw asSignatureAuthError(err);
|
|
129
|
+
}
|
|
103
130
|
let fallbackResult = null;
|
|
104
131
|
let fallbackError;
|
|
105
132
|
let fallbackThrew = false;
|
|
@@ -110,23 +137,16 @@ function requireSignatureWhenPresent(signatureAuth, fallbackAuth, options = {})
|
|
|
110
137
|
fallbackError = err;
|
|
111
138
|
}
|
|
112
139
|
if (fallbackResult !== null) return fallbackResult;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
"request_signature_required",
|
|
119
|
-
0,
|
|
120
|
-
`Operation ${operation} requires an RFC 9421 request signature when no other credentials are presented.`
|
|
121
|
-
)
|
|
122
|
-
});
|
|
123
|
-
}
|
|
140
|
+
try {
|
|
141
|
+
assertUnsignedOperationNotRequired(operation, unsignedCapability);
|
|
142
|
+
assertUnsignedProtocolMethodNotRequired(body, unsignedCapability);
|
|
143
|
+
} catch (err) {
|
|
144
|
+
throw asSignatureAuthError(err);
|
|
124
145
|
}
|
|
125
146
|
if (fallbackThrew) throw fallbackError;
|
|
126
147
|
return null;
|
|
127
148
|
};
|
|
128
|
-
|
|
129
|
-
if (anyChildNeedsRawBody || resolveOperation) {
|
|
149
|
+
if (resolveOperation || authenticatorNeedsRawBody(signatureAuth) || authenticatorNeedsRawBody(fallbackAuth)) {
|
|
130
150
|
tagAuthenticatorNeedsRawBody(combined);
|
|
131
151
|
}
|
|
132
152
|
tagAuthenticatorPresenceGated(combined);
|
|
@@ -135,9 +155,13 @@ function requireSignatureWhenPresent(signatureAuth, fallbackAuth, options = {})
|
|
|
135
155
|
function requireAuthenticatedOrSigned(options) {
|
|
136
156
|
return requireSignatureWhenPresent(options.signature, options.fallback, {
|
|
137
157
|
requiredFor: options.requiredFor,
|
|
158
|
+
protocolMethodsRequiredFor: options.protocolMethodsRequiredFor,
|
|
138
159
|
resolveOperation: options.resolveOperation
|
|
139
160
|
});
|
|
140
161
|
}
|
|
162
|
+
function adcpOperationResolver(req) {
|
|
163
|
+
return resolveRequestOperation(operationInput(req));
|
|
164
|
+
}
|
|
141
165
|
function mcpToolNameResolver(req) {
|
|
142
166
|
const raw = req.rawBody;
|
|
143
167
|
if (!raw) return void 0;
|
|
@@ -150,6 +174,24 @@ function mcpToolNameResolver(req) {
|
|
|
150
174
|
return void 0;
|
|
151
175
|
}
|
|
152
176
|
}
|
|
177
|
+
function operationInput(req) {
|
|
178
|
+
const candidate = req;
|
|
179
|
+
return { rawBody: candidate.rawBody, method: candidate.method, url: candidate.url };
|
|
180
|
+
}
|
|
181
|
+
function bodyText(req) {
|
|
182
|
+
const raw = req.rawBody;
|
|
183
|
+
return typeof raw === "string" ? raw : raw?.toString("utf8");
|
|
184
|
+
}
|
|
185
|
+
function signatureAuthError(err) {
|
|
186
|
+
return new AuthError(`Signature rejected (${err.code}).`, { cause: err });
|
|
187
|
+
}
|
|
188
|
+
function asSignatureAuthError(err) {
|
|
189
|
+
return err instanceof RequestSignatureError ? signatureAuthError(err) : err;
|
|
190
|
+
}
|
|
191
|
+
function logUnresolvable(req) {
|
|
192
|
+
const reason = describeUnresolvable(operationInput(req));
|
|
193
|
+
console.error(`[adcp/auth] request body does not resolve to one operation: ${reason ?? "unknown"}`);
|
|
194
|
+
}
|
|
153
195
|
const SAFE_KEYID = /^[A-Za-z0-9._-]{1,256}$/;
|
|
154
196
|
function hasSignatureHeader(req) {
|
|
155
197
|
return nonEmptyHeader(req.headers["signature-input"]) || nonEmptyHeader(req.headers["signature"]);
|
|
@@ -182,6 +224,7 @@ function firstHeader(value) {
|
|
|
182
224
|
return void 0;
|
|
183
225
|
}
|
|
184
226
|
export {
|
|
227
|
+
adcpOperationResolver,
|
|
185
228
|
mcpToolNameResolver,
|
|
186
229
|
principalForVerifiedSigner,
|
|
187
230
|
requireAuthenticatedOrSigned,
|
|
@@ -69,6 +69,7 @@ var import_diagnostic_limits = require('../validation/diagnostic-limits.js');
|
|
|
69
69
|
var import_idempotency2 = require('./idempotency/index.js');
|
|
70
70
|
var import_webhook_emitter = require('./webhook-emitter.js');
|
|
71
71
|
var import_middleware = require('../signing/middleware.js');
|
|
72
|
+
var import_operation_resolution = require('../signing/operation-resolution.js');
|
|
72
73
|
var import_account_mode = require('./account-mode.js');
|
|
73
74
|
var import_test_controller_bridge = require('./test-controller-bridge.js');
|
|
74
75
|
var import_version2 = require('../version.js');
|
|
@@ -1431,22 +1432,10 @@ function buildSignedRequestsPreTransport(signedRequests, effectiveRequestSigning
|
|
|
1431
1432
|
revocationStore: signedRequests.revocationStore,
|
|
1432
1433
|
adcpVersion,
|
|
1433
1434
|
...signedRequests.agentUrlForKeyid ? { agentUrlForKeyid: signedRequests.agentUrlForKeyid } : {},
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
const parsed = JSON.parse(raw);
|
|
1439
|
-
const messages = Array.isArray(parsed) ? parsed : [parsed];
|
|
1440
|
-
const operations = messages.flatMap((message) => {
|
|
1441
|
-
if (message == null || typeof message !== "object") return [];
|
|
1442
|
-
const candidate = message;
|
|
1443
|
-
return candidate.method === "tools/call" && typeof candidate.params?.name === "string" ? [candidate.params.name] : [];
|
|
1444
|
-
});
|
|
1445
|
-
return operations.find((operation) => requiredFor.includes(operation)) ?? operations[0];
|
|
1446
|
-
} catch {
|
|
1447
|
-
}
|
|
1448
|
-
return void 0;
|
|
1449
|
-
}
|
|
1435
|
+
// One resolver for MCP `tools/call` and A2A message methods; a body that
|
|
1436
|
+
// does not resolve to exactly one operation is rejected by the verifier
|
|
1437
|
+
// (`request_body_malformed`), never treated as "not in required_for".
|
|
1438
|
+
resolveOperation: (req) => (0, import_operation_resolution.resolveRequestOperation)({ rawBody: req.rawBody, method: req.method, url: req.url })
|
|
1450
1439
|
});
|
|
1451
1440
|
return async function adcpPreTransport(req, res) {
|
|
1452
1441
|
const serveContext = (0, import_auth.getServeRequestContext)(req);
|
|
@@ -104,6 +104,7 @@ import {
|
|
|
104
104
|
createWebhookEmitter
|
|
105
105
|
} from "./webhook-emitter.mjs";
|
|
106
106
|
import { createExpressVerifier } from "../signing/middleware.mjs";
|
|
107
|
+
import { resolveRequestOperation } from "../signing/operation-resolution.mjs";
|
|
107
108
|
import { isSandboxOrMockAccount } from "./account-mode.mjs";
|
|
108
109
|
import {
|
|
109
110
|
isSandboxRequest as isSandboxRequestForSeeding,
|
|
@@ -1503,22 +1504,10 @@ function buildSignedRequestsPreTransport(signedRequests, effectiveRequestSigning
|
|
|
1503
1504
|
revocationStore: signedRequests.revocationStore,
|
|
1504
1505
|
adcpVersion,
|
|
1505
1506
|
...signedRequests.agentUrlForKeyid ? { agentUrlForKeyid: signedRequests.agentUrlForKeyid } : {},
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
const parsed = JSON.parse(raw);
|
|
1511
|
-
const messages = Array.isArray(parsed) ? parsed : [parsed];
|
|
1512
|
-
const operations = messages.flatMap((message) => {
|
|
1513
|
-
if (message == null || typeof message !== "object") return [];
|
|
1514
|
-
const candidate = message;
|
|
1515
|
-
return candidate.method === "tools/call" && typeof candidate.params?.name === "string" ? [candidate.params.name] : [];
|
|
1516
|
-
});
|
|
1517
|
-
return operations.find((operation) => requiredFor.includes(operation)) ?? operations[0];
|
|
1518
|
-
} catch {
|
|
1519
|
-
}
|
|
1520
|
-
return void 0;
|
|
1521
|
-
}
|
|
1507
|
+
// One resolver for MCP `tools/call` and A2A message methods; a body that
|
|
1508
|
+
// does not resolve to exactly one operation is rejected by the verifier
|
|
1509
|
+
// (`request_body_malformed`), never treated as "not in required_for".
|
|
1510
|
+
resolveOperation: (req) => resolveRequestOperation({ rawBody: req.rawBody, method: req.method, url: req.url })
|
|
1522
1511
|
});
|
|
1523
1512
|
return async function adcpPreTransport(req, res) {
|
|
1524
1513
|
const serveContext = getServeRequestContext(req);
|
|
@@ -49,7 +49,7 @@ export { verifyApiKey, verifyBearer, anyOf, extractBearerToken, respondUnauthori
|
|
|
49
49
|
export type { Authenticator, AuthPrincipal, AuthResult, VerifyApiKeyOptions, VerifyBearerOptions, RespondUnauthorizedOptions, ServeRequestContext, } from './auth.mjs';
|
|
50
50
|
export { verifyIntrospection } from './auth-introspection.mjs';
|
|
51
51
|
export type { VerifyIntrospectionOptions, IntrospectionCacheOptions, IntrospectionResponse, } from './auth-introspection.mjs';
|
|
52
|
-
export { verifySignatureAsAuthenticator, requireSignatureWhenPresent, requireAuthenticatedOrSigned, mcpToolNameResolver, } from './auth-signature.mjs';
|
|
52
|
+
export { verifySignatureAsAuthenticator, requireSignatureWhenPresent, requireAuthenticatedOrSigned, mcpToolNameResolver, adcpOperationResolver, } from './auth-signature.mjs';
|
|
53
53
|
export type { VerifySignatureAsAuthenticatorOptions, RequireSignatureWhenPresentOptions, RequireAuthenticatedOrSignedOptions, } from './auth-signature.mjs';
|
|
54
54
|
export { InMemoryStateStore, StateError, PatchConflictError, DEFAULT_MAX_DOCUMENT_BYTES, SESSION_KEY_FIELD, createSessionedStore, scopedStore, patchWithRetry, isPutIfMatchConflict, validateCollection, validateId, validatePayloadSize, validateWrite, } from './state-store.mjs';
|
|
55
55
|
export type { AdcpStateStore, InMemoryStateStoreOptions, ListOptions, ListResult, PatchWithRetryOptions, PutIfMatchResult, StateErrorCode, VersionedDocument, } from './state-store.mjs';
|
|
@@ -49,7 +49,7 @@ export { verifyApiKey, verifyBearer, anyOf, extractBearerToken, respondUnauthori
|
|
|
49
49
|
export type { Authenticator, AuthPrincipal, AuthResult, VerifyApiKeyOptions, VerifyBearerOptions, RespondUnauthorizedOptions, ServeRequestContext, } from './auth';
|
|
50
50
|
export { verifyIntrospection } from './auth-introspection';
|
|
51
51
|
export type { VerifyIntrospectionOptions, IntrospectionCacheOptions, IntrospectionResponse, } from './auth-introspection';
|
|
52
|
-
export { verifySignatureAsAuthenticator, requireSignatureWhenPresent, requireAuthenticatedOrSigned, mcpToolNameResolver, } from './auth-signature';
|
|
52
|
+
export { verifySignatureAsAuthenticator, requireSignatureWhenPresent, requireAuthenticatedOrSigned, mcpToolNameResolver, adcpOperationResolver, } from './auth-signature';
|
|
53
53
|
export type { VerifySignatureAsAuthenticatorOptions, RequireSignatureWhenPresentOptions, RequireAuthenticatedOrSignedOptions, } from './auth-signature';
|
|
54
54
|
export { InMemoryStateStore, StateError, PatchConflictError, DEFAULT_MAX_DOCUMENT_BYTES, SESSION_KEY_FIELD, createSessionedStore, scopedStore, patchWithRetry, isPutIfMatchConflict, validateCollection, validateId, validatePayloadSize, validateWrite, } from './state-store';
|
|
55
55
|
export type { AdcpStateStore, InMemoryStateStoreOptions, ListOptions, ListResult, PatchWithRetryOptions, PutIfMatchResult, StateErrorCode, VersionedDocument, } from './state-store';
|
package/dist/lib/server/index.js
CHANGED
|
@@ -87,6 +87,7 @@ __export(server_exports, {
|
|
|
87
87
|
WebhookAuthenticationResolutionError: () => import_webhook_delivery.WebhookAuthenticationResolutionError,
|
|
88
88
|
WebhookDeliveryTerminalError: () => import_webhook_delivery.WebhookDeliveryTerminalError,
|
|
89
89
|
adcpError: () => import_errors.adcpError,
|
|
90
|
+
adcpOperationResolver: () => import_auth_signature.adcpOperationResolver,
|
|
90
91
|
anyOf: () => import_auth.anyOf,
|
|
91
92
|
applyTargetingInput: () => import_targeting_input.applyTargetingInput,
|
|
92
93
|
assertCreativeTransition: () => import_state_machine.assertCreativeTransition,
|
|
@@ -415,6 +416,7 @@ var import_media_buy_action_resolver = require('./media-buy-action-resolver.js')
|
|
|
415
416
|
WebhookAuthenticationResolutionError,
|
|
416
417
|
WebhookDeliveryTerminalError,
|
|
417
418
|
adcpError,
|
|
419
|
+
adcpOperationResolver,
|
|
418
420
|
anyOf,
|
|
419
421
|
applyTargetingInput,
|
|
420
422
|
assertCreativeTransition,
|
|
@@ -119,7 +119,8 @@ import {
|
|
|
119
119
|
verifySignatureAsAuthenticator,
|
|
120
120
|
requireSignatureWhenPresent,
|
|
121
121
|
requireAuthenticatedOrSigned,
|
|
122
|
-
mcpToolNameResolver
|
|
122
|
+
mcpToolNameResolver,
|
|
123
|
+
adcpOperationResolver
|
|
123
124
|
} from "./auth-signature.mjs";
|
|
124
125
|
import {
|
|
125
126
|
InMemoryStateStore,
|
|
@@ -363,6 +364,7 @@ export {
|
|
|
363
364
|
WebhookAuthenticationResolutionError,
|
|
364
365
|
WebhookDeliveryTerminalError,
|
|
365
366
|
adcpError,
|
|
367
|
+
adcpOperationResolver,
|
|
366
368
|
anyOf,
|
|
367
369
|
applyTargetingInput,
|
|
368
370
|
assertCreativeTransition,
|
|
@@ -35,6 +35,7 @@ var import_capability_cache = require('./capability-cache.js');
|
|
|
35
35
|
var import_webhook_auth_detection = require('./webhook-auth-detection.js');
|
|
36
36
|
var import_version = require('../version.js');
|
|
37
37
|
var import_content_digest = require('./content-digest.js');
|
|
38
|
+
var import_operation_resolution = require('./operation-resolution.js');
|
|
38
39
|
var import_content_digest2 = require('./content-digest.js');
|
|
39
40
|
const MAX_WEBHOOK_AUTH_INSPECTION_BYTES = 1048576;
|
|
40
41
|
function defaultUpstream() {
|
|
@@ -62,42 +63,11 @@ function describeBody(body) {
|
|
|
62
63
|
}
|
|
63
64
|
return typeof body;
|
|
64
65
|
}
|
|
65
|
-
const A2A_SEND_METHODS = /* @__PURE__ */ new Set([
|
|
66
|
-
"message/send",
|
|
67
|
-
"message/stream",
|
|
68
|
-
"SendMessage",
|
|
69
|
-
"SendStreamingMessage"
|
|
70
|
-
]);
|
|
71
66
|
function extractAdcpOperation(body) {
|
|
72
67
|
const text = bodyToUtf8(body);
|
|
73
68
|
if (!text) return void 0;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
parsed = JSON.parse(text);
|
|
77
|
-
} catch {
|
|
78
|
-
return void 0;
|
|
79
|
-
}
|
|
80
|
-
if (!parsed || typeof parsed !== "object") return void 0;
|
|
81
|
-
const rpc = parsed;
|
|
82
|
-
if (rpc.method === "tools/call") {
|
|
83
|
-
const params = rpc.params;
|
|
84
|
-
return typeof params?.name === "string" ? params.name : void 0;
|
|
85
|
-
}
|
|
86
|
-
if (typeof rpc.method === "string" && A2A_SEND_METHODS.has(rpc.method)) {
|
|
87
|
-
const params = rpc.params;
|
|
88
|
-
const parts = params?.message?.parts;
|
|
89
|
-
if (!Array.isArray(parts)) return void 0;
|
|
90
|
-
for (const part of parts) {
|
|
91
|
-
if (part && typeof part === "object") {
|
|
92
|
-
const p = part;
|
|
93
|
-
const isDataPart = p.kind === void 0 || p.kind === "data";
|
|
94
|
-
if (isDataPart && typeof p.data?.skill === "string") {
|
|
95
|
-
return p.data.skill;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return void 0;
|
|
69
|
+
const operation = (0, import_operation_resolution.resolveRequestOperation)({ rawBody: text, method: "POST" });
|
|
70
|
+
return typeof operation === "string" ? operation : void 0;
|
|
101
71
|
}
|
|
102
72
|
function carriesWebhookAuthentication(body) {
|
|
103
73
|
const text = bodyToUtf8(body);
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import { containsWebhookAuthentication } from "./webhook-auth-detection.mjs";
|
|
8
8
|
import { ADCP_VERSION } from "../version.mjs";
|
|
9
9
|
import { requestSigningEncodingForVersion } from "./content-digest.mjs";
|
|
10
|
+
import { resolveRequestOperation } from "./operation-resolution.mjs";
|
|
10
11
|
import { requestSigningEncodingForVersion as requestSigningEncodingForVersion2 } from "./content-digest.mjs";
|
|
11
12
|
const MAX_WEBHOOK_AUTH_INSPECTION_BYTES = 1048576;
|
|
12
13
|
function defaultUpstream() {
|
|
@@ -34,42 +35,11 @@ function describeBody(body) {
|
|
|
34
35
|
}
|
|
35
36
|
return typeof body;
|
|
36
37
|
}
|
|
37
|
-
const A2A_SEND_METHODS = /* @__PURE__ */ new Set([
|
|
38
|
-
"message/send",
|
|
39
|
-
"message/stream",
|
|
40
|
-
"SendMessage",
|
|
41
|
-
"SendStreamingMessage"
|
|
42
|
-
]);
|
|
43
38
|
function extractAdcpOperation(body) {
|
|
44
39
|
const text = bodyToUtf8(body);
|
|
45
40
|
if (!text) return void 0;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
parsed = JSON.parse(text);
|
|
49
|
-
} catch {
|
|
50
|
-
return void 0;
|
|
51
|
-
}
|
|
52
|
-
if (!parsed || typeof parsed !== "object") return void 0;
|
|
53
|
-
const rpc = parsed;
|
|
54
|
-
if (rpc.method === "tools/call") {
|
|
55
|
-
const params = rpc.params;
|
|
56
|
-
return typeof params?.name === "string" ? params.name : void 0;
|
|
57
|
-
}
|
|
58
|
-
if (typeof rpc.method === "string" && A2A_SEND_METHODS.has(rpc.method)) {
|
|
59
|
-
const params = rpc.params;
|
|
60
|
-
const parts = params?.message?.parts;
|
|
61
|
-
if (!Array.isArray(parts)) return void 0;
|
|
62
|
-
for (const part of parts) {
|
|
63
|
-
if (part && typeof part === "object") {
|
|
64
|
-
const p = part;
|
|
65
|
-
const isDataPart = p.kind === void 0 || p.kind === "data";
|
|
66
|
-
if (isDataPart && typeof p.data?.skill === "string") {
|
|
67
|
-
return p.data.skill;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return void 0;
|
|
41
|
+
const operation = resolveRequestOperation({ rawBody: text, method: "POST" });
|
|
42
|
+
return typeof operation === "string" ? operation : void 0;
|
|
73
43
|
}
|
|
74
44
|
function carriesWebhookAuthentication(body) {
|
|
75
45
|
const text = bodyToUtf8(body);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type VerifyRequestOptions } from './verifier.mjs';
|
|
2
|
+
import type { ResolvedOperation } from './operation-resolution.mjs';
|
|
2
3
|
import type { VerifiedSigner } from './types.mjs';
|
|
3
4
|
declare module 'http' {
|
|
4
5
|
interface IncomingMessage {
|
|
@@ -56,6 +57,13 @@ export interface ExpressMiddlewareOptions extends Omit<VerifyRequestOptions, 'op
|
|
|
56
57
|
* the verifier will then treat the request as "not in any required_for"
|
|
57
58
|
* and accept unsigned traffic rather than rejecting.
|
|
58
59
|
*
|
|
60
|
+
* Return {@link UNRESOLVABLE_OPERATION} for a body that does not resolve to
|
|
61
|
+
* exactly one operation; the verifier then rejects it with
|
|
62
|
+
* `request_body_malformed`, signed or not. `resolveRequestOperation` (and
|
|
63
|
+
* `adcpOperationResolver` from `@adcp/sdk/server`) implements the MCP and A2A
|
|
64
|
+
* rules, including that fail-closed result, and is what `createAdcpServer`
|
|
65
|
+
* auto-wires.
|
|
66
|
+
*
|
|
59
67
|
* SECURITY: a `resolveOperation` that always returns `undefined` — for
|
|
60
68
|
* example, a routing helper that silently fails to match — disables
|
|
61
69
|
* `required_for` enforcement globally. Unsigned requests on signed-only
|
|
@@ -64,7 +72,7 @@ export interface ExpressMiddlewareOptions extends Omit<VerifyRequestOptions, 'op
|
|
|
64
72
|
* asserting `resolveOperation(req)` is non-undefined for sample signed
|
|
65
73
|
* requests is the simplest guard.
|
|
66
74
|
*/
|
|
67
|
-
resolveOperation: (req: ExpressLike) =>
|
|
75
|
+
resolveOperation: (req: ExpressLike) => ResolvedOperation;
|
|
68
76
|
/**
|
|
69
77
|
* Override how the request's full URL is reconstructed. Use when the server
|
|
70
78
|
* sits behind a TLS-terminating or path-rewriting load balancer, since
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type VerifyRequestOptions } from './verifier';
|
|
2
|
+
import type { ResolvedOperation } from './operation-resolution';
|
|
2
3
|
import type { VerifiedSigner } from './types';
|
|
3
4
|
declare module 'http' {
|
|
4
5
|
interface IncomingMessage {
|
|
@@ -56,6 +57,13 @@ export interface ExpressMiddlewareOptions extends Omit<VerifyRequestOptions, 'op
|
|
|
56
57
|
* the verifier will then treat the request as "not in any required_for"
|
|
57
58
|
* and accept unsigned traffic rather than rejecting.
|
|
58
59
|
*
|
|
60
|
+
* Return {@link UNRESOLVABLE_OPERATION} for a body that does not resolve to
|
|
61
|
+
* exactly one operation; the verifier then rejects it with
|
|
62
|
+
* `request_body_malformed`, signed or not. `resolveRequestOperation` (and
|
|
63
|
+
* `adcpOperationResolver` from `@adcp/sdk/server`) implements the MCP and A2A
|
|
64
|
+
* rules, including that fail-closed result, and is what `createAdcpServer`
|
|
65
|
+
* auto-wires.
|
|
66
|
+
*
|
|
59
67
|
* SECURITY: a `resolveOperation` that always returns `undefined` — for
|
|
60
68
|
* example, a routing helper that silently fails to match — disables
|
|
61
69
|
* `required_for` enforcement globally. Unsigned requests on signed-only
|
|
@@ -64,7 +72,7 @@ export interface ExpressMiddlewareOptions extends Omit<VerifyRequestOptions, 'op
|
|
|
64
72
|
* asserting `resolveOperation(req)` is non-undefined for sample signed
|
|
65
73
|
* requests is the simplest guard.
|
|
66
74
|
*/
|
|
67
|
-
resolveOperation: (req: ExpressLike) =>
|
|
75
|
+
resolveOperation: (req: ExpressLike) => ResolvedOperation;
|
|
68
76
|
/**
|
|
69
77
|
* Override how the request's full URL is reconstructed. Use when the server
|
|
70
78
|
* sits behind a TLS-terminating or path-rewriting load balancer, since
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distinguished "this body does not resolve to exactly one operation" result.
|
|
3
|
+
* A `Symbol.for` key so it survives duplicate copies of the SDK in one process.
|
|
4
|
+
*/
|
|
5
|
+
export declare const UNRESOLVABLE_OPERATION: unique symbol;
|
|
6
|
+
export type UnresolvableOperation = typeof UNRESOLVABLE_OPERATION;
|
|
7
|
+
/** What a `resolveOperation` callback may return. */
|
|
8
|
+
export type ResolvedOperation = string | undefined | UnresolvableOperation;
|
|
9
|
+
export declare function isUnresolvableOperation(value: unknown): value is UnresolvableOperation;
|
|
10
|
+
/** JSON-RPC methods that carry an A2A Message and therefore an invocation DataPart. */
|
|
11
|
+
export declare const A2A_MESSAGE_METHODS: ReadonlySet<string>;
|
|
12
|
+
export interface OperationResolutionInput {
|
|
13
|
+
/** The exact request body bytes, decoded as UTF-8. */
|
|
14
|
+
rawBody?: string | Buffer;
|
|
15
|
+
/** HTTP method. When present and not `POST`, the request carries no operation. */
|
|
16
|
+
method?: string;
|
|
17
|
+
/** Request URL (path may be relative). Selects the A2A HTTP+JSON binding. */
|
|
18
|
+
url?: string;
|
|
19
|
+
}
|
|
20
|
+
export type OperationResolution = {
|
|
21
|
+
kind: 'operation';
|
|
22
|
+
operation: string;
|
|
23
|
+
} | {
|
|
24
|
+
kind: 'none';
|
|
25
|
+
} | {
|
|
26
|
+
kind: 'unresolvable';
|
|
27
|
+
reason: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the operation a request carries, with a diagnostic reason when it
|
|
31
|
+
* cannot be resolved. Pure and synchronous; never throws.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveRequestOperationDetailed(input: OperationResolutionInput): OperationResolution;
|
|
34
|
+
/** {@link resolveRequestOperationDetailed} collapsed to the `resolveOperation` return shape. */
|
|
35
|
+
export declare function resolveRequestOperation(input: OperationResolutionInput): ResolvedOperation;
|
|
36
|
+
/** Diagnostic reason for an unresolvable body. Server-side logs only. */
|
|
37
|
+
export declare function describeUnresolvable(input: OperationResolutionInput): string | undefined;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Distinguished "this body does not resolve to exactly one operation" result.
|
|
3
|
+
* A `Symbol.for` key so it survives duplicate copies of the SDK in one process.
|
|
4
|
+
*/
|
|
5
|
+
export declare const UNRESOLVABLE_OPERATION: unique symbol;
|
|
6
|
+
export type UnresolvableOperation = typeof UNRESOLVABLE_OPERATION;
|
|
7
|
+
/** What a `resolveOperation` callback may return. */
|
|
8
|
+
export type ResolvedOperation = string | undefined | UnresolvableOperation;
|
|
9
|
+
export declare function isUnresolvableOperation(value: unknown): value is UnresolvableOperation;
|
|
10
|
+
/** JSON-RPC methods that carry an A2A Message and therefore an invocation DataPart. */
|
|
11
|
+
export declare const A2A_MESSAGE_METHODS: ReadonlySet<string>;
|
|
12
|
+
export interface OperationResolutionInput {
|
|
13
|
+
/** The exact request body bytes, decoded as UTF-8. */
|
|
14
|
+
rawBody?: string | Buffer;
|
|
15
|
+
/** HTTP method. When present and not `POST`, the request carries no operation. */
|
|
16
|
+
method?: string;
|
|
17
|
+
/** Request URL (path may be relative). Selects the A2A HTTP+JSON binding. */
|
|
18
|
+
url?: string;
|
|
19
|
+
}
|
|
20
|
+
export type OperationResolution = {
|
|
21
|
+
kind: 'operation';
|
|
22
|
+
operation: string;
|
|
23
|
+
} | {
|
|
24
|
+
kind: 'none';
|
|
25
|
+
} | {
|
|
26
|
+
kind: 'unresolvable';
|
|
27
|
+
reason: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Resolve the operation a request carries, with a diagnostic reason when it
|
|
31
|
+
* cannot be resolved. Pure and synchronous; never throws.
|
|
32
|
+
*/
|
|
33
|
+
export declare function resolveRequestOperationDetailed(input: OperationResolutionInput): OperationResolution;
|
|
34
|
+
/** {@link resolveRequestOperationDetailed} collapsed to the `resolveOperation` return shape. */
|
|
35
|
+
export declare function resolveRequestOperation(input: OperationResolutionInput): ResolvedOperation;
|
|
36
|
+
/** Diagnostic reason for an unresolvable body. Server-side logs only. */
|
|
37
|
+
export declare function describeUnresolvable(input: OperationResolutionInput): string | undefined;
|
|
@@ -0,0 +1,154 @@
|
|
|
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 operation_resolution_exports = {};
|
|
20
|
+
__export(operation_resolution_exports, {
|
|
21
|
+
A2A_MESSAGE_METHODS: () => A2A_MESSAGE_METHODS,
|
|
22
|
+
UNRESOLVABLE_OPERATION: () => UNRESOLVABLE_OPERATION,
|
|
23
|
+
describeUnresolvable: () => describeUnresolvable,
|
|
24
|
+
isUnresolvableOperation: () => isUnresolvableOperation,
|
|
25
|
+
resolveRequestOperation: () => resolveRequestOperation,
|
|
26
|
+
resolveRequestOperationDetailed: () => resolveRequestOperationDetailed
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(operation_resolution_exports);
|
|
29
|
+
var import_strict_json = require('./agent-resolver/strict-json.js');
|
|
30
|
+
const UNRESOLVABLE_OPERATION = /* @__PURE__ */ Symbol.for("@adcp/client.signing.unresolvableOperation");
|
|
31
|
+
function isUnresolvableOperation(value) {
|
|
32
|
+
return value === UNRESOLVABLE_OPERATION;
|
|
33
|
+
}
|
|
34
|
+
const A2A_MESSAGE_METHODS = /* @__PURE__ */ new Set([
|
|
35
|
+
"SendMessage",
|
|
36
|
+
"SendStreamingMessage",
|
|
37
|
+
"message/send",
|
|
38
|
+
"message/stream"
|
|
39
|
+
]);
|
|
40
|
+
const CONTENT_MEMBERS = ["text", "data", "raw", "url", "file"];
|
|
41
|
+
const FILE_MEMBERS = /* @__PURE__ */ new Set(["raw", "url", "file"]);
|
|
42
|
+
const HTTP_JSON_MESSAGE_PATH = /(?:^|\/)message:(?:send|stream)$/;
|
|
43
|
+
const ENVELOPE_MEMBERS = ["method", "params"];
|
|
44
|
+
const TOOLS_CALL_PARAMS_MEMBERS = ["name"];
|
|
45
|
+
const CARRIER_MEMBERS = ["message"];
|
|
46
|
+
const MESSAGE_MEMBERS = ["parts", "taskId"];
|
|
47
|
+
const PART_MEMBERS = [...CONTENT_MEMBERS, "kind"];
|
|
48
|
+
const DATA_MEMBERS = ["skill"];
|
|
49
|
+
function resolveRequestOperationDetailed(input) {
|
|
50
|
+
if (input.method !== void 0 && input.method.toUpperCase() !== "POST") return { kind: "none" };
|
|
51
|
+
const raw = typeof input.rawBody === "string" ? input.rawBody : input.rawBody?.toString("utf8");
|
|
52
|
+
if (raw === void 0 || raw.trim() === "") return unresolvable("request body is empty");
|
|
53
|
+
if (raw.charCodeAt(0) === 65279) return unresolvable("body starts with a byte order mark");
|
|
54
|
+
let body;
|
|
55
|
+
try {
|
|
56
|
+
body = (0, import_strict_json.parseStrictJson)(raw);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
return unresolvable(err instanceof import_strict_json.StrictJsonError ? `body is not strict JSON (${err.code})` : "body is not JSON");
|
|
59
|
+
}
|
|
60
|
+
if (!isPlainObject(body)) {
|
|
61
|
+
return unresolvable(Array.isArray(body) ? "JSON-RPC batches are not supported" : "body is not a JSON object");
|
|
62
|
+
}
|
|
63
|
+
if (isHttpJsonMessagePath(input.url)) {
|
|
64
|
+
return resolveMessageCarrier(body);
|
|
65
|
+
}
|
|
66
|
+
if (hasCaseVariantMember(body, ENVELOPE_MEMBERS)) return unresolvable("case variant of an envelope member");
|
|
67
|
+
const method = body.method;
|
|
68
|
+
if (method === void 0 && isJsonRpcResponse(body)) {
|
|
69
|
+
return { kind: "none" };
|
|
70
|
+
}
|
|
71
|
+
if (typeof method !== "string") return unresolvable("JSON-RPC request has no string method");
|
|
72
|
+
if (method === "tools/call") {
|
|
73
|
+
const params = body.params;
|
|
74
|
+
if (!isPlainObject(params)) return unresolvable("tools/call params is not an object");
|
|
75
|
+
if (hasCaseVariantMember(params, TOOLS_CALL_PARAMS_MEMBERS)) return unresolvable("case variant of a params member");
|
|
76
|
+
const name = params.name;
|
|
77
|
+
if (typeof name !== "string" || name.length === 0) return unresolvable("tools/call params.name is not a string");
|
|
78
|
+
return { kind: "operation", operation: name };
|
|
79
|
+
}
|
|
80
|
+
if (A2A_MESSAGE_METHODS.has(method)) {
|
|
81
|
+
const params = body.params;
|
|
82
|
+
if (!isPlainObject(params)) return unresolvable("message method params is not an object");
|
|
83
|
+
return resolveMessageCarrier(params);
|
|
84
|
+
}
|
|
85
|
+
return { kind: "none" };
|
|
86
|
+
}
|
|
87
|
+
function resolveRequestOperation(input) {
|
|
88
|
+
const resolution = resolveRequestOperationDetailed(input);
|
|
89
|
+
if (resolution.kind === "operation") return resolution.operation;
|
|
90
|
+
return resolution.kind === "none" ? void 0 : UNRESOLVABLE_OPERATION;
|
|
91
|
+
}
|
|
92
|
+
function describeUnresolvable(input) {
|
|
93
|
+
const resolution = resolveRequestOperationDetailed(input);
|
|
94
|
+
return resolution.kind === "unresolvable" ? resolution.reason : void 0;
|
|
95
|
+
}
|
|
96
|
+
function resolveMessageCarrier(container) {
|
|
97
|
+
if (hasCaseVariantMember(container, CARRIER_MEMBERS)) return unresolvable("case variant of the message member");
|
|
98
|
+
const message = container.message;
|
|
99
|
+
if (!isPlainObject(message)) return unresolvable("request carries no message object");
|
|
100
|
+
if (hasCaseVariantMember(message, MESSAGE_MEMBERS)) return unresolvable("case variant of a message member");
|
|
101
|
+
const parts = message.parts;
|
|
102
|
+
if (!Array.isArray(parts)) return unresolvable("message.parts is not an array");
|
|
103
|
+
let invocation;
|
|
104
|
+
for (const part of parts) {
|
|
105
|
+
if (!isPlainObject(part)) return unresolvable("a Part is not an object");
|
|
106
|
+
if (hasCaseVariantMember(part, PART_MEMBERS)) return unresolvable("case variant of a Part member");
|
|
107
|
+
const present = CONTENT_MEMBERS.filter((member2) => Object.prototype.hasOwnProperty.call(part, member2));
|
|
108
|
+
if (present.length !== 1) return unresolvable("a Part must carry exactly one content member");
|
|
109
|
+
const member = present[0];
|
|
110
|
+
if (FILE_MEMBERS.has(member)) return unresolvable("FileParts are not allowed on an AdCP invocation");
|
|
111
|
+
const kind = part.kind;
|
|
112
|
+
if (kind !== void 0 && kind !== member) return unresolvable("a Part kind disagrees with its content member");
|
|
113
|
+
if (member === "data") {
|
|
114
|
+
if (invocation !== void 0) return unresolvable("message carries more than one DataPart");
|
|
115
|
+
if (!isPlainObject(part.data)) return unresolvable("DataPart data is not an object");
|
|
116
|
+
invocation = part.data;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (invocation === void 0) return unresolvable("message carries no DataPart");
|
|
120
|
+
if (hasCaseVariantMember(invocation, DATA_MEMBERS)) return unresolvable("case variant of skill");
|
|
121
|
+
const skill = invocation.skill;
|
|
122
|
+
if (typeof skill !== "string" || skill.length === 0) return unresolvable("DataPart skill is not a non-empty string");
|
|
123
|
+
return { kind: "operation", operation: skill };
|
|
124
|
+
}
|
|
125
|
+
function isJsonRpcResponse(body) {
|
|
126
|
+
const has = (key) => Object.prototype.hasOwnProperty.call(body, key);
|
|
127
|
+
return (has("result") || has("error")) && !has("params");
|
|
128
|
+
}
|
|
129
|
+
function unresolvable(reason) {
|
|
130
|
+
return { kind: "unresolvable", reason };
|
|
131
|
+
}
|
|
132
|
+
function isHttpJsonMessagePath(url) {
|
|
133
|
+
if (!url) return false;
|
|
134
|
+
const queryStart = url.search(/[?#]/);
|
|
135
|
+
return HTTP_JSON_MESSAGE_PATH.test(queryStart === -1 ? url : url.slice(0, queryStart));
|
|
136
|
+
}
|
|
137
|
+
function isPlainObject(value) {
|
|
138
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
139
|
+
}
|
|
140
|
+
function hasCaseVariantMember(obj, recognized) {
|
|
141
|
+
return Object.keys(obj).some((key) => {
|
|
142
|
+
const lowered = key.toLowerCase();
|
|
143
|
+
return recognized.some((name) => name.toLowerCase() === lowered && name !== key);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
147
|
+
0 && (module.exports = {
|
|
148
|
+
A2A_MESSAGE_METHODS,
|
|
149
|
+
UNRESOLVABLE_OPERATION,
|
|
150
|
+
describeUnresolvable,
|
|
151
|
+
isUnresolvableOperation,
|
|
152
|
+
resolveRequestOperation,
|
|
153
|
+
resolveRequestOperationDetailed
|
|
154
|
+
});
|