@knownagents/sdk 1.11.0 → 2.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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![NPM version](https://img.shields.io/npm/v/@knownagents/sdk.svg)](https://npmjs.org/package/@knownagents/sdk)
4
4
 
5
- This library provides convenient access to [Known Agents](https://knownagents.com/) from server-side TypeScript or JavaScript.
5
+ This library provides convenient access to [Known Agents](https://knownagents.com/) from server-side Node.js applications written in TypeScript or JavaScript.
6
6
 
7
7
  ## Install the Package
8
8
 
@@ -24,25 +24,35 @@ const knownAgents = new KnownAgents("YOUR_ACCESS_TOKEN")
24
24
 
25
25
  ## How To Set Up Agent & LLM Analytics ([Full Docs](https://knownagents.com/docs/analytics))
26
26
 
27
- Get realtime insight into the hidden ecosystem of [crawlers, scrapers, AI agents, and other bots](https://knownagents.com/agents) browsing your website. Measure human traffic coming from AI chat and search platforms like ChatGPT, Perplexity, and Gemini.
27
+ Get realtime insight into the hidden ecosystem of [AI agents and other bots](https://knownagents.com/agents) browsing your website, REST APIs, and [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) servers. Measure human traffic coming from AI chat and search platforms like ChatGPT, Perplexity, and Gemini.
28
28
 
29
- To collect this data, call `trackVisit` for each incoming request in the endpoints where you serve your pages.
29
+ ### Track Pageview and REST Calls
30
+
31
+ To collect pageview and REST API analytics, call `trackPageviewOrRESTCall` with the incoming Node.js request and response.
30
32
 
31
33
  ```ts
32
- knownAgents.trackVisit(request)
34
+ knownAgents.trackPageviewOrRESTCall(request, response)
33
35
  ```
34
36
 
35
- For richer analytics, include the response and duration:
37
+ For REST APIs that return [ACP (Agentic Commerce Protocol)](https://www.agenticcommerce.dev/) or [UCP (Universal Commerce Protocol)](https://ucp.dev/) commerce metadata, include the response body:
36
38
 
37
39
  ```ts
38
- knownAgents.trackVisit(request, response, responseDurationInMilliseconds)
40
+ knownAgents.trackPageviewOrRESTCall(request, response, {
41
+ restACPResponseBody: acpResponseBody
42
+ })
39
43
  ```
40
44
 
41
- ### Use Middleware if Possible
45
+ ```ts
46
+ knownAgents.trackPageviewOrRESTCall(request, response, {
47
+ restUCPResponseBody: ucpResponseBody
48
+ })
49
+ ```
50
+
51
+ The SDK waits for the response to finish, then sends status, headers, duration, and any commerce metadata. Sensitive headers are filtered automatically.
42
52
 
43
- If you can, add this in middleware to track incoming requests to all pages from a single place.
53
+ #### Use Middleware if Possible
44
54
 
45
- Here's an example with Express, but you can apply this same technique with other frameworks:
55
+ If your framework supports middleware, call `trackPageviewOrRESTCall` there so pageviews and REST calls are tracked from a single place. [MCP](https://modelcontextprotocol.io/) requests are skipped automatically.
46
56
 
47
57
  ```ts
48
58
  import express from "express"
@@ -51,46 +61,75 @@ import { KnownAgents } from "@knownagents/sdk"
51
61
  const app = express()
52
62
  const knownAgents = new KnownAgents("YOUR_ACCESS_TOKEN")
53
63
 
54
- app.use((req, res, next) => {
55
- const start = Date.now()
56
- res.on('finish', () => {
57
- const duration = Date.now() - start
58
- knownAgents.trackVisit(req, res, duration)
59
- })
60
-
64
+ app.use((request, response, next) => {
65
+ knownAgents.trackPageviewOrRESTCall(request, response)
61
66
  next()
62
67
  })
63
68
 
64
- app.get("/", (req, res) => {
65
- res.send("Hello, world!")
69
+ app.get("/", (request, response) => {
70
+ response.send("Hello, world!")
66
71
  })
67
72
 
68
73
  app.listen(3000, () => console.log("Server running on port 3000"))
69
74
  ```
70
75
 
71
- ### Batch Requests If Possible
76
+ ### Track MCP Calls
72
77
 
73
- For high-traffic websites, batch multiple visits together and send them periodically (e.g. every 30 seconds) using `trackVisits`:
78
+ For [MCP](https://modelcontextprotocol.io/) servers that use `StreamableHTTPServerTransport`, call `trackMCPCall` after connecting the transport and before the transport handles the request.
79
+
80
+ For MCP calls that return [ACP](https://www.agenticcommerce.dev/) or [UCP](https://ucp.dev/) commerce metadata, the SDK captures the relevant currency and total amount automatically.
81
+
82
+ Use this order in your MCP HTTP handler:
74
83
 
75
84
  ```ts
76
- import { VisitRequest } from "@knownagents/sdk"
85
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"
86
+
87
+ const transport = new StreamableHTTPServerTransport({
88
+ sessionIdGenerator: undefined
89
+ })
90
+
91
+ await mcpServer.connect(transport)
92
+ knownAgents.trackMCPCall(request, response, transport)
93
+ await transport.handleRequest(request, response, parsedBody)
94
+ ```
95
+
96
+ Use `trackVisits` instead if the same transport instance handles concurrent requests.
77
97
 
98
+ ### Batching
99
+
100
+ For high-traffic websites, batch multiple visits together and send them periodically (e.g. every 30 seconds) using `trackVisits`. `trackVisits` can also batch MCP visits; if you do that, include the MCP fields in each `VisitRequest` and do not also call `trackMCPCall` for the same requests. Here's an Express example:
101
+
102
+ ```ts
103
+ import express from "express"
104
+ import { KnownAgents, type VisitRequest } from "@knownagents/sdk"
105
+
106
+ const app = express()
107
+ const knownAgents = new KnownAgents("YOUR_ACCESS_TOKEN")
78
108
  const visits: VisitRequest[] = []
79
109
 
80
- // Collect visits
81
- visits.push({
82
- request_path: req.url,
83
- request_method: req.method,
84
- request_headers: req.headers,
85
- response_status_code: res.statusCode,
86
- response_duration_in_milliseconds: duration,
87
- created: new Date().toISOString()
110
+ app.use((request, response, next) => {
111
+ const created = new Date()
112
+
113
+ response.once("finish", () => {
114
+ visits.push({
115
+ request_path: request.url,
116
+ request_method: request.method,
117
+ request_headers: request.headers,
118
+ response_status_code: response.statusCode,
119
+ response_headers: response.getHeaders(),
120
+ response_duration_in_milliseconds: Date.now() - created.getTime(),
121
+ created: created.toISOString()
122
+ })
123
+ })
124
+
125
+ next()
88
126
  })
89
127
 
90
- // Send batch periodically
91
128
  setInterval(() => {
92
- if (visits.length > 0) {
93
- knownAgents.trackVisits(visits.splice(0))
129
+ const batch = visits.splice(0)
130
+
131
+ if (batch.length > 0) {
132
+ knownAgents.trackVisits(batch)
94
133
  }
95
134
  }, 30000)
96
135
  ```
@@ -110,21 +149,21 @@ Protect sensitive content from unwanted access and scraping. Generate a continuo
110
149
  Use the `generateRobotsTXT` function. Select which `AgentType`s you want to block, and a string specifying which URLs are disallowed (e.g. `"/"` to disallow all paths).
111
150
 
112
151
  ```ts
152
+ import { AgentType } from "@knownagents/sdk"
153
+
113
154
  const robotsTxt = await knownAgents.generateRobotsTXT([
114
- AgentType.AIDataScraper,
115
- AgentType.Scraper,
116
- AgentType.IntelligenceGatherer,
117
- AgentType.SEOCrawler
118
- // ...
155
+ AgentType.AIDataScraper,
156
+ AgentType.AIDataProvider,
157
+ AgentType.Scraper,
158
+ AgentType.SEOCrawler
119
159
  ], "/")
120
-
121
160
  ```
122
161
 
123
162
  The return value is a plain text robots.txt string. Generate a `robotsTxt` periodically (e.g. once per day), then cache and serve it from your website's `/robots.txt` endpoint.
124
163
 
125
164
  ## How To Use Agent Identification ([Full Docs](https://knownagents.com/docs/identification))
126
165
 
127
- Use the `identifyAgent` and `identifyAgents` functions to [identify](https://knownagents.com/agents) and verify agents from network requests using Web Bot Auth (HTTP message signatures), IP matching, or other available methods. This can be useful for implementing access policies based on verified agent identity or enriching your own datasets.
166
+ Use the `identifyAgent` and `identifyAgents` functions to identify and verify [AI agents and bots](https://knownagents.com/agents) from network requests using Web Bot Auth (HTTP message signatures), IP matching, or other available methods. This can be useful for implementing access policies based on verified agent identity or enriching your own datasets.
128
167
 
129
168
  ### Identify a Single Request
130
169
 
@@ -134,9 +173,9 @@ Call `identifyAgent` with the incoming request.
134
173
  const identification = await knownAgents.identifyAgent(request)
135
174
 
136
175
  if (identification.result === "verified") {
137
- // Agent is legitimate
176
+ handleVerifiedAgent(identification)
138
177
  } else if (identification.result === "verification_failed") {
139
- // Agent is not legitimate
178
+ handleFailedVerification(identification)
140
179
  }
141
180
  ```
142
181
 
@@ -177,8 +216,8 @@ TypeScript >= 4.7 is supported.
177
216
 
178
217
  The following runtimes are supported:
179
218
 
180
- - Node.js 18 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions.
219
+ - Node.js 18 LTS or later ([non-EOL](https://endoflife.date/nodejs))
181
220
 
182
221
  ## Support
183
222
 
184
- Please [open an issue](https://github.com/knownagents/node-sdk/issues) with questions, bugs, or suggestions.
223
+ Please [open an issue](https://github.com/knownagents/node-sdk/issues) with questions, bugs, or suggestions.
@@ -0,0 +1,74 @@
1
+ import type { IncomingMessage, ServerResponse } from "http";
2
+ import type { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
3
+ import type { AgentType, IdentificationRequest, IdentificationResult, TrackPageviewOrRESTCallOptions, VisitRequest } from "./types";
4
+ /**
5
+ * Server-side client for Known Agents analytics, robots.txt generation, and agent identification.
6
+ */
7
+ export declare class KnownAgents {
8
+ private readonly accessToken;
9
+ /**
10
+ * Creates a new instance of the Known Agents client.
11
+ *
12
+ * @param accessToken - Your project's access token.
13
+ */
14
+ constructor(accessToken: string);
15
+ /**
16
+ * Tracks a single non-MCP pageview or REST API call for analytics.
17
+ * The visit is sent after the response finishes so status, headers, and duration are included.
18
+ * This method is non-blocking and handles errors internally.
19
+ *
20
+ * @param request - The incoming Node.js HTTP request.
21
+ * @param response - The outgoing Node.js HTTP response.
22
+ * @param options - Optional ACP or UCP response metadata for REST API calls.
23
+ */
24
+ trackPageviewOrRESTCall(request: IncomingMessage, response: ServerResponse, options?: TrackPageviewOrRESTCallOptions): void;
25
+ /**
26
+ * Tracks a single MCP call handled by `StreamableHTTPServerTransport`.
27
+ * Call this after connecting the transport and before the transport processes the request so request and response metadata can be captured.
28
+ * Do not use this with transport instances shared across concurrent requests; use `trackVisits()` instead.
29
+ * This method is non-blocking and handles errors internally.
30
+ *
31
+ * @param request - The incoming Node.js HTTP request.
32
+ * @param response - The outgoing Node.js HTTP response.
33
+ * @param transport - The MCP streamable HTTP transport handling the request.
34
+ */
35
+ trackMCPCall(request: IncomingMessage, response: ServerResponse, transport: StreamableHTTPServerTransport): void;
36
+ /**
37
+ * Tracks multiple visits in a batch for analytics.
38
+ * This method is non-blocking and handles errors internally.
39
+ * Recommended for high-traffic websites - batch visits and send periodically (e.g. every 30 seconds).
40
+ *
41
+ * @param requests - An array of visits.
42
+ */
43
+ trackVisits(requests: VisitRequest[]): void;
44
+ /**
45
+ * Generates a robots.txt file that disallows the specified agent types.
46
+ * The generated file stays up-to-date with all current and future agents in the specified categories.
47
+ * Cache and serve the result at your website's `/robots.txt` endpoint.
48
+ *
49
+ * @param agentTypes - An array of agent types to disallow.
50
+ * @param disallow - The path to disallow (default: "/" for all paths).
51
+ * @returns A promise that resolves to the generated robots.txt content as a string.
52
+ * @throws {Error} If the API call fails or returns a non-200 status.
53
+ */
54
+ generateRobotsTXT(agentTypes: AgentType[], disallow?: string): Promise<string>;
55
+ /**
56
+ * Identifies and verifies a single agent from an HTTP request.
57
+ * Uses Web Bot Auth (HTTP message signatures), IP matching, or other available methods.
58
+ *
59
+ * @param request - The incoming Node.js HTTP request.
60
+ * @returns A promise that resolves to the identification result.
61
+ * @throws {Error} If the API call fails or returns a non-200 status.
62
+ */
63
+ identifyAgent(request: IncomingMessage): Promise<IdentificationResult>;
64
+ /**
65
+ * Identifies and verifies multiple agents from HTTP requests in a batch.
66
+ * Uses Web Bot Auth (HTTP message signatures), IP matching, or other available methods.
67
+ *
68
+ * @param requests - An array of identification requests.
69
+ * @returns A promise that resolves to an array of identification results.
70
+ * @throws {Error} If the API call fails or returns a non-200 status.
71
+ */
72
+ identifyAgents(requests: IdentificationRequest[]): Promise<IdentificationResult[]>;
73
+ }
74
+ //# sourceMappingURL=KnownAgents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KnownAgents.d.ts","sourceRoot":"","sources":["../src/KnownAgents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAA;AAC3D,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAA;AAavG,OAAO,KAAK,EACR,SAAS,EACT,qBAAqB,EACrB,oBAAoB,EACpB,8BAA8B,EAC9B,YAAY,EACf,MAAM,SAAS,CAAA;AAqChB;;GAEG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IAEpC;;;;OAIG;gBACS,WAAW,EAAE,MAAM;IAI/B;;;;;;;;OAQG;IACH,uBAAuB,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,8BAA8B,GAAG,IAAI;IAsC3H;;;;;;;;;OASG;IACH,YAAY,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,6BAA6B,GAAG,IAAI;IAuEhH;;;;;;OAMG;IACH,WAAW,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IA6B3C;;;;;;;;;OASG;IACG,iBAAiB,CAAC,UAAU,EAAE,SAAS,EAAE,EAAE,QAAQ,GAAE,MAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAoBzF;;;;;;;OAOG;IACG,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAmB5E;;;;;;;OAOG;IACG,cAAc,CAAC,QAAQ,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;CAsB3F"}
@@ -0,0 +1,247 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KnownAgents = void 0;
4
+ const commerce_1 = require("./commerce");
5
+ const headers_1 = require("./headers");
6
+ const paths_1 = require("./paths");
7
+ /**
8
+ * Server-side client for Known Agents analytics, robots.txt generation, and agent identification.
9
+ */
10
+ class KnownAgents {
11
+ /**
12
+ * Creates a new instance of the Known Agents client.
13
+ *
14
+ * @param accessToken - Your project's access token.
15
+ */
16
+ constructor(accessToken) {
17
+ this.accessToken = accessToken;
18
+ }
19
+ /**
20
+ * Tracks a single non-MCP pageview or REST API call for analytics.
21
+ * The visit is sent after the response finishes so status, headers, and duration are included.
22
+ * This method is non-blocking and handles errors internally.
23
+ *
24
+ * @param request - The incoming Node.js HTTP request.
25
+ * @param response - The outgoing Node.js HTTP response.
26
+ * @param options - Optional ACP or UCP response metadata for REST API calls.
27
+ */
28
+ trackPageviewOrRESTCall(request, response, options) {
29
+ const isMCPCall = (0, headers_1.getIsMCPCall)(request.headers);
30
+ const path = request.url;
31
+ const method = request.method;
32
+ if (isMCPCall || !path || (0, paths_1.getIsPathExcluded)(path) || !method) {
33
+ return;
34
+ }
35
+ const created = new Date();
36
+ const sendVisit = () => {
37
+ const responseDurationInMilliseconds = Date.now() - created.getTime();
38
+ const visitRequest = {
39
+ request_path: path,
40
+ request_method: method,
41
+ request_headers: request.headers,
42
+ response_status_code: response?.statusCode,
43
+ response_headers: response.getHeaders(),
44
+ response_duration_in_milliseconds: responseDurationInMilliseconds,
45
+ acp_response_currency: options?.restACPResponseBody ? (0, commerce_1.getRESTACPCurrencyIfPossible)(options?.restACPResponseBody) : undefined,
46
+ acp_response_total_amount: options?.restACPResponseBody ? (0, commerce_1.getRESTACPTotalAmountIfPossible)(options?.restACPResponseBody) : undefined,
47
+ ucp_response_currency: options?.restUCPResponseBody ? (0, commerce_1.getRESTUCPCurrencyIfPossible)(options?.restUCPResponseBody) : undefined,
48
+ ucp_response_total_amount: options?.restUCPResponseBody ? (0, commerce_1.getRESTUCPTotalAmountIfPossible)(options?.restUCPResponseBody) : undefined,
49
+ created: created.toISOString()
50
+ };
51
+ this.trackVisits([visitRequest]);
52
+ };
53
+ if (response.writableEnded) {
54
+ sendVisit();
55
+ }
56
+ else {
57
+ response.once("finish", sendVisit);
58
+ }
59
+ }
60
+ /**
61
+ * Tracks a single MCP call handled by `StreamableHTTPServerTransport`.
62
+ * Call this after connecting the transport and before the transport processes the request so request and response metadata can be captured.
63
+ * Do not use this with transport instances shared across concurrent requests; use `trackVisits()` instead.
64
+ * This method is non-blocking and handles errors internally.
65
+ *
66
+ * @param request - The incoming Node.js HTTP request.
67
+ * @param response - The outgoing Node.js HTTP response.
68
+ * @param transport - The MCP streamable HTTP transport handling the request.
69
+ */
70
+ trackMCPCall(request, response, transport) {
71
+ const isMCPCall = (0, headers_1.getIsMCPCall)(request.headers);
72
+ const path = request.url;
73
+ const method = request.method;
74
+ if (!isMCPCall || !path || (0, paths_1.getIsPathExcluded)(path) || !method) {
75
+ return;
76
+ }
77
+ const created = new Date();
78
+ let mcpRequestBody;
79
+ let mcpResponseBody;
80
+ const originalTransportOnMessage = transport.onmessage;
81
+ transport.onmessage = (message, extra) => {
82
+ mcpRequestBody = message;
83
+ originalTransportOnMessage?.(message, extra);
84
+ };
85
+ const originalTransportSend = transport.send;
86
+ transport.send = async (message, options) => {
87
+ mcpResponseBody = message;
88
+ await originalTransportSend.call(transport, message, options);
89
+ };
90
+ const restoreTransport = () => {
91
+ transport.onmessage = originalTransportOnMessage;
92
+ transport.send = originalTransportSend;
93
+ };
94
+ const sendVisit = () => {
95
+ restoreTransport();
96
+ if (!mcpRequestBody || !mcpResponseBody) {
97
+ return;
98
+ }
99
+ const responseDurationInMilliseconds = Date.now() - created.getTime();
100
+ const visitRequest = {
101
+ request_path: path,
102
+ request_method: method,
103
+ request_headers: request.headers,
104
+ response_status_code: response?.statusCode,
105
+ response_headers: response.getHeaders(),
106
+ response_duration_in_milliseconds: responseDurationInMilliseconds,
107
+ mcp_request_method: mcpRequestBody.method,
108
+ mcp_request_tool_name: mcpRequestBody.params?.name,
109
+ mcp_request_client_info_name: mcpRequestBody.params?.clientInfo?.name,
110
+ mcp_request_client_info_version: mcpRequestBody.params?.clientInfo?.version,
111
+ mcp_response_result_is_error: mcpResponseBody.result?.isError,
112
+ mcp_response_error_code: mcpResponseBody.error?.code,
113
+ mcp_response_error_message: mcpResponseBody.error?.message,
114
+ acp_response_currency: (0, commerce_1.getMCPACPCurrencyIfPossible)(request, mcpResponseBody),
115
+ acp_response_total_amount: (0, commerce_1.getMCPACPTotalAmountIfPossible)(request, mcpResponseBody),
116
+ ucp_response_currency: (0, commerce_1.getMCPUCPCurrencyIfPossible)(request, mcpResponseBody),
117
+ ucp_response_total_amount: (0, commerce_1.getMCPUCPTotalAmountIfPossible)(request, mcpResponseBody),
118
+ created: created.toISOString()
119
+ };
120
+ this.trackVisits([visitRequest]);
121
+ };
122
+ if (response.writableEnded) {
123
+ sendVisit();
124
+ }
125
+ else {
126
+ response.once("finish", sendVisit);
127
+ }
128
+ }
129
+ /**
130
+ * Tracks multiple visits in a batch for analytics.
131
+ * This method is non-blocking and handles errors internally.
132
+ * Recommended for high-traffic websites - batch visits and send periodically (e.g. every 30 seconds).
133
+ *
134
+ * @param requests - An array of visits.
135
+ */
136
+ trackVisits(requests) {
137
+ const filteredRequests = requests
138
+ .filter((request) => {
139
+ return !(0, paths_1.getIsPathExcluded)(request.request_path);
140
+ })
141
+ .map((request) => {
142
+ return {
143
+ ...request,
144
+ request_headers: (0, headers_1.getFilteredHeaders)(request.request_headers),
145
+ response_headers: request.response_headers ? (0, headers_1.getFilteredHeaders)(request.response_headers) : undefined,
146
+ };
147
+ });
148
+ if (filteredRequests.length === 0) {
149
+ return;
150
+ }
151
+ fetch("https://api.knownagents.com/visits", {
152
+ method: "POST",
153
+ headers: {
154
+ "Authorization": `Bearer ${this.accessToken}`,
155
+ "Content-Type": "application/json"
156
+ },
157
+ body: JSON.stringify(filteredRequests)
158
+ }).catch(error => {
159
+ console.error(`Known Agents failed to track visits: ${error.message}`);
160
+ });
161
+ }
162
+ /**
163
+ * Generates a robots.txt file that disallows the specified agent types.
164
+ * The generated file stays up-to-date with all current and future agents in the specified categories.
165
+ * Cache and serve the result at your website's `/robots.txt` endpoint.
166
+ *
167
+ * @param agentTypes - An array of agent types to disallow.
168
+ * @param disallow - The path to disallow (default: "/" for all paths).
169
+ * @returns A promise that resolves to the generated robots.txt content as a string.
170
+ * @throws {Error} If the API call fails or returns a non-200 status.
171
+ */
172
+ async generateRobotsTXT(agentTypes, disallow = "/") {
173
+ const response = await fetch("https://api.knownagents.com/robots-txts", {
174
+ method: "POST",
175
+ headers: {
176
+ "Authorization": `Bearer ${this.accessToken}`,
177
+ "Content-Type": "application/json"
178
+ },
179
+ body: JSON.stringify({
180
+ agent_types: agentTypes,
181
+ disallow: disallow
182
+ })
183
+ });
184
+ if (response.ok) {
185
+ return await response.text();
186
+ }
187
+ else {
188
+ throw new Error(`Known Agents failed to generate robots.txt: ${response.status} ${response.statusText}`);
189
+ }
190
+ }
191
+ /**
192
+ * Identifies and verifies a single agent from an HTTP request.
193
+ * Uses Web Bot Auth (HTTP message signatures), IP matching, or other available methods.
194
+ *
195
+ * @param request - The incoming Node.js HTTP request.
196
+ * @returns A promise that resolves to the identification result.
197
+ * @throws {Error} If the API call fails or returns a non-200 status.
198
+ */
199
+ async identifyAgent(request) {
200
+ const response = await fetch("https://api.knownagents.com/agent-identifications", {
201
+ method: "POST",
202
+ headers: {
203
+ "Authorization": `Bearer ${this.accessToken}`,
204
+ "Content-Type": "application/json"
205
+ },
206
+ body: JSON.stringify({
207
+ request_headers: (0, headers_1.getFilteredHeaders)(request.headers)
208
+ })
209
+ });
210
+ if (response.ok) {
211
+ return await response.json();
212
+ }
213
+ else {
214
+ throw new Error(`Known Agents failed to identify agent: ${response.status} ${response.statusText}`);
215
+ }
216
+ }
217
+ /**
218
+ * Identifies and verifies multiple agents from HTTP requests in a batch.
219
+ * Uses Web Bot Auth (HTTP message signatures), IP matching, or other available methods.
220
+ *
221
+ * @param requests - An array of identification requests.
222
+ * @returns A promise that resolves to an array of identification results.
223
+ * @throws {Error} If the API call fails or returns a non-200 status.
224
+ */
225
+ async identifyAgents(requests) {
226
+ const response = await fetch("https://api.knownagents.com/agent-identifications", {
227
+ method: "POST",
228
+ headers: {
229
+ "Authorization": `Bearer ${this.accessToken}`,
230
+ "Content-Type": "application/json"
231
+ },
232
+ body: JSON.stringify(requests.map(request => {
233
+ return {
234
+ ...request,
235
+ request_headers: (0, headers_1.getFilteredHeaders)(request.request_headers),
236
+ };
237
+ }))
238
+ });
239
+ if (response.ok) {
240
+ return await response.json();
241
+ }
242
+ else {
243
+ throw new Error(`Known Agents failed to identify agents: ${response.status} ${response.statusText}`);
244
+ }
245
+ }
246
+ }
247
+ exports.KnownAgents = KnownAgents;
@@ -0,0 +1,28 @@
1
+ import type { IncomingMessage } from "http";
2
+ import type { RESTACPResponseBody, RESTUCPResponseBody } from "./types";
3
+ interface MCPCommerceResponseBody {
4
+ result?: {
5
+ currency?: string;
6
+ totals?: {
7
+ type?: string;
8
+ amount?: number;
9
+ }[];
10
+ structuredContent?: {
11
+ currency?: string;
12
+ totals?: {
13
+ type?: string;
14
+ amount?: number;
15
+ }[];
16
+ };
17
+ };
18
+ }
19
+ export declare function getRESTACPCurrencyIfPossible(restACPResponseBody: RESTACPResponseBody): string | undefined;
20
+ export declare function getRESTACPTotalAmountIfPossible(restACPResponseBody: RESTACPResponseBody): number | undefined;
21
+ export declare function getMCPACPCurrencyIfPossible(request: IncomingMessage, mcpResponseBody: MCPCommerceResponseBody): string | undefined;
22
+ export declare function getMCPACPTotalAmountIfPossible(request: IncomingMessage, mcpResponseBody: MCPCommerceResponseBody): number | undefined;
23
+ export declare function getRESTUCPCurrencyIfPossible(restUCPResponseBody: RESTUCPResponseBody): string | undefined;
24
+ export declare function getRESTUCPTotalAmountIfPossible(restUCPResponseBody: RESTUCPResponseBody): number | undefined;
25
+ export declare function getMCPUCPCurrencyIfPossible(request: IncomingMessage, mcpResponseBody: MCPCommerceResponseBody): string | undefined;
26
+ export declare function getMCPUCPTotalAmountIfPossible(request: IncomingMessage, mcpResponseBody: MCPCommerceResponseBody): number | undefined;
27
+ export {};
28
+ //# sourceMappingURL=commerce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commerce.d.ts","sourceRoot":"","sources":["../src/commerce.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AAE3C,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAEvE,UAAU,uBAAuB;IAC7B,MAAM,CAAC,EAAE;QACL,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,MAAM,CAAC,EAAE;YACL,IAAI,CAAC,EAAE,MAAM,CAAA;YACb,MAAM,CAAC,EAAE,MAAM,CAAA;SAClB,EAAE,CAAA;QACH,iBAAiB,CAAC,EAAE;YAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;YACjB,MAAM,CAAC,EAAE;gBACL,IAAI,CAAC,EAAE,MAAM,CAAA;gBACb,MAAM,CAAC,EAAE,MAAM,CAAA;aAClB,EAAE,CAAA;SACN,CAAA;KACJ,CAAA;CACJ;AAED,wBAAgB,4BAA4B,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,MAAM,GAAG,SAAS,CAEzG;AAED,wBAAgB,+BAA+B,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,MAAM,GAAG,SAAS,CAI5G;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,uBAAuB,GAAG,MAAM,GAAG,SAAS,CAGlI;AAED,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,uBAAuB,GAAG,MAAM,GAAG,SAAS,CAOrI;AAED,wBAAgB,4BAA4B,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,MAAM,GAAG,SAAS,CAEzG;AAED,wBAAgB,+BAA+B,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,MAAM,GAAG,SAAS,CAI5G;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,uBAAuB,GAAG,MAAM,GAAG,SAAS,CAGlI;AAED,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,uBAAuB,GAAG,MAAM,GAAG,SAAS,CAOrI"}
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRESTACPCurrencyIfPossible = getRESTACPCurrencyIfPossible;
4
+ exports.getRESTACPTotalAmountIfPossible = getRESTACPTotalAmountIfPossible;
5
+ exports.getMCPACPCurrencyIfPossible = getMCPACPCurrencyIfPossible;
6
+ exports.getMCPACPTotalAmountIfPossible = getMCPACPTotalAmountIfPossible;
7
+ exports.getRESTUCPCurrencyIfPossible = getRESTUCPCurrencyIfPossible;
8
+ exports.getRESTUCPTotalAmountIfPossible = getRESTUCPTotalAmountIfPossible;
9
+ exports.getMCPUCPCurrencyIfPossible = getMCPUCPCurrencyIfPossible;
10
+ exports.getMCPUCPTotalAmountIfPossible = getMCPUCPTotalAmountIfPossible;
11
+ const headers_1 = require("./headers");
12
+ function getRESTACPCurrencyIfPossible(restACPResponseBody) {
13
+ return restACPResponseBody?.currency;
14
+ }
15
+ function getRESTACPTotalAmountIfPossible(restACPResponseBody) {
16
+ return restACPResponseBody?.totals?.find((total) => {
17
+ return total.type == "total";
18
+ })?.amount;
19
+ }
20
+ function getMCPACPCurrencyIfPossible(request, mcpResponseBody) {
21
+ const isProbablyACP = !(0, headers_1.getIsUCPCall)(request.headers) && (0, headers_1.getIsProbablyACPCall)(request.headers);
22
+ return isProbablyACP ? mcpResponseBody.result?.currency : undefined;
23
+ }
24
+ function getMCPACPTotalAmountIfPossible(request, mcpResponseBody) {
25
+ const isProbablyACP = !(0, headers_1.getIsUCPCall)(request.headers) && (0, headers_1.getIsProbablyACPCall)(request.headers);
26
+ return isProbablyACP
27
+ ? mcpResponseBody.result?.totals?.find((total) => {
28
+ return total.type == "total";
29
+ })?.amount
30
+ : undefined;
31
+ }
32
+ function getRESTUCPCurrencyIfPossible(restUCPResponseBody) {
33
+ return restUCPResponseBody?.currency;
34
+ }
35
+ function getRESTUCPTotalAmountIfPossible(restUCPResponseBody) {
36
+ return restUCPResponseBody?.totals?.find((total) => {
37
+ return total.type == "total";
38
+ })?.amount;
39
+ }
40
+ function getMCPUCPCurrencyIfPossible(request, mcpResponseBody) {
41
+ const isUCP = (0, headers_1.getIsUCPCall)(request.headers);
42
+ return isUCP ? mcpResponseBody.result?.structuredContent?.currency : undefined;
43
+ }
44
+ function getMCPUCPTotalAmountIfPossible(request, mcpResponseBody) {
45
+ const isUCP = (0, headers_1.getIsUCPCall)(request.headers);
46
+ return isUCP
47
+ ? mcpResponseBody.result?.structuredContent?.totals?.find((total) => {
48
+ return total.type == "total";
49
+ })?.amount
50
+ : undefined;
51
+ }
@@ -0,0 +1,6 @@
1
+ import type { IncomingHttpHeaders, OutgoingHttpHeaders } from "http";
2
+ export declare function getFilteredHeaders<Headers extends IncomingHttpHeaders | OutgoingHttpHeaders>(headers: Headers): Headers;
3
+ export declare function getIsMCPCall(headers: IncomingHttpHeaders): boolean;
4
+ export declare function getIsUCPCall(headers: IncomingHttpHeaders): boolean;
5
+ export declare function getIsProbablyACPCall(headers: IncomingHttpHeaders): boolean;
6
+ //# sourceMappingURL=headers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAA;AA2BpE,wBAAgB,kBAAkB,CAAC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAUvH;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAIlE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAIlE;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAI1E"}