@knownagents/sdk 1.11.0 → 2.1.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,73 +24,110 @@ 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 how [AI agents and other bots](https://knownagents.com/agents) browse your web pages, call your [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) endpoints, and purchase products through your [ACP (Agentic Commerce Protocol)](https://www.agenticcommerce.dev/) and [UCP (Universal Commerce Protocol)](https://ucp.dev/) shopping flows. Measure human traffic from AI chat and search platforms like ChatGPT, Claude, 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 Pageviews and REST Calls
30
+
31
+ Call `trackPageviewOrRESTCall` with the incoming request and outgoing response. If you can, do this in middleware.
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
+ MCP calls are skipped automatically by `trackPageviewOrRESTCall`. Use `trackMCPCall` to track MCP calls.
38
+
39
+ High-traffic websites should not use this method. Instead, batch visits and send them periodically with `trackVisits` (see below).
40
+
41
+ #### Agentic Commerce Calls
42
+
43
+ For REST implementations of ACP and UCP, include the response body.
44
+
45
+ ```ts
46
+ // For ACP calls ...
47
+
48
+ knownAgents.trackPageviewOrRESTCall(request, response, {
49
+ acpResponseBody: acpResponseBody
50
+ })
51
+ ```
36
52
 
37
53
  ```ts
38
- knownAgents.trackVisit(request, response, responseDurationInMilliseconds)
54
+ // For UCP calls ...
55
+
56
+ knownAgents.trackPageviewOrRESTCall(request, response, {
57
+ ucpResponseBody: ucpResponseBody
58
+ })
39
59
  ```
40
60
 
41
- ### Use Middleware if Possible
61
+ ### Track MCP Calls
42
62
 
43
- If you can, add this in middleware to track incoming requests to all pages from a single place.
63
+ For MCP servers that use `StreamableHTTPServerTransport`, call `trackMCPCall` after connecting the transport and before the transport handles the request.
44
64
 
45
- Here's an example with Express, but you can apply this same technique with other frameworks:
65
+ High-traffic websites, or those that use the same transport instance to handle multiple concurrent requests, should not use this method. Instead, batch visits and send them periodically with `trackVisits` (see below).
46
66
 
47
67
  ```ts
48
- import express from "express"
49
- import { KnownAgents } from "@knownagents/sdk"
68
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
69
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"
50
70
 
51
- const app = express()
52
- const knownAgents = new KnownAgents("YOUR_ACCESS_TOKEN")
71
+ // ...
53
72
 
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
-
61
- next()
73
+ const mcpServer = new McpServer({
74
+ name: SERVER_NAME,
75
+ version: SERVER_VERSION,
62
76
  })
63
77
 
64
- app.get("/", (req, res) => {
65
- res.send("Hello, world!")
78
+ const transport = new StreamableHTTPServerTransport({
79
+ sessionIdGenerator: undefined
66
80
  })
67
81
 
68
- app.listen(3000, () => console.log("Server running on port 3000"))
82
+ // ...
83
+
84
+ await mcpServer.connect(transport)
85
+
86
+ knownAgents.trackMCPCall(request, response, transport)
87
+
88
+ await transport.handleRequest(request, response, parsedBody)
69
89
  ```
70
90
 
71
- ### Batch Requests If Possible
91
+ #### Agentic Commerce Calls
92
+
93
+ This method will track MCP implementations of ACP and UCP automatically.
72
94
 
73
- For high-traffic websites, batch multiple visits together and send them periodically (e.g. every 30 seconds) using `trackVisits`:
95
+ ### Batching for High-Traffic Websites
96
+
97
+ High-traffic websites should batch multiple visits together and send them periodically (e.g. every 30 seconds) using `trackVisits`. This method can track pageviews, REST, MCP, ACP, and UCP calls. Here's an example with Express middleware:
74
98
 
75
99
  ```ts
76
- import { VisitRequest } from "@knownagents/sdk"
100
+ import express from "express"
101
+ import { KnownAgents, type VisitRequest } from "@knownagents/sdk"
77
102
 
103
+ const app = express()
104
+
105
+ const knownAgents = new KnownAgents("YOUR_ACCESS_TOKEN")
78
106
  const visits: VisitRequest[] = []
79
107
 
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()
108
+ app.use((request, response, next) => {
109
+ const created = new Date()
110
+
111
+ response.once("finish", () => {
112
+ visits.push({
113
+ request_path: request.url,
114
+ request_method: request.method,
115
+ request_headers: request.headers,
116
+ response_status_code: response.statusCode,
117
+ response_headers: response.getHeaders(),
118
+ response_duration_in_milliseconds: Date.now() - created.getTime(),
119
+ created: created.toISOString()
120
+ })
121
+ })
122
+
123
+ next()
88
124
  })
89
125
 
90
- // Send batch periodically
91
126
  setInterval(() => {
92
- if (visits.length > 0) {
93
- knownAgents.trackVisits(visits.splice(0))
127
+ const batch = visits.splice(0)
128
+
129
+ if (batch.length > 0) {
130
+ knownAgents.trackVisits(batch)
94
131
  }
95
132
  }, 30000)
96
133
  ```
@@ -101,48 +138,38 @@ setInterval(() => {
101
138
  - Click **Send a Test Visit**
102
139
  - Click **Realtime**
103
140
 
104
- If your website is correctly connected, you should see visits from the Known Agent in the realtime timeline within a few seconds.
141
+ If your website is correctly connected, you should see visits from a test agent in the realtime timeline within a few seconds.
105
142
 
106
143
  ## How To Set Up Automatic Robots.txt ([Full Docs](https://knownagents.com/docs/robots-txt))
107
144
 
108
- Protect sensitive content from unwanted access and scraping. Generate a continuously updating robots.txt that stays up to date with [all current and future bots](https://knownagents.com/agents) in the specified categories automatically.
145
+ Serve a robots.txt that continuously updates with rules for new [crawlers, scrapers, AI agents, and other bots](https://knownagents.com/agents) as they're discovered.
109
146
 
110
- 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).
147
+ Use the `generateRobotsTXT` method. Select which `AgentType`s you want to block, and a string specifying which URLs are disallowed (e.g. `"/"` to disallow all paths).
111
148
 
112
149
  ```ts
150
+ import { AgentType } from "@knownagents/sdk"
151
+
113
152
  const robotsTxt = await knownAgents.generateRobotsTXT([
114
- AgentType.AIDataScraper,
115
- AgentType.Scraper,
116
- AgentType.IntelligenceGatherer,
117
- AgentType.SEOCrawler
118
- // ...
153
+ AgentType.AIDataScraper,
154
+ AgentType.AIDataProvider,
155
+ AgentType.Scraper,
156
+ AgentType.SEOCrawler
119
157
  ], "/")
120
-
121
158
  ```
122
159
 
123
- 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
-
125
- ## How To Use Agent Identification ([Full Docs](https://knownagents.com/docs/identification))
160
+ The return value is a plain text robots.txt string. Generate a `robotsTxt` periodically (e.g. once per day, using a cron job). Then, serve it from your website's `/robots.txt` endpoint.
126
161
 
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.
162
+ ## How To Use the Agent Identification API ([Full Docs](https://knownagents.com/docs/identification))
128
163
 
129
- ### Identify a Single Request
164
+ Identify and verify [AI agents and other bots](https://knownagents.com/agents) in your own products, from incoming network requests. Authentication uses Web Bot Auth (HTTP message signatures), IP matching, or other available methods. This API can be useful for implementing access policies based on verified agent identity or enriching your own datasets.
130
165
 
131
- Call `identifyAgent` with the incoming request.
166
+ Call `identifyAgent` to identify a single incoming request:
132
167
 
133
168
  ```ts
134
169
  const identification = await knownAgents.identifyAgent(request)
135
-
136
- if (identification.result === "verified") {
137
- // Agent is legitimate
138
- } else if (identification.result === "verification_failed") {
139
- // Agent is not legitimate
140
- }
141
170
  ```
142
171
 
143
- ### Identify Multiple Requests
144
-
145
- Use `identifyAgents` to identify multiple requests at once:
172
+ Call `identifyAgents` to identify multiple requests at once:
146
173
 
147
174
  ```ts
148
175
  const identifications = await knownAgents.identifyAgents([
@@ -157,7 +184,7 @@ const identifications = await knownAgents.identifyAgents([
157
184
  ])
158
185
  ```
159
186
 
160
- The functions return an object (or array of objects) with the following fields:
187
+ These methods return an object (or array of objects) with the following fields:
161
188
 
162
189
  - `id`: The identifier from the request (if provided)
163
190
  - `result`: The identification result:
@@ -177,8 +204,8 @@ TypeScript >= 4.7 is supported.
177
204
 
178
205
  The following runtimes are supported:
179
206
 
180
- - Node.js 18 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions.
207
+ - Node.js 18 LTS or later ([non-EOL](https://endoflife.date/nodejs))
181
208
 
182
209
  ## Support
183
210
 
184
- Please [open an issue](https://github.com/knownagents/node-sdk/issues) with questions, bugs, or suggestions.
211
+ 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;AAGvG,OAAO,KAAK,EACR,SAAS,EACT,qBAAqB,EACrB,oBAAoB,EACpB,8BAA8B,EAC9B,YAAY,EACf,MAAM,SAAS,CAAA;AAEhB;;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;IAoC3H;;;;;;;;;OASG;IACH,YAAY,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,6BAA6B,GAAG,IAAI;IAqEhH;;;;;;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,242 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KnownAgents = void 0;
4
+ const headers_1 = require("./headers");
5
+ const paths_1 = require("./paths");
6
+ /**
7
+ * Server-side client for Known Agents analytics, robots.txt generation, and agent identification.
8
+ */
9
+ class KnownAgents {
10
+ /**
11
+ * Creates a new instance of the Known Agents client.
12
+ *
13
+ * @param accessToken - Your project's access token.
14
+ */
15
+ constructor(accessToken) {
16
+ this.accessToken = accessToken;
17
+ }
18
+ /**
19
+ * Tracks a single non-MCP pageview or REST API call for analytics.
20
+ * The visit is sent after the response finishes so status, headers, and duration are included.
21
+ * This method is non-blocking and handles errors internally.
22
+ *
23
+ * @param request - The incoming Node.js HTTP request.
24
+ * @param response - The outgoing Node.js HTTP response.
25
+ * @param options - Optional ACP or UCP response metadata for REST API calls.
26
+ */
27
+ trackPageviewOrRESTCall(request, response, options) {
28
+ const isMCPCall = (0, headers_1.getIsMCPCall)(request.headers);
29
+ const path = request.url;
30
+ const method = request.method;
31
+ if (isMCPCall || !path || (0, paths_1.getIsPathExcluded)(path) || !method) {
32
+ return;
33
+ }
34
+ const created = new Date();
35
+ const sendVisit = () => {
36
+ const responseDurationInMilliseconds = Date.now() - created.getTime();
37
+ const visitRequest = {
38
+ request_path: path,
39
+ request_method: method,
40
+ request_headers: request.headers,
41
+ response_status_code: response?.statusCode,
42
+ response_headers: response.getHeaders(),
43
+ response_duration_in_milliseconds: responseDurationInMilliseconds,
44
+ acp_response_body: options?.acpResponseBody,
45
+ ucp_response_body: options?.ucpResponseBody,
46
+ created: created.toISOString()
47
+ };
48
+ this.trackVisits([visitRequest]);
49
+ };
50
+ if (response.writableEnded) {
51
+ sendVisit();
52
+ }
53
+ else {
54
+ response.once("finish", sendVisit);
55
+ }
56
+ }
57
+ /**
58
+ * Tracks a single MCP call handled by `StreamableHTTPServerTransport`.
59
+ * Call this after connecting the transport and before the transport processes the request so request and response metadata can be captured.
60
+ * Do not use this with transport instances shared across concurrent requests; use `trackVisits()` instead.
61
+ * This method is non-blocking and handles errors internally.
62
+ *
63
+ * @param request - The incoming Node.js HTTP request.
64
+ * @param response - The outgoing Node.js HTTP response.
65
+ * @param transport - The MCP streamable HTTP transport handling the request.
66
+ */
67
+ trackMCPCall(request, response, transport) {
68
+ const path = request.url;
69
+ const method = request.method;
70
+ if (!path || (0, paths_1.getIsPathExcluded)(path) || !method) {
71
+ return;
72
+ }
73
+ const created = new Date();
74
+ let mcpRequestBody;
75
+ let mcpResponseBody;
76
+ const originalTransportOnMessage = transport.onmessage;
77
+ transport.onmessage = (message, extra) => {
78
+ mcpRequestBody = message;
79
+ originalTransportOnMessage?.(message, extra);
80
+ };
81
+ const originalTransportSend = transport.send;
82
+ transport.send = async (message, options) => {
83
+ mcpResponseBody = message;
84
+ await originalTransportSend.call(transport, message, options);
85
+ };
86
+ const restoreTransport = () => {
87
+ transport.onmessage = originalTransportOnMessage;
88
+ transport.send = originalTransportSend;
89
+ };
90
+ const sendVisit = () => {
91
+ restoreTransport();
92
+ if (!mcpRequestBody || !mcpResponseBody) {
93
+ return;
94
+ }
95
+ const responseDurationInMilliseconds = Date.now() - created.getTime();
96
+ const mcpResponseResult = mcpResponseBody.result?.structuredContent ?? mcpResponseBody.result;
97
+ const visitRequest = {
98
+ request_path: path,
99
+ request_method: method,
100
+ request_headers: request.headers,
101
+ response_status_code: response?.statusCode,
102
+ response_headers: response.getHeaders(),
103
+ response_duration_in_milliseconds: responseDurationInMilliseconds,
104
+ mcp_request_method: mcpRequestBody.method,
105
+ mcp_request_tool_name: mcpRequestBody.params?.name,
106
+ mcp_request_client_info_name: mcpRequestBody.params?.clientInfo?.name,
107
+ mcp_request_client_info_version: mcpRequestBody.params?.clientInfo?.version,
108
+ mcp_response_result_is_error: mcpResponseBody.result?.isError,
109
+ mcp_response_error_code: mcpResponseBody.error?.code,
110
+ mcp_response_error_message: mcpResponseBody.error?.message,
111
+ acp_response_body: (0, headers_1.getIsACPCall)(request.headers) ? mcpResponseResult : undefined,
112
+ ucp_response_body: (0, headers_1.getIsUCPCall)(request.headers) ? mcpResponseResult : undefined,
113
+ created: created.toISOString()
114
+ };
115
+ this.trackVisits([visitRequest]);
116
+ };
117
+ if (response.writableEnded) {
118
+ sendVisit();
119
+ }
120
+ else {
121
+ response.once("finish", sendVisit);
122
+ }
123
+ }
124
+ /**
125
+ * Tracks multiple visits in a batch for analytics.
126
+ * This method is non-blocking and handles errors internally.
127
+ * Recommended for high-traffic websites - batch visits and send periodically (e.g. every 30 seconds).
128
+ *
129
+ * @param requests - An array of visits.
130
+ */
131
+ trackVisits(requests) {
132
+ const filteredRequests = requests
133
+ .filter((request) => {
134
+ return !(0, paths_1.getIsPathExcluded)(request.request_path);
135
+ })
136
+ .map((request) => {
137
+ return {
138
+ ...request,
139
+ request_headers: (0, headers_1.getFilteredHeaders)(request.request_headers),
140
+ response_headers: request.response_headers ? (0, headers_1.getFilteredHeaders)(request.response_headers) : undefined,
141
+ };
142
+ });
143
+ if (filteredRequests.length === 0) {
144
+ return;
145
+ }
146
+ fetch("https://api.knownagents.com/visits", {
147
+ method: "POST",
148
+ headers: {
149
+ "Authorization": `Bearer ${this.accessToken}`,
150
+ "Content-Type": "application/json"
151
+ },
152
+ body: JSON.stringify(filteredRequests)
153
+ }).catch(error => {
154
+ console.error(`Known Agents failed to track visits: ${error.message}`);
155
+ });
156
+ }
157
+ /**
158
+ * Generates a robots.txt file that disallows the specified agent types.
159
+ * The generated file stays up-to-date with all current and future agents in the specified categories.
160
+ * Cache and serve the result at your website's `/robots.txt` endpoint.
161
+ *
162
+ * @param agentTypes - An array of agent types to disallow.
163
+ * @param disallow - The path to disallow (default: "/" for all paths).
164
+ * @returns A promise that resolves to the generated robots.txt content as a string.
165
+ * @throws {Error} If the API call fails or returns a non-200 status.
166
+ */
167
+ async generateRobotsTXT(agentTypes, disallow = "/") {
168
+ const response = await fetch("https://api.knownagents.com/robots-txts", {
169
+ method: "POST",
170
+ headers: {
171
+ "Authorization": `Bearer ${this.accessToken}`,
172
+ "Content-Type": "application/json"
173
+ },
174
+ body: JSON.stringify({
175
+ agent_types: agentTypes,
176
+ disallow: disallow
177
+ })
178
+ });
179
+ if (response.ok) {
180
+ return await response.text();
181
+ }
182
+ else {
183
+ throw new Error(`Known Agents failed to generate robots.txt: ${response.status} ${response.statusText}`);
184
+ }
185
+ }
186
+ /**
187
+ * Identifies and verifies a single agent from an HTTP request.
188
+ * Uses Web Bot Auth (HTTP message signatures), IP matching, or other available methods.
189
+ *
190
+ * @param request - The incoming Node.js HTTP request.
191
+ * @returns A promise that resolves to the identification result.
192
+ * @throws {Error} If the API call fails or returns a non-200 status.
193
+ */
194
+ async identifyAgent(request) {
195
+ const response = await fetch("https://api.knownagents.com/agent-identifications", {
196
+ method: "POST",
197
+ headers: {
198
+ "Authorization": `Bearer ${this.accessToken}`,
199
+ "Content-Type": "application/json"
200
+ },
201
+ body: JSON.stringify({
202
+ request_headers: (0, headers_1.getFilteredHeaders)(request.headers)
203
+ })
204
+ });
205
+ if (response.ok) {
206
+ return await response.json();
207
+ }
208
+ else {
209
+ throw new Error(`Known Agents failed to identify agent: ${response.status} ${response.statusText}`);
210
+ }
211
+ }
212
+ /**
213
+ * Identifies and verifies multiple agents from HTTP requests in a batch.
214
+ * Uses Web Bot Auth (HTTP message signatures), IP matching, or other available methods.
215
+ *
216
+ * @param requests - An array of identification requests.
217
+ * @returns A promise that resolves to an array of identification results.
218
+ * @throws {Error} If the API call fails or returns a non-200 status.
219
+ */
220
+ async identifyAgents(requests) {
221
+ const response = await fetch("https://api.knownagents.com/agent-identifications", {
222
+ method: "POST",
223
+ headers: {
224
+ "Authorization": `Bearer ${this.accessToken}`,
225
+ "Content-Type": "application/json"
226
+ },
227
+ body: JSON.stringify(requests.map(request => {
228
+ return {
229
+ ...request,
230
+ request_headers: (0, headers_1.getFilteredHeaders)(request.request_headers),
231
+ };
232
+ }))
233
+ });
234
+ if (response.ok) {
235
+ return await response.json();
236
+ }
237
+ else {
238
+ throw new Error(`Known Agents failed to identify agents: ${response.status} ${response.statusText}`);
239
+ }
240
+ }
241
+ }
242
+ 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 getIsACPCall(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,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAIlE"}