@knownagents/sdk 2.1.0 → 2.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/README.md +34 -71
- package/dist/KnownAgents.d.ts +23 -8
- package/dist/KnownAgents.d.ts.map +1 -1
- package/dist/KnownAgents.js +70 -19
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +10 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/KnownAgents.ts +90 -24
- package/src/index.ts +1 -0
- package/src/types.ts +11 -1
- package/dist/commerce.d.ts +0 -28
- package/dist/commerce.d.ts.map +0 -1
- package/dist/commerce.js +0 -51
package/README.md
CHANGED
|
@@ -22,48 +22,33 @@ import { KnownAgents } from "@knownagents/sdk"
|
|
|
22
22
|
const knownAgents = new KnownAgents("YOUR_ACCESS_TOKEN")
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
29
|
-
### Track Pageviews and REST Calls
|
|
30
|
-
|
|
31
|
-
Call `trackPageviewOrRESTCall` with the incoming request and outgoing response. If you can, do this in middleware.
|
|
25
|
+
To batch visits, set the visit event queue size and flush interval:
|
|
32
26
|
|
|
33
27
|
```ts
|
|
34
|
-
knownAgents
|
|
28
|
+
const knownAgents = new KnownAgents("YOUR_ACCESS_TOKEN", {
|
|
29
|
+
flushQueueSize: 1000,
|
|
30
|
+
flushIntervalInMilliseconds: 10000
|
|
31
|
+
})
|
|
35
32
|
```
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
High-traffic websites should not use this method. Instead, batch visits and send them periodically with `trackVisits` (see below).
|
|
34
|
+
The entire visit event queue is uploaded when it reaches `flushQueueSize` or when the flush interval elapses after the first visit event enters an empty queue.
|
|
40
35
|
|
|
41
|
-
|
|
36
|
+
## Send Visit Events ([Agent Analytics](https://knownagents.com/products/agent-analytics), [LLM Referral Tracking](https://knownagents.com/products/llm-referral-tracking))
|
|
42
37
|
|
|
43
|
-
|
|
38
|
+
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.
|
|
44
39
|
|
|
45
|
-
|
|
46
|
-
// For ACP calls ...
|
|
40
|
+
### Pageviews and REST Calls
|
|
47
41
|
|
|
48
|
-
|
|
49
|
-
acpResponseBody: acpResponseBody
|
|
50
|
-
})
|
|
51
|
-
```
|
|
42
|
+
Call `trackPageviewOrRESTCall` with the incoming request and outgoing response. If you can, do this in middleware. This method skips MCP calls automatically.
|
|
52
43
|
|
|
53
44
|
```ts
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
knownAgents.trackPageviewOrRESTCall(request, response, {
|
|
57
|
-
ucpResponseBody: ucpResponseBody
|
|
58
|
-
})
|
|
45
|
+
knownAgents.trackPageviewOrRESTCall(request, response)
|
|
59
46
|
```
|
|
60
47
|
|
|
61
|
-
###
|
|
48
|
+
### MCP Calls (Optional)
|
|
62
49
|
|
|
63
50
|
For MCP servers that use `StreamableHTTPServerTransport`, call `trackMCPCall` after connecting the transport and before the transport handles the request.
|
|
64
51
|
|
|
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).
|
|
66
|
-
|
|
67
52
|
```ts
|
|
68
53
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
|
|
69
54
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"
|
|
@@ -88,50 +73,28 @@ knownAgents.trackMCPCall(request, response, transport)
|
|
|
88
73
|
await transport.handleRequest(request, response, parsedBody)
|
|
89
74
|
```
|
|
90
75
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
This method will track MCP implementations of ACP and UCP automatically.
|
|
94
|
-
|
|
95
|
-
### Batching for High-Traffic Websites
|
|
76
|
+
### Agentic Commerce Interactions (Optional)
|
|
96
77
|
|
|
97
|
-
|
|
78
|
+
For REST implementations of ACP and UCP, include the response body in `trackPageviewOrRESTCall`.
|
|
98
79
|
|
|
99
80
|
```ts
|
|
100
|
-
|
|
101
|
-
import { KnownAgents, type VisitRequest } from "@knownagents/sdk"
|
|
102
|
-
|
|
103
|
-
const app = express()
|
|
81
|
+
// For ACP calls ...
|
|
104
82
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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()
|
|
83
|
+
knownAgents.trackPageviewOrRESTCall(request, response, {
|
|
84
|
+
acpResponseBody: acpResponseBody
|
|
124
85
|
})
|
|
86
|
+
```
|
|
125
87
|
|
|
126
|
-
|
|
127
|
-
|
|
88
|
+
```ts
|
|
89
|
+
// For UCP calls ...
|
|
128
90
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}, 30000)
|
|
91
|
+
knownAgents.trackPageviewOrRESTCall(request, response, {
|
|
92
|
+
ucpResponseBody: ucpResponseBody
|
|
93
|
+
})
|
|
133
94
|
```
|
|
134
95
|
|
|
96
|
+
`trackMCPCall` will track MCP implementations of ACP and UCP automatically.
|
|
97
|
+
|
|
135
98
|
### Test Your Integration
|
|
136
99
|
|
|
137
100
|
- Open your project's settings page
|
|
@@ -140,7 +103,7 @@ setInterval(() => {
|
|
|
140
103
|
|
|
141
104
|
If your website is correctly connected, you should see visits from a test agent in the realtime timeline within a few seconds.
|
|
142
105
|
|
|
143
|
-
##
|
|
106
|
+
## Set Up Automatic Robots.txt ([Automatic Robots.txt](https://knownagents.com/products/automatic-robots-txt))
|
|
144
107
|
|
|
145
108
|
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.
|
|
146
109
|
|
|
@@ -159,7 +122,7 @@ const robotsTxt = await knownAgents.generateRobotsTXT([
|
|
|
159
122
|
|
|
160
123
|
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.
|
|
161
124
|
|
|
162
|
-
##
|
|
125
|
+
## Use the Agent Identification API ([Agent Identification API](https://knownagents.com/products/agent-identification-api))
|
|
163
126
|
|
|
164
127
|
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.
|
|
165
128
|
|
|
@@ -188,15 +151,15 @@ These methods return an object (or array of objects) with the following fields:
|
|
|
188
151
|
|
|
189
152
|
- `id`: The identifier from the request (if provided)
|
|
190
153
|
- `result`: The identification result:
|
|
191
|
-
- `"verified"`: The agent
|
|
192
|
-
- `"verification_failed"`: The agent was identified but
|
|
193
|
-
- `"
|
|
194
|
-
- `"
|
|
154
|
+
- `"verified"`: The agent was identified and verified
|
|
155
|
+
- `"verification_failed"`: The agent was identified but failed verification (it was spoofed)
|
|
156
|
+
- `"not_verifiable"`: The agent was identified but could not be verified (no method available)
|
|
157
|
+
- `"unknown_agent"`: Not an agent, or the agent is not in the database
|
|
195
158
|
- `agent_id`: The unique ID of the agent (if identified)
|
|
196
|
-
- `agent_token`: The name of the agent (e.g. `"
|
|
159
|
+
- `agent_token`: The name of the agent (e.g. `"Claude-User"`) (if identified)
|
|
197
160
|
- `agent_url`: The documentation URL of the agent (if identified)
|
|
198
|
-
- `agent_type_name`: The type of agent (e.g. `"AI
|
|
199
|
-
- `operator_name`: The company
|
|
161
|
+
- `agent_type_name`: The type of agent (e.g. `"AI Assistant"`) (if identified)
|
|
162
|
+
- `operator_name`: The company operating the agent (e.g. `"Anthropic"`) (if identified)
|
|
200
163
|
|
|
201
164
|
## Requirements
|
|
202
165
|
|
package/dist/KnownAgents.d.ts
CHANGED
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from "http";
|
|
2
2
|
import type { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
3
|
-
import type { AgentType, IdentificationRequest, IdentificationResult, TrackPageviewOrRESTCallOptions, VisitRequest } from "./types";
|
|
3
|
+
import type { AgentType, IdentificationRequest, IdentificationResult, KnownAgentsOptions, TrackPageviewOrRESTCallOptions, VisitRequest } from "./types";
|
|
4
4
|
/**
|
|
5
5
|
* Server-side client for Known Agents analytics, robots.txt generation, and agent identification.
|
|
6
6
|
*/
|
|
7
7
|
export declare class KnownAgents {
|
|
8
8
|
private readonly accessToken;
|
|
9
|
+
private readonly flushIntervalInMilliseconds;
|
|
10
|
+
private readonly flushQueueSize;
|
|
11
|
+
private readonly visitQueue;
|
|
12
|
+
private flushTimeout;
|
|
13
|
+
private pendingFlushPromise;
|
|
9
14
|
/**
|
|
10
15
|
* Creates a new instance of the Known Agents client.
|
|
11
16
|
*
|
|
12
17
|
* @param accessToken - Your project's access token.
|
|
18
|
+
* @param options - Optional batching configuration.
|
|
13
19
|
*/
|
|
14
|
-
constructor(accessToken: string);
|
|
20
|
+
constructor(accessToken: string, options?: KnownAgentsOptions);
|
|
15
21
|
/**
|
|
16
22
|
* Tracks a single non-MCP pageview or REST API call for analytics.
|
|
17
|
-
* The visit is
|
|
18
|
-
* This method is non-blocking and handles errors internally.
|
|
23
|
+
* The visit is added to the visit event queue after the response finishes so status, headers, and duration are included.
|
|
24
|
+
* This method is non-blocking and handles upload errors internally.
|
|
19
25
|
*
|
|
20
26
|
* @param request - The incoming Node.js HTTP request.
|
|
21
27
|
* @param response - The outgoing Node.js HTTP response.
|
|
@@ -26,7 +32,7 @@ export declare class KnownAgents {
|
|
|
26
32
|
* Tracks a single MCP call handled by `StreamableHTTPServerTransport`.
|
|
27
33
|
* Call this after connecting the transport and before the transport processes the request so request and response metadata can be captured.
|
|
28
34
|
* Do not use this with transport instances shared across concurrent requests; use `trackVisits()` instead.
|
|
29
|
-
* This method is non-blocking and handles errors internally.
|
|
35
|
+
* This method is non-blocking and handles upload errors internally.
|
|
30
36
|
*
|
|
31
37
|
* @param request - The incoming Node.js HTTP request.
|
|
32
38
|
* @param response - The outgoing Node.js HTTP response.
|
|
@@ -34,13 +40,20 @@ export declare class KnownAgents {
|
|
|
34
40
|
*/
|
|
35
41
|
trackMCPCall(request: IncomingMessage, response: ServerResponse, transport: StreamableHTTPServerTransport): void;
|
|
36
42
|
/**
|
|
37
|
-
*
|
|
38
|
-
* This method is non-blocking and handles errors internally.
|
|
39
|
-
*
|
|
43
|
+
* Adds multiple visits to the visit event queue for analytics.
|
|
44
|
+
* This method is non-blocking and handles upload errors internally.
|
|
45
|
+
* All visit events are uploaded together when the queue size reaches the configured threshold or the flush interval elapses.
|
|
40
46
|
*
|
|
41
47
|
* @param requests - An array of visits.
|
|
42
48
|
*/
|
|
43
49
|
trackVisits(requests: VisitRequest[]): void;
|
|
50
|
+
/**
|
|
51
|
+
* Uploads all events currently in the visit event queue and waits for pending uploads to finish.
|
|
52
|
+
* This method handles upload errors internally.
|
|
53
|
+
*
|
|
54
|
+
* @returns A promise that resolves after all pending upload attempts finish.
|
|
55
|
+
*/
|
|
56
|
+
flush(): Promise<void>;
|
|
44
57
|
/**
|
|
45
58
|
* Generates a robots.txt file that disallows the specified agent types.
|
|
46
59
|
* The generated file stays up-to-date with all current and future agents in the specified categories.
|
|
@@ -70,5 +83,7 @@ export declare class KnownAgents {
|
|
|
70
83
|
* @throws {Error} If the API call fails or returns a non-200 status.
|
|
71
84
|
*/
|
|
72
85
|
identifyAgents(requests: IdentificationRequest[]): Promise<IdentificationResult[]>;
|
|
86
|
+
private scheduleFlush;
|
|
87
|
+
private sendVisits;
|
|
73
88
|
}
|
|
74
89
|
//# sourceMappingURL=KnownAgents.d.ts.map
|
|
@@ -1 +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;
|
|
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,kBAAkB,EAClB,8BAA8B,EAC9B,YAAY,EACf,MAAM,SAAS,CAAA;AAKhB;;GAEG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IACpC,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAQ;IACpD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,mBAAmB,CAAmC;IAE9D;;;;;OAKG;gBACS,WAAW,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB;IAMjE;;;;;;;;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;IAoEhH;;;;;;OAMG;IACH,WAAW,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IA2B3C;;;;;OAKG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBtB;;;;;;;;;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;IAsBxF,OAAO,CAAC,aAAa;YAaP,UAAU;CAmB3B"}
|
package/dist/KnownAgents.js
CHANGED
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.KnownAgents = void 0;
|
|
4
4
|
const headers_1 = require("./headers");
|
|
5
5
|
const paths_1 = require("./paths");
|
|
6
|
+
const DEFAULT_FLUSH_INTERVAL_IN_MILLISECONDS = 10000;
|
|
7
|
+
const DEFAULT_FLUSH_QUEUE_SIZE = 1;
|
|
6
8
|
/**
|
|
7
9
|
* Server-side client for Known Agents analytics, robots.txt generation, and agent identification.
|
|
8
10
|
*/
|
|
@@ -11,14 +13,19 @@ class KnownAgents {
|
|
|
11
13
|
* Creates a new instance of the Known Agents client.
|
|
12
14
|
*
|
|
13
15
|
* @param accessToken - Your project's access token.
|
|
16
|
+
* @param options - Optional batching configuration.
|
|
14
17
|
*/
|
|
15
|
-
constructor(accessToken) {
|
|
18
|
+
constructor(accessToken, options = {}) {
|
|
19
|
+
this.visitQueue = [];
|
|
20
|
+
this.pendingFlushPromise = Promise.resolve();
|
|
16
21
|
this.accessToken = accessToken;
|
|
22
|
+
this.flushIntervalInMilliseconds = options.flushIntervalInMilliseconds ?? DEFAULT_FLUSH_INTERVAL_IN_MILLISECONDS;
|
|
23
|
+
this.flushQueueSize = options.flushQueueSize ?? DEFAULT_FLUSH_QUEUE_SIZE;
|
|
17
24
|
}
|
|
18
25
|
/**
|
|
19
26
|
* Tracks a single non-MCP pageview or REST API call for analytics.
|
|
20
|
-
* The visit is
|
|
21
|
-
* This method is non-blocking and handles errors internally.
|
|
27
|
+
* The visit is added to the visit event queue after the response finishes so status, headers, and duration are included.
|
|
28
|
+
* This method is non-blocking and handles upload errors internally.
|
|
22
29
|
*
|
|
23
30
|
* @param request - The incoming Node.js HTTP request.
|
|
24
31
|
* @param response - The outgoing Node.js HTTP response.
|
|
@@ -58,7 +65,7 @@ class KnownAgents {
|
|
|
58
65
|
* Tracks a single MCP call handled by `StreamableHTTPServerTransport`.
|
|
59
66
|
* Call this after connecting the transport and before the transport processes the request so request and response metadata can be captured.
|
|
60
67
|
* Do not use this with transport instances shared across concurrent requests; use `trackVisits()` instead.
|
|
61
|
-
* This method is non-blocking and handles errors internally.
|
|
68
|
+
* This method is non-blocking and handles upload errors internally.
|
|
62
69
|
*
|
|
63
70
|
* @param request - The incoming Node.js HTTP request.
|
|
64
71
|
* @param response - The outgoing Node.js HTTP response.
|
|
@@ -93,7 +100,6 @@ class KnownAgents {
|
|
|
93
100
|
return;
|
|
94
101
|
}
|
|
95
102
|
const responseDurationInMilliseconds = Date.now() - created.getTime();
|
|
96
|
-
const mcpResponseResult = mcpResponseBody.result?.structuredContent ?? mcpResponseBody.result;
|
|
97
103
|
const visitRequest = {
|
|
98
104
|
request_path: path,
|
|
99
105
|
request_method: method,
|
|
@@ -108,8 +114,8 @@ class KnownAgents {
|
|
|
108
114
|
mcp_response_result_is_error: mcpResponseBody.result?.isError,
|
|
109
115
|
mcp_response_error_code: mcpResponseBody.error?.code,
|
|
110
116
|
mcp_response_error_message: mcpResponseBody.error?.message,
|
|
111
|
-
acp_response_body: (0, headers_1.getIsACPCall)(request.headers) ?
|
|
112
|
-
ucp_response_body: (0, headers_1.getIsUCPCall)(request.headers) ?
|
|
117
|
+
acp_response_body: (0, headers_1.getIsACPCall)(request.headers) ? mcpResponseBody.result?.structuredContent ?? mcpResponseBody.result : undefined,
|
|
118
|
+
ucp_response_body: (0, headers_1.getIsUCPCall)(request.headers) ? mcpResponseBody.result?.structuredContent ?? mcpResponseBody.result : undefined,
|
|
113
119
|
created: created.toISOString()
|
|
114
120
|
};
|
|
115
121
|
this.trackVisits([visitRequest]);
|
|
@@ -122,9 +128,9 @@ class KnownAgents {
|
|
|
122
128
|
}
|
|
123
129
|
}
|
|
124
130
|
/**
|
|
125
|
-
*
|
|
126
|
-
* This method is non-blocking and handles errors internally.
|
|
127
|
-
*
|
|
131
|
+
* Adds multiple visits to the visit event queue for analytics.
|
|
132
|
+
* This method is non-blocking and handles upload errors internally.
|
|
133
|
+
* All visit events are uploaded together when the queue size reaches the configured threshold or the flush interval elapses.
|
|
128
134
|
*
|
|
129
135
|
* @param requests - An array of visits.
|
|
130
136
|
*/
|
|
@@ -143,16 +149,32 @@ class KnownAgents {
|
|
|
143
149
|
if (filteredRequests.length === 0) {
|
|
144
150
|
return;
|
|
145
151
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
152
|
+
this.visitQueue.push(...filteredRequests);
|
|
153
|
+
if (this.visitQueue.length >= this.flushQueueSize) {
|
|
154
|
+
void this.flush();
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
this.scheduleFlush();
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Uploads all events currently in the visit event queue and waits for pending uploads to finish.
|
|
161
|
+
* This method handles upload errors internally.
|
|
162
|
+
*
|
|
163
|
+
* @returns A promise that resolves after all pending upload attempts finish.
|
|
164
|
+
*/
|
|
165
|
+
flush() {
|
|
166
|
+
if (this.flushTimeout) {
|
|
167
|
+
clearTimeout(this.flushTimeout);
|
|
168
|
+
this.flushTimeout = undefined;
|
|
169
|
+
}
|
|
170
|
+
const requests = this.visitQueue.splice(0);
|
|
171
|
+
if (requests.length === 0) {
|
|
172
|
+
return this.pendingFlushPromise;
|
|
173
|
+
}
|
|
174
|
+
this.pendingFlushPromise = this.pendingFlushPromise.then(() => {
|
|
175
|
+
return this.sendVisits(requests);
|
|
155
176
|
});
|
|
177
|
+
return this.pendingFlushPromise;
|
|
156
178
|
}
|
|
157
179
|
/**
|
|
158
180
|
* Generates a robots.txt file that disallows the specified agent types.
|
|
@@ -238,5 +260,34 @@ class KnownAgents {
|
|
|
238
260
|
throw new Error(`Known Agents failed to identify agents: ${response.status} ${response.statusText}`);
|
|
239
261
|
}
|
|
240
262
|
}
|
|
263
|
+
scheduleFlush() {
|
|
264
|
+
if (this.flushTimeout) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
this.flushTimeout = setTimeout(() => {
|
|
268
|
+
this.flushTimeout = undefined;
|
|
269
|
+
void this.flush();
|
|
270
|
+
}, this.flushIntervalInMilliseconds);
|
|
271
|
+
this.flushTimeout.unref();
|
|
272
|
+
}
|
|
273
|
+
async sendVisits(requests) {
|
|
274
|
+
try {
|
|
275
|
+
const response = await fetch("https://api.knownagents.com/visits", {
|
|
276
|
+
method: "POST",
|
|
277
|
+
headers: {
|
|
278
|
+
"Authorization": `Bearer ${this.accessToken}`,
|
|
279
|
+
"Content-Type": "application/json"
|
|
280
|
+
},
|
|
281
|
+
body: JSON.stringify(requests)
|
|
282
|
+
});
|
|
283
|
+
if (!response.ok) {
|
|
284
|
+
throw new Error(`${response.status} ${response.statusText}`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
289
|
+
console.error(`Known Agents failed to track visits: ${message}`);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
241
292
|
}
|
|
242
293
|
exports.KnownAgents = KnownAgents;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { KnownAgents } from "./KnownAgents";
|
|
2
|
-
export { AgentType, type IdentificationRequest, type IdentificationResult, type TrackPageviewOrRESTCallOptions, type VisitRequest } from "./types";
|
|
2
|
+
export { AgentType, type IdentificationRequest, type IdentificationResult, type KnownAgentsOptions, type TrackPageviewOrRESTCallOptions, type VisitRequest } from "./types";
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EACH,SAAS,EACT,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,8BAA8B,EACnC,KAAK,YAAY,EACpB,MAAM,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EACH,SAAS,EACT,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,8BAA8B,EACnC,KAAK,YAAY,EACpB,MAAM,SAAS,CAAA"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import type { IncomingHttpHeaders, OutgoingHttpHeaders } from "http";
|
|
2
|
+
/**
|
|
3
|
+
* Batching configuration for the Known Agents client.
|
|
4
|
+
*/
|
|
5
|
+
export interface KnownAgentsOptions {
|
|
6
|
+
/** The maximum time a partial visit event queue waits before upload. Defaults to 10,000 milliseconds. */
|
|
7
|
+
flushIntervalInMilliseconds?: number;
|
|
8
|
+
/** The number of visit events in the queue that triggers an upload. Defaults to 1. */
|
|
9
|
+
flushQueueSize?: number;
|
|
10
|
+
}
|
|
2
11
|
/**
|
|
3
12
|
* Additional metadata to include when tracking a pageview or REST API call.
|
|
4
13
|
*/
|
|
@@ -10,7 +19,7 @@ export interface TrackPageviewOrRESTCallOptions {
|
|
|
10
19
|
}
|
|
11
20
|
/**
|
|
12
21
|
* A normalized visit payload for the Known Agents API.
|
|
13
|
-
* Use this with `trackVisits()`
|
|
22
|
+
* Use this with `trackVisits()` to manually add visit events to the queue.
|
|
14
23
|
*/
|
|
15
24
|
export interface VisitRequest {
|
|
16
25
|
/** The URL path and query string of the request (e.g. "/about?foo=bar") */
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAA;AAEpE;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC3C,6BAA6B;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACzC,6BAA6B;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC5C;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IACzB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAA;IACpB,2CAA2C;IAC3C,cAAc,EAAE,MAAM,CAAA;IACtB,8EAA8E;IAC9E,eAAe,EAAE,mBAAmB,CAAA;IACpC,oDAAoD;IACpD,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,mBAAmB,CAAA;IACtC,4CAA4C;IAC5C,iCAAiC,CAAC,EAAE,MAAM,CAAA;IAC1C,sCAAsC;IACtC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,gCAAgC;IAChC,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,kCAAkC;IAClC,4BAA4B,CAAC,EAAE,MAAM,CAAA;IACrC,qCAAqC;IACrC,+BAA+B,CAAC,EAAE,MAAM,CAAA;IACxC,kDAAkD;IAClD,4BAA4B,CAAC,EAAE,OAAO,CAAA;IACtC,kCAAkC;IAClC,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,qCAAqC;IACrC,0BAA0B,CAAC,EAAE,MAAM,CAAA;IACnC,4BAA4B;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3C,4BAA4B;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3C,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IAClC,4FAA4F;IAC5F,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,8EAA8E;IAC9E,eAAe,EAAE,mBAAmB,CAAA;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,oDAAoD;IACpD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX;;;;;;OAMG;IACH,MAAM,EAAE,UAAU,GAAG,qBAAqB,GAAG,eAAe,GAAG,gBAAgB,CAAA;IAC/E,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kFAAkF;IAClF,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;GAEG;AACH,oBAAY,SAAS;IACjB,OAAO,aAAa;IACpB,WAAW,iBAAiB;IAC5B,aAAa,oBAAoB;IACjC,cAAc,qBAAqB;IACnC,aAAa,oBAAoB;IACjC,eAAe,sBAAsB;IACrC,QAAQ,aAAa;IACrB,cAAc,oBAAoB;IAClC,eAAe,qBAAqB;IACpC,OAAO,YAAY;IACnB,oBAAoB,0BAA0B;IAC9C,OAAO,YAAY;IACnB,UAAU,gBAAgB;IAC1B,mBAAmB,0BAA0B;IAC7C,eAAe,qBAAqB;IACpC,mBAAmB,0BAA0B;CAChD"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAA;AAEpE;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAC/B,yGAAyG;IACzG,2BAA2B,CAAC,EAAE,MAAM,CAAA;IACpC,sFAAsF;IACtF,cAAc,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC3C,6BAA6B;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACzC,6BAA6B;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC5C;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IACzB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAA;IACpB,2CAA2C;IAC3C,cAAc,EAAE,MAAM,CAAA;IACtB,8EAA8E;IAC9E,eAAe,EAAE,mBAAmB,CAAA;IACpC,oDAAoD;IACpD,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,mBAAmB,CAAA;IACtC,4CAA4C;IAC5C,iCAAiC,CAAC,EAAE,MAAM,CAAA;IAC1C,sCAAsC;IACtC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,gCAAgC;IAChC,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,kCAAkC;IAClC,4BAA4B,CAAC,EAAE,MAAM,CAAA;IACrC,qCAAqC;IACrC,+BAA+B,CAAC,EAAE,MAAM,CAAA;IACxC,kDAAkD;IAClD,4BAA4B,CAAC,EAAE,OAAO,CAAA;IACtC,kCAAkC;IAClC,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,qCAAqC;IACrC,0BAA0B,CAAC,EAAE,MAAM,CAAA;IACnC,4BAA4B;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3C,4BAA4B;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3C,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IAClC,4FAA4F;IAC5F,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,8EAA8E;IAC9E,eAAe,EAAE,mBAAmB,CAAA;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,oDAAoD;IACpD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX;;;;;;OAMG;IACH,MAAM,EAAE,UAAU,GAAG,qBAAqB,GAAG,eAAe,GAAG,gBAAgB,CAAA;IAC/E,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kFAAkF;IAClF,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;GAEG;AACH,oBAAY,SAAS;IACjB,OAAO,aAAa;IACpB,WAAW,iBAAiB;IAC5B,aAAa,oBAAoB;IACjC,cAAc,qBAAqB;IACnC,aAAa,oBAAoB;IACjC,eAAe,sBAAsB;IACrC,QAAQ,aAAa;IACrB,cAAc,oBAAoB;IAClC,eAAe,qBAAqB;IACpC,OAAO,YAAY;IACnB,oBAAoB,0BAA0B;IAC9C,OAAO,YAAY;IACnB,UAAU,gBAAgB;IAC1B,mBAAmB,0BAA0B;IAC7C,eAAe,qBAAqB;IACpC,mBAAmB,0BAA0B;CAChD"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knownagents/sdk",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "The official Node.js SDK for Known Agents: AI agent analytics (bot traffic), LLM referral tracking, automatic robots.txt, agent
|
|
3
|
+
"version": "2.2.0",
|
|
4
|
+
"description": "The official Node.js SDK for Known Agents: AI agent analytics (bot traffic), LLM referral tracking, automatic robots.txt, agent identification",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"web scraping",
|
|
33
33
|
"ai blocking",
|
|
34
34
|
"bot blocking",
|
|
35
|
-
"agent
|
|
35
|
+
"agent identification",
|
|
36
36
|
"bot verification",
|
|
37
37
|
"verify ai agents",
|
|
38
38
|
"web bot auth",
|
package/src/KnownAgents.ts
CHANGED
|
@@ -6,29 +6,41 @@ import type {
|
|
|
6
6
|
AgentType,
|
|
7
7
|
IdentificationRequest,
|
|
8
8
|
IdentificationResult,
|
|
9
|
+
KnownAgentsOptions,
|
|
9
10
|
TrackPageviewOrRESTCallOptions,
|
|
10
11
|
VisitRequest
|
|
11
12
|
} from "./types"
|
|
12
13
|
|
|
14
|
+
const DEFAULT_FLUSH_INTERVAL_IN_MILLISECONDS = 10000
|
|
15
|
+
const DEFAULT_FLUSH_QUEUE_SIZE = 1
|
|
16
|
+
|
|
13
17
|
/**
|
|
14
18
|
* Server-side client for Known Agents analytics, robots.txt generation, and agent identification.
|
|
15
19
|
*/
|
|
16
20
|
export class KnownAgents {
|
|
17
21
|
private readonly accessToken: string
|
|
22
|
+
private readonly flushIntervalInMilliseconds: number
|
|
23
|
+
private readonly flushQueueSize: number
|
|
24
|
+
private readonly visitQueue: VisitRequest[] = []
|
|
25
|
+
private flushTimeout: NodeJS.Timeout | undefined
|
|
26
|
+
private pendingFlushPromise: Promise<void> = Promise.resolve()
|
|
18
27
|
|
|
19
28
|
/**
|
|
20
29
|
* Creates a new instance of the Known Agents client.
|
|
21
|
-
*
|
|
30
|
+
*
|
|
22
31
|
* @param accessToken - Your project's access token.
|
|
32
|
+
* @param options - Optional batching configuration.
|
|
23
33
|
*/
|
|
24
|
-
constructor(accessToken: string) {
|
|
34
|
+
constructor(accessToken: string, options: KnownAgentsOptions = {}) {
|
|
25
35
|
this.accessToken = accessToken
|
|
36
|
+
this.flushIntervalInMilliseconds = options.flushIntervalInMilliseconds ?? DEFAULT_FLUSH_INTERVAL_IN_MILLISECONDS
|
|
37
|
+
this.flushQueueSize = options.flushQueueSize ?? DEFAULT_FLUSH_QUEUE_SIZE
|
|
26
38
|
}
|
|
27
39
|
|
|
28
40
|
/**
|
|
29
41
|
* Tracks a single non-MCP pageview or REST API call for analytics.
|
|
30
|
-
* The visit is
|
|
31
|
-
* This method is non-blocking and handles errors internally.
|
|
42
|
+
* The visit is added to the visit event queue after the response finishes so status, headers, and duration are included.
|
|
43
|
+
* This method is non-blocking and handles upload errors internally.
|
|
32
44
|
*
|
|
33
45
|
* @param request - The incoming Node.js HTTP request.
|
|
34
46
|
* @param response - The outgoing Node.js HTTP response.
|
|
@@ -74,7 +86,7 @@ export class KnownAgents {
|
|
|
74
86
|
* Tracks a single MCP call handled by `StreamableHTTPServerTransport`.
|
|
75
87
|
* Call this after connecting the transport and before the transport processes the request so request and response metadata can be captured.
|
|
76
88
|
* Do not use this with transport instances shared across concurrent requests; use `trackVisits()` instead.
|
|
77
|
-
* This method is non-blocking and handles errors internally.
|
|
89
|
+
* This method is non-blocking and handles upload errors internally.
|
|
78
90
|
*
|
|
79
91
|
* @param request - The incoming Node.js HTTP request.
|
|
80
92
|
* @param response - The outgoing Node.js HTTP response.
|
|
@@ -98,7 +110,7 @@ export class KnownAgents {
|
|
|
98
110
|
mcpRequestBody = message
|
|
99
111
|
originalTransportOnMessage?.(message, extra)
|
|
100
112
|
}
|
|
101
|
-
|
|
113
|
+
|
|
102
114
|
const originalTransportSend = transport.send
|
|
103
115
|
transport.send = async (message, options): Promise<void> => {
|
|
104
116
|
mcpResponseBody = message
|
|
@@ -118,7 +130,6 @@ export class KnownAgents {
|
|
|
118
130
|
}
|
|
119
131
|
|
|
120
132
|
const responseDurationInMilliseconds = Date.now() - created.getTime()
|
|
121
|
-
const mcpResponseResult = mcpResponseBody.result?.structuredContent ?? mcpResponseBody.result
|
|
122
133
|
|
|
123
134
|
const visitRequest: VisitRequest = {
|
|
124
135
|
request_path: path,
|
|
@@ -134,8 +145,8 @@ export class KnownAgents {
|
|
|
134
145
|
mcp_response_result_is_error: mcpResponseBody.result?.isError,
|
|
135
146
|
mcp_response_error_code: mcpResponseBody.error?.code,
|
|
136
147
|
mcp_response_error_message: mcpResponseBody.error?.message,
|
|
137
|
-
acp_response_body: getIsACPCall(request.headers) ?
|
|
138
|
-
ucp_response_body: getIsUCPCall(request.headers) ?
|
|
148
|
+
acp_response_body: getIsACPCall(request.headers) ? mcpResponseBody.result?.structuredContent ?? mcpResponseBody.result : undefined,
|
|
149
|
+
ucp_response_body: getIsUCPCall(request.headers) ? mcpResponseBody.result?.structuredContent ?? mcpResponseBody.result : undefined,
|
|
139
150
|
created: created.toISOString()
|
|
140
151
|
}
|
|
141
152
|
|
|
@@ -148,11 +159,11 @@ export class KnownAgents {
|
|
|
148
159
|
response.once("finish", sendVisit)
|
|
149
160
|
}
|
|
150
161
|
}
|
|
151
|
-
|
|
162
|
+
|
|
152
163
|
/**
|
|
153
|
-
*
|
|
154
|
-
* This method is non-blocking and handles errors internally.
|
|
155
|
-
*
|
|
164
|
+
* Adds multiple visits to the visit event queue for analytics.
|
|
165
|
+
* This method is non-blocking and handles upload errors internally.
|
|
166
|
+
* All visit events are uploaded together when the queue size reaches the configured threshold or the flush interval elapses.
|
|
156
167
|
*
|
|
157
168
|
* @param requests - An array of visits.
|
|
158
169
|
*/
|
|
@@ -173,18 +184,41 @@ export class KnownAgents {
|
|
|
173
184
|
return
|
|
174
185
|
}
|
|
175
186
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
187
|
+
this.visitQueue.push(...filteredRequests)
|
|
188
|
+
|
|
189
|
+
if (this.visitQueue.length >= this.flushQueueSize) {
|
|
190
|
+
void this.flush()
|
|
191
|
+
return
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
this.scheduleFlush()
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Uploads all events currently in the visit event queue and waits for pending uploads to finish.
|
|
199
|
+
* This method handles upload errors internally.
|
|
200
|
+
*
|
|
201
|
+
* @returns A promise that resolves after all pending upload attempts finish.
|
|
202
|
+
*/
|
|
203
|
+
flush(): Promise<void> {
|
|
204
|
+
if (this.flushTimeout) {
|
|
205
|
+
clearTimeout(this.flushTimeout)
|
|
206
|
+
this.flushTimeout = undefined
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const requests = this.visitQueue.splice(0)
|
|
210
|
+
|
|
211
|
+
if (requests.length === 0) {
|
|
212
|
+
return this.pendingFlushPromise
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
this.pendingFlushPromise = this.pendingFlushPromise.then(() => {
|
|
216
|
+
return this.sendVisits(requests)
|
|
185
217
|
})
|
|
218
|
+
|
|
219
|
+
return this.pendingFlushPromise
|
|
186
220
|
}
|
|
187
|
-
|
|
221
|
+
|
|
188
222
|
/**
|
|
189
223
|
* Generates a robots.txt file that disallows the specified agent types.
|
|
190
224
|
* The generated file stays up-to-date with all current and future agents in the specified categories.
|
|
@@ -214,7 +248,7 @@ export class KnownAgents {
|
|
|
214
248
|
throw new Error(`Known Agents failed to generate robots.txt: ${response.status} ${response.statusText}`)
|
|
215
249
|
}
|
|
216
250
|
}
|
|
217
|
-
|
|
251
|
+
|
|
218
252
|
/**
|
|
219
253
|
* Identifies and verifies a single agent from an HTTP request.
|
|
220
254
|
* Uses Web Bot Auth (HTTP message signatures), IP matching, or other available methods.
|
|
@@ -272,4 +306,36 @@ export class KnownAgents {
|
|
|
272
306
|
}
|
|
273
307
|
}
|
|
274
308
|
|
|
309
|
+
private scheduleFlush(): void {
|
|
310
|
+
if (this.flushTimeout) {
|
|
311
|
+
return
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
this.flushTimeout = setTimeout(() => {
|
|
315
|
+
this.flushTimeout = undefined
|
|
316
|
+
void this.flush()
|
|
317
|
+
}, this.flushIntervalInMilliseconds)
|
|
318
|
+
|
|
319
|
+
this.flushTimeout.unref()
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
private async sendVisits(requests: VisitRequest[]): Promise<void> {
|
|
323
|
+
try {
|
|
324
|
+
const response = await fetch("https://api.knownagents.com/visits", {
|
|
325
|
+
method: "POST",
|
|
326
|
+
headers: {
|
|
327
|
+
"Authorization": `Bearer ${this.accessToken}`,
|
|
328
|
+
"Content-Type": "application/json"
|
|
329
|
+
},
|
|
330
|
+
body: JSON.stringify(requests)
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
if (!response.ok) {
|
|
334
|
+
throw new Error(`${response.status} ${response.statusText}`)
|
|
335
|
+
}
|
|
336
|
+
} catch (error) {
|
|
337
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
338
|
+
console.error(`Known Agents failed to track visits: ${message}`)
|
|
339
|
+
}
|
|
340
|
+
}
|
|
275
341
|
}
|
package/src/index.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import type { IncomingHttpHeaders, OutgoingHttpHeaders } from "http"
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Batching configuration for the Known Agents client.
|
|
5
|
+
*/
|
|
6
|
+
export interface KnownAgentsOptions {
|
|
7
|
+
/** The maximum time a partial visit event queue waits before upload. Defaults to 10,000 milliseconds. */
|
|
8
|
+
flushIntervalInMilliseconds?: number
|
|
9
|
+
/** The number of visit events in the queue that triggers an upload. Defaults to 1. */
|
|
10
|
+
flushQueueSize?: number
|
|
11
|
+
}
|
|
12
|
+
|
|
3
13
|
/**
|
|
4
14
|
* Additional metadata to include when tracking a pageview or REST API call.
|
|
5
15
|
*/
|
|
@@ -12,7 +22,7 @@ export interface TrackPageviewOrRESTCallOptions {
|
|
|
12
22
|
|
|
13
23
|
/**
|
|
14
24
|
* A normalized visit payload for the Known Agents API.
|
|
15
|
-
* Use this with `trackVisits()`
|
|
25
|
+
* Use this with `trackVisits()` to manually add visit events to the queue.
|
|
16
26
|
*/
|
|
17
27
|
export interface VisitRequest {
|
|
18
28
|
/** The URL path and query string of the request (e.g. "/about?foo=bar") */
|
package/dist/commerce.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
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
|
package/dist/commerce.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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"}
|
package/dist/commerce.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
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
|
-
}
|