@analytickit/sdk-node 0.0.0-stage → 0.1.1
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/LICENSE +21 -0
- package/README.md +107 -2
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +157 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware.d.ts +79 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +223 -0
- package/dist/middleware.js.map +1 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +37 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AnalyticKit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,108 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@analytickit/sdk-node`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> **Status: published.** `npm install @analytickit/sdk-node`
|
|
4
|
+
|
|
5
|
+
Node client for AgentGraph. Two things live in this package:
|
|
6
|
+
|
|
7
|
+
1. A plain `track()`/`trackBatch()` client — for an AI agent, job, or backend
|
|
8
|
+
service that wants to emit its own events.
|
|
9
|
+
2. Request middleware (`trackRequest()` plus three framework adapters) that
|
|
10
|
+
turns any Node server into a server-side event collector, so traffic that
|
|
11
|
+
never runs the browser SDK's JavaScript — AI crawlers in particular —
|
|
12
|
+
still produces events.
|
|
13
|
+
|
|
14
|
+
Full install guide and the F0.3 access-log import mapping:
|
|
15
|
+
[`docs/help/server-side-collection.md`](../../docs/help/server-side-collection.md).
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @analytickit/sdk-node
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
(Inside this monorepo, import it as `@analytickit/sdk-node` from any
|
|
24
|
+
workspace, no install step needed.)
|
|
25
|
+
|
|
26
|
+
## Client
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { AnalyticKit } from '@analytickit/sdk-node';
|
|
30
|
+
|
|
31
|
+
const client = new AnalyticKit({
|
|
32
|
+
apiKey: process.env.ANALYTICKIT_SDK_KEY!,
|
|
33
|
+
endpoint: 'https://app.analytickit.com', // bare origin — no trailing /v1
|
|
34
|
+
// actorType: 'human' (default) | 'ai_agent' | 'cli' | ...
|
|
35
|
+
// maxRetries: 2 (default) — only retries 5xx and network errors, never 4xx
|
|
36
|
+
// timeout: 5000 (default, ms)
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### `track(eventName, options?)`
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
await client.track('report_generated', {
|
|
44
|
+
actorType: 'ai_agent',
|
|
45
|
+
agentId: 'agent_123',
|
|
46
|
+
taskId: 'task_456',
|
|
47
|
+
properties: { reportType: 'weekly_summary' },
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### `trackBatch(events)`
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
const { accepted, rejected } = await client.trackBatch([
|
|
55
|
+
{ eventName: 'agent_step', taskId: 't1' },
|
|
56
|
+
{ eventName: 'agent_step', taskId: 't1' },
|
|
57
|
+
]);
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### `trackRequest(context, options?)`
|
|
61
|
+
|
|
62
|
+
Records one inbound HTTP request as observed by a server-side collector.
|
|
63
|
+
Normally you don't call this directly — the middleware adapters below call
|
|
64
|
+
it for you — but it's the primitive they're built on, useful for a custom
|
|
65
|
+
collector (e.g. one that wants to attach a response `status`):
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
await client.trackRequest(
|
|
69
|
+
{ userAgent, ip, path, referrer, host, method, status },
|
|
70
|
+
{ eventName: 'page_view', visitorId, sessionId },
|
|
71
|
+
);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`request_context` on the sent payload takes priority over ingest's own
|
|
75
|
+
transport headers for Web2 enrichment — see the install guide, §3.
|
|
76
|
+
|
|
77
|
+
## Middleware adapters
|
|
78
|
+
|
|
79
|
+
All three are re-exported from the package root (as well as from
|
|
80
|
+
`@analytickit/sdk-node/middleware`):
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import {
|
|
84
|
+
analyticKitExpress,
|
|
85
|
+
analyticKitFastify,
|
|
86
|
+
analyticKitFetch,
|
|
87
|
+
extractContext,
|
|
88
|
+
shouldCollect,
|
|
89
|
+
DEFAULT_IGNORE,
|
|
90
|
+
} from '@analytickit/sdk-node';
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
| Export | For |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| `analyticKitExpress(options)` | `app.use(...)` |
|
|
96
|
+
| `analyticKitFastify(options)` | `app.addHook('onRequest', ...)` |
|
|
97
|
+
| `analyticKitFetch(options)` | Next.js middleware, Hono, edge runtimes — anything handed a Fetch API `Request` |
|
|
98
|
+
| `extractContext(req, options?)` | Pull a `RequestContext` off a node-style request object directly |
|
|
99
|
+
| `shouldCollect(path, options)` | The ignore/sample-rate decision, exposed standalone |
|
|
100
|
+
| `DEFAULT_IGNORE` | The default `ignore` regex list (static assets, health checks, `_next`, favicon) |
|
|
101
|
+
|
|
102
|
+
All three take `MiddlewareOptions` — at minimum `{ client }`. See the
|
|
103
|
+
install guide for `ignore`, `sampleRate`, `trustProxy`, and `onError`, and
|
|
104
|
+
for why collection adds no request latency and cannot fail the request.
|
|
105
|
+
|
|
106
|
+
Full docs, the privacy/`capture_ip` behavior, volume-control gotchas, and
|
|
107
|
+
the F0.3 CSV access-log import mapping:
|
|
108
|
+
[`docs/help/server-side-collection.md`](../../docs/help/server-side-collection.md).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { NodeSdkConfig, TrackOptions, RequestContext, TrackRequestOptions } from './types.js';
|
|
2
|
+
export type { NodeSdkConfig, TrackOptions, RequestContext, TrackRequestOptions } from './types.js';
|
|
3
|
+
export { analyticKitExpress, analyticKitFastify, analyticKitFetch, extractContext, shouldCollect, DEFAULT_IGNORE, detectAgentProtocol, } from './middleware.js';
|
|
4
|
+
export type { MiddlewareOptions, NodeLikeRequest } from './middleware.js';
|
|
5
|
+
export declare class AnalyticKit {
|
|
6
|
+
private readonly apiKey;
|
|
7
|
+
private readonly endpoint;
|
|
8
|
+
private readonly actorType;
|
|
9
|
+
private readonly maxRetries;
|
|
10
|
+
private readonly timeout;
|
|
11
|
+
constructor(config: NodeSdkConfig);
|
|
12
|
+
track(eventName: string, options?: Partial<Omit<TrackOptions, 'eventName'>>): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Record a single inbound HTTP request observed by a server-side collector.
|
|
15
|
+
*
|
|
16
|
+
* The ingest side reads `request_context` in preference to the transport
|
|
17
|
+
* headers on our own call, because those describe THIS process, not the end
|
|
18
|
+
* user. `page_path` is mirrored to the top level so the event also lights up
|
|
19
|
+
* the existing funnel UI without a server round-trip.
|
|
20
|
+
*/
|
|
21
|
+
trackRequest(context: RequestContext, options?: TrackRequestOptions): Promise<void>;
|
|
22
|
+
trackBatch(events: TrackOptions[]): Promise<{
|
|
23
|
+
accepted: number;
|
|
24
|
+
rejected: number;
|
|
25
|
+
}>;
|
|
26
|
+
shutdown(): Promise<void>;
|
|
27
|
+
private _sendWithRetry;
|
|
28
|
+
private _sleep;
|
|
29
|
+
}
|
|
30
|
+
export default AnalyticKit;
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAGnG,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACnG,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,cAAc,EACd,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAE1E,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,aAAa;IAW3B,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BjG;;;;;;;OAOG;IACG,YAAY,CAChB,OAAO,EAAE,cAAc,EACvB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,IAAI,CAAC;IAyCV,UAAU,CACd,MAAM,EAAE,YAAY,EAAE,GACrB,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IA+B5C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YAIjB,cAAc;IA0C5B,OAAO,CAAC,MAAM;CAGf;AAED,eAAe,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AnalyticKit = exports.detectAgentProtocol = exports.DEFAULT_IGNORE = exports.shouldCollect = exports.extractContext = exports.analyticKitFetch = exports.analyticKitFastify = exports.analyticKitExpress = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const types_js_1 = require("./types.js");
|
|
6
|
+
var middleware_js_1 = require("./middleware.js");
|
|
7
|
+
Object.defineProperty(exports, "analyticKitExpress", { enumerable: true, get: function () { return middleware_js_1.analyticKitExpress; } });
|
|
8
|
+
Object.defineProperty(exports, "analyticKitFastify", { enumerable: true, get: function () { return middleware_js_1.analyticKitFastify; } });
|
|
9
|
+
Object.defineProperty(exports, "analyticKitFetch", { enumerable: true, get: function () { return middleware_js_1.analyticKitFetch; } });
|
|
10
|
+
Object.defineProperty(exports, "extractContext", { enumerable: true, get: function () { return middleware_js_1.extractContext; } });
|
|
11
|
+
Object.defineProperty(exports, "shouldCollect", { enumerable: true, get: function () { return middleware_js_1.shouldCollect; } });
|
|
12
|
+
Object.defineProperty(exports, "DEFAULT_IGNORE", { enumerable: true, get: function () { return middleware_js_1.DEFAULT_IGNORE; } });
|
|
13
|
+
Object.defineProperty(exports, "detectAgentProtocol", { enumerable: true, get: function () { return middleware_js_1.detectAgentProtocol; } });
|
|
14
|
+
class AnalyticKit {
|
|
15
|
+
apiKey;
|
|
16
|
+
endpoint;
|
|
17
|
+
actorType;
|
|
18
|
+
maxRetries;
|
|
19
|
+
timeout;
|
|
20
|
+
constructor(config) {
|
|
21
|
+
if (!config.apiKey) {
|
|
22
|
+
throw new Error('AnalyticKit: apiKey is required');
|
|
23
|
+
}
|
|
24
|
+
this.apiKey = config.apiKey;
|
|
25
|
+
this.endpoint = config.endpoint.replace(/\/$/, '');
|
|
26
|
+
this.actorType = config.actorType ?? types_js_1.NODE_CONFIG_DEFAULTS.actorType;
|
|
27
|
+
this.maxRetries = config.maxRetries ?? types_js_1.NODE_CONFIG_DEFAULTS.maxRetries;
|
|
28
|
+
this.timeout = config.timeout ?? types_js_1.NODE_CONFIG_DEFAULTS.timeout;
|
|
29
|
+
}
|
|
30
|
+
async track(eventName, options) {
|
|
31
|
+
// Minted here, BEFORE _sendWithRetry — the whole point is that all
|
|
32
|
+
// retries of this event carry the same key, so ingest derives one
|
|
33
|
+
// event_id and the duplicate is absorbed. _sendWithRetry re-sends the
|
|
34
|
+
// identical body string, so the key is stable by construction
|
|
35
|
+
// (2026-07-04 critique, Arch #6: a 5xx retry used to create a second row).
|
|
36
|
+
const payload = {
|
|
37
|
+
idempotency_key: options?.idempotencyKey ?? (0, node_crypto_1.randomUUID)(),
|
|
38
|
+
event_name: eventName,
|
|
39
|
+
timestamp: Date.now(),
|
|
40
|
+
actor_type: options?.actorType ?? this.actorType,
|
|
41
|
+
properties: options?.properties,
|
|
42
|
+
agent_id: options?.agentId,
|
|
43
|
+
task_id: options?.taskId,
|
|
44
|
+
workflow_id: options?.workflowId,
|
|
45
|
+
wallet_address: options?.walletAddress,
|
|
46
|
+
chain: options?.chain,
|
|
47
|
+
};
|
|
48
|
+
await this._sendWithRetry(`${this.endpoint}/v1/events`, JSON.stringify(payload), this.maxRetries);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Record a single inbound HTTP request observed by a server-side collector.
|
|
52
|
+
*
|
|
53
|
+
* The ingest side reads `request_context` in preference to the transport
|
|
54
|
+
* headers on our own call, because those describe THIS process, not the end
|
|
55
|
+
* user. `page_path` is mirrored to the top level so the event also lights up
|
|
56
|
+
* the existing funnel UI without a server round-trip.
|
|
57
|
+
*/
|
|
58
|
+
async trackRequest(context, options) {
|
|
59
|
+
const requestContext = {};
|
|
60
|
+
const map = [
|
|
61
|
+
['userAgent', 'user_agent'],
|
|
62
|
+
['ip', 'ip'],
|
|
63
|
+
['path', 'path'],
|
|
64
|
+
['referrer', 'referrer'],
|
|
65
|
+
['host', 'host'],
|
|
66
|
+
['method', 'method'],
|
|
67
|
+
['status', 'status'],
|
|
68
|
+
['protocol', 'protocol'],
|
|
69
|
+
];
|
|
70
|
+
for (const [from, to] of map) {
|
|
71
|
+
const value = context[from];
|
|
72
|
+
// Omit absent fields entirely — sending explicit nulls would make the
|
|
73
|
+
// ingest-side "was this forwarded?" check ambiguous.
|
|
74
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
75
|
+
requestContext[to] = value;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const payload = {
|
|
79
|
+
idempotency_key: options?.idempotencyKey ?? (0, node_crypto_1.randomUUID)(),
|
|
80
|
+
event_name: options?.eventName ?? 'page_view',
|
|
81
|
+
timestamp: Date.now(),
|
|
82
|
+
actor_type: options?.actorType ?? this.actorType,
|
|
83
|
+
properties: options?.properties,
|
|
84
|
+
visitor_id: options?.visitorId,
|
|
85
|
+
session_id: options?.sessionId,
|
|
86
|
+
page_path: context.path ?? undefined,
|
|
87
|
+
page_referrer: context.referrer ?? undefined,
|
|
88
|
+
request_context: requestContext,
|
|
89
|
+
};
|
|
90
|
+
await this._sendWithRetry(`${this.endpoint}/v1/events`, JSON.stringify(payload), this.maxRetries);
|
|
91
|
+
}
|
|
92
|
+
async trackBatch(events) {
|
|
93
|
+
const payloads = events.map((e) => ({
|
|
94
|
+
idempotency_key: e.idempotencyKey ?? (0, node_crypto_1.randomUUID)(),
|
|
95
|
+
event_name: e.eventName,
|
|
96
|
+
timestamp: Date.now(),
|
|
97
|
+
actor_type: e.actorType ?? this.actorType,
|
|
98
|
+
properties: e.properties,
|
|
99
|
+
agent_id: e.agentId,
|
|
100
|
+
task_id: e.taskId,
|
|
101
|
+
workflow_id: e.workflowId,
|
|
102
|
+
wallet_address: e.walletAddress,
|
|
103
|
+
chain: e.chain,
|
|
104
|
+
}));
|
|
105
|
+
const res = await this._sendWithRetry(`${this.endpoint}/v1/events/batch`, JSON.stringify(payloads), this.maxRetries);
|
|
106
|
+
if (res) {
|
|
107
|
+
const body = (await res.json());
|
|
108
|
+
return {
|
|
109
|
+
accepted: body.data?.accepted ?? events.length,
|
|
110
|
+
rejected: body.data?.rejected ?? 0,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return { accepted: events.length, rejected: 0 };
|
|
114
|
+
}
|
|
115
|
+
async shutdown() {
|
|
116
|
+
// No-op for now; future queue support would flush pending here
|
|
117
|
+
}
|
|
118
|
+
async _sendWithRetry(url, body, retriesLeft) {
|
|
119
|
+
const attempt = this.maxRetries - retriesLeft;
|
|
120
|
+
try {
|
|
121
|
+
const controller = new AbortController();
|
|
122
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
123
|
+
const res = await fetch(url, {
|
|
124
|
+
method: 'POST',
|
|
125
|
+
headers: {
|
|
126
|
+
'Content-Type': 'application/json',
|
|
127
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
128
|
+
},
|
|
129
|
+
body,
|
|
130
|
+
signal: controller.signal,
|
|
131
|
+
});
|
|
132
|
+
clearTimeout(timer);
|
|
133
|
+
if (res.status >= 500 && retriesLeft > 0) {
|
|
134
|
+
const backoff = 100 * Math.pow(2, attempt);
|
|
135
|
+
await this._sleep(backoff);
|
|
136
|
+
return this._sendWithRetry(url, body, retriesLeft - 1);
|
|
137
|
+
}
|
|
138
|
+
// 4xx: do NOT retry — return as-is
|
|
139
|
+
return res;
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
// Network errors: retry if possible
|
|
143
|
+
if (retriesLeft > 0) {
|
|
144
|
+
const backoff = 100 * Math.pow(2, attempt);
|
|
145
|
+
await this._sleep(backoff);
|
|
146
|
+
return this._sendWithRetry(url, body, retriesLeft - 1);
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
_sleep(ms) {
|
|
152
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
exports.AnalyticKit = AnalyticKit;
|
|
156
|
+
exports.default = AnalyticKit;
|
|
157
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { AnalyticKit } from './index.js';
|
|
2
|
+
import type { RequestContext, TrackRequestOptions } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Structural stand-ins for `http.IncomingMessage` and the Express/Fastify
|
|
5
|
+
* request objects that wrap it. Typed here rather than imported so this
|
|
6
|
+
* package keeps its zero-runtime-dependency guarantee.
|
|
7
|
+
*/
|
|
8
|
+
export interface NodeLikeRequest {
|
|
9
|
+
method?: string;
|
|
10
|
+
url?: string;
|
|
11
|
+
originalUrl?: string;
|
|
12
|
+
headers: Record<string, string | string[] | undefined>;
|
|
13
|
+
socket?: {
|
|
14
|
+
remoteAddress?: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export interface MiddlewareOptions {
|
|
18
|
+
client: AnalyticKit;
|
|
19
|
+
/** Event name for collected requests. Default 'page_view'. */
|
|
20
|
+
eventName?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Paths matching any of these are not collected. REPLACES the defaults —
|
|
23
|
+
* pass `[...DEFAULT_IGNORE, /^\/admin/]` to extend them instead.
|
|
24
|
+
*/
|
|
25
|
+
ignore?: RegExp[];
|
|
26
|
+
/** 0..1. Default 1 (collect everything). */
|
|
27
|
+
sampleRate?: number;
|
|
28
|
+
/** Read the client IP from X-Forwarded-For. Default true. */
|
|
29
|
+
trustProxy?: boolean;
|
|
30
|
+
/** Called instead of throwing when collection faults. Default: swallow. */
|
|
31
|
+
onError?: (err: unknown) => void;
|
|
32
|
+
/** Extra options forwarded to trackRequest (actorType, properties, ...). */
|
|
33
|
+
track?: Omit<TrackRequestOptions, 'eventName'>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Requests a page-analytics product should not count. Static assets dominate
|
|
37
|
+
* request volume on any real site and would swamp both the customer's event
|
|
38
|
+
* quota and the AI-traffic signal this feature exists to surface.
|
|
39
|
+
*/
|
|
40
|
+
export declare const DEFAULT_IGNORE: RegExp[];
|
|
41
|
+
/**
|
|
42
|
+
* Infer the agent protocol from request headers. `get` is a case-insensitive
|
|
43
|
+
* header lookup (`headerValue` for node-style requests, `Headers.get` for
|
|
44
|
+
* Fetch). Only the derived label is ever returned — header VALUES (session
|
|
45
|
+
* ids, payment payloads) never pass through this function's result.
|
|
46
|
+
*
|
|
47
|
+
* x402 wins when both signals are present: a paid MCP call is still a
|
|
48
|
+
* payment event.
|
|
49
|
+
*/
|
|
50
|
+
export declare function detectAgentProtocol(get: (name: string) => string | null | undefined): 'mcp' | 'x402' | null;
|
|
51
|
+
/** True when this path should produce an event. */
|
|
52
|
+
export declare function shouldCollect(path: string, options: Pick<MiddlewareOptions, 'ignore' | 'sampleRate'>): boolean;
|
|
53
|
+
/** Pull the END USER's signals off a node-style request object. */
|
|
54
|
+
export declare function extractContext(req: NodeLikeRequest, options?: Pick<MiddlewareOptions, 'trustProxy'>): RequestContext;
|
|
55
|
+
/**
|
|
56
|
+
* Express / Connect middleware.
|
|
57
|
+
*
|
|
58
|
+
* app.use(analyticKitExpress({ client }));
|
|
59
|
+
*
|
|
60
|
+
* `next()` is called synchronously before any I/O, so the collector adds no
|
|
61
|
+
* latency and cannot fail the request.
|
|
62
|
+
*/
|
|
63
|
+
export declare function analyticKitExpress(options: MiddlewareOptions): (req: NodeLikeRequest, res: unknown, next: () => void) => void;
|
|
64
|
+
/**
|
|
65
|
+
* Fastify onRequest hook.
|
|
66
|
+
*
|
|
67
|
+
* app.addHook('onRequest', analyticKitFastify({ client }));
|
|
68
|
+
*/
|
|
69
|
+
export declare function analyticKitFastify(options: MiddlewareOptions): (req: NodeLikeRequest, reply: unknown, done: () => void) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Fetch-API collector for Next.js middleware, Hono, and edge runtimes.
|
|
72
|
+
*
|
|
73
|
+
* export function middleware(request: NextRequest) {
|
|
74
|
+
* collect(request);
|
|
75
|
+
* return NextResponse.next();
|
|
76
|
+
* }
|
|
77
|
+
*/
|
|
78
|
+
export declare function analyticKitFetch(options: MiddlewareOptions): (request: Request) => void;
|
|
79
|
+
//# sourceMappingURL=middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtE;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,MAAM,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,WAAW,CAAC;IACpB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;IACjC,4EAA4E;IAC5E,KAAK,CAAC,EAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC;CAChD;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,EAalC,CAAC;AAsBF;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/C,KAAK,GAAG,MAAM,GAAG,IAAI,CAIvB;AAED,mDAAmD;AACnD,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,YAAY,CAAC,GACxD,OAAO,CAYT;AAED,mEAAmE;AACnE,wBAAgB,cAAc,CAC5B,GAAG,EAAE,eAAe,EACpB,OAAO,GAAE,IAAI,CAAC,iBAAiB,EAAE,YAAY,CAAM,GAClD,cAAc,CAuBhB;AA6CD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,iBAAiB,GACzB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,KAAK,IAAI,CAchE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,iBAAiB,GACzB,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,KAAK,IAAI,CAWlE;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,iBAAiB,GACzB,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CA4B5B"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_IGNORE = void 0;
|
|
4
|
+
exports.detectAgentProtocol = detectAgentProtocol;
|
|
5
|
+
exports.shouldCollect = shouldCollect;
|
|
6
|
+
exports.extractContext = extractContext;
|
|
7
|
+
exports.analyticKitExpress = analyticKitExpress;
|
|
8
|
+
exports.analyticKitFastify = analyticKitFastify;
|
|
9
|
+
exports.analyticKitFetch = analyticKitFetch;
|
|
10
|
+
/**
|
|
11
|
+
* Requests a page-analytics product should not count. Static assets dominate
|
|
12
|
+
* request volume on any real site and would swamp both the customer's event
|
|
13
|
+
* quota and the AI-traffic signal this feature exists to surface.
|
|
14
|
+
*/
|
|
15
|
+
exports.DEFAULT_IGNORE = [
|
|
16
|
+
// Static assets. Anchored with `$` and matched against the PATHNAME only
|
|
17
|
+
// (see shouldCollect) — an unanchored form applied to path+query would drop
|
|
18
|
+
// a real page like `/search?q=file.js`.
|
|
19
|
+
/\.(?:js|mjs|cjs|css|map|png|jpe?g|gif|svg|webp|avif|ico|woff2?|ttf|eot|txt|xml|json)$/i,
|
|
20
|
+
// Health checks. These MUST be anchored: a bare `/^\/health/` also swallows
|
|
21
|
+
// real content pages such as `/health-insurance-quotes` or `/healthcare`,
|
|
22
|
+
// and silently losing a customer's pageviews is close to impossible to
|
|
23
|
+
// notice from the outside.
|
|
24
|
+
/^\/healthz?(?:\/|$)/,
|
|
25
|
+
/^\/_next\//,
|
|
26
|
+
/^\/__nextjs/,
|
|
27
|
+
/^\/favicon\.ico$/,
|
|
28
|
+
];
|
|
29
|
+
function headerValue(headers, name) {
|
|
30
|
+
// Fast path: Node's own http parser (and Express/Fastify on top of it)
|
|
31
|
+
// already lowercases header names, which covers nearly every real request.
|
|
32
|
+
// Falls back to a case-insensitive scan for the rare proxy/framework that
|
|
33
|
+
// doesn't normalize, and for callers constructing headers by hand.
|
|
34
|
+
const direct = headers[name];
|
|
35
|
+
if (direct !== undefined)
|
|
36
|
+
return Array.isArray(direct) ? direct[0] : direct;
|
|
37
|
+
const lower = name.toLowerCase();
|
|
38
|
+
for (const key of Object.keys(headers)) {
|
|
39
|
+
if (key.toLowerCase() === lower) {
|
|
40
|
+
const raw = headers[key];
|
|
41
|
+
return Array.isArray(raw) ? raw[0] : raw;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Infer the agent protocol from request headers. `get` is a case-insensitive
|
|
48
|
+
* header lookup (`headerValue` for node-style requests, `Headers.get` for
|
|
49
|
+
* Fetch). Only the derived label is ever returned — header VALUES (session
|
|
50
|
+
* ids, payment payloads) never pass through this function's result.
|
|
51
|
+
*
|
|
52
|
+
* x402 wins when both signals are present: a paid MCP call is still a
|
|
53
|
+
* payment event.
|
|
54
|
+
*/
|
|
55
|
+
function detectAgentProtocol(get) {
|
|
56
|
+
if (get('payment-signature') || get('x-payment'))
|
|
57
|
+
return 'x402';
|
|
58
|
+
if (get('mcp-session-id') || get('mcp-protocol-version'))
|
|
59
|
+
return 'mcp';
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
/** True when this path should produce an event. */
|
|
63
|
+
function shouldCollect(path, options) {
|
|
64
|
+
const ignore = options.ignore ?? exports.DEFAULT_IGNORE;
|
|
65
|
+
// Ignore patterns are matched against the pathname; the query string takes
|
|
66
|
+
// no part in the decision. Without this, `/search?q=file.js` reads as a
|
|
67
|
+
// JavaScript asset and the pageview is thrown away.
|
|
68
|
+
const pathname = path.split('?')[0] ?? path;
|
|
69
|
+
if (ignore.some((re) => re.test(pathname)))
|
|
70
|
+
return false;
|
|
71
|
+
const rate = options.sampleRate ?? 1;
|
|
72
|
+
if (rate >= 1)
|
|
73
|
+
return true;
|
|
74
|
+
if (rate <= 0)
|
|
75
|
+
return false;
|
|
76
|
+
return Math.random() < rate;
|
|
77
|
+
}
|
|
78
|
+
/** Pull the END USER's signals off a node-style request object. */
|
|
79
|
+
function extractContext(req, options = {}) {
|
|
80
|
+
const headers = req.headers ?? {};
|
|
81
|
+
const trustProxy = options.trustProxy ?? true;
|
|
82
|
+
let ip = req.socket?.remoteAddress ?? null;
|
|
83
|
+
if (trustProxy) {
|
|
84
|
+
const xff = headerValue(headers, 'x-forwarded-for');
|
|
85
|
+
// "client, proxy1, proxy2" — the first hop is the client.
|
|
86
|
+
const first = xff?.split(',')[0]?.trim();
|
|
87
|
+
if (first)
|
|
88
|
+
ip = first;
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
userAgent: headerValue(headers, 'user-agent') ?? null,
|
|
92
|
+
ip,
|
|
93
|
+
path: req.originalUrl ?? req.url ?? null,
|
|
94
|
+
// Note the historical misspelling: the HTTP header is `Referer`.
|
|
95
|
+
referrer: headerValue(headers, 'referer') ?? headerValue(headers, 'referrer') ?? null,
|
|
96
|
+
host: headerValue(headers, 'host') ?? null,
|
|
97
|
+
method: req.method ?? null,
|
|
98
|
+
status: null,
|
|
99
|
+
protocol: detectAgentProtocol((name) => headerValue(headers, name)),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Report a collection fault to the caller's handler, absorbing anything that
|
|
104
|
+
* handler itself throws.
|
|
105
|
+
*
|
|
106
|
+
* The customer's `onError` is arbitrary code we invoke from inside a promise
|
|
107
|
+
* rejection handler. If it throws there, the rejection is unhandled — and Node
|
|
108
|
+
* 15+ terminates the process on an unhandled rejection by default. That would
|
|
109
|
+
* turn "your analytics had a hiccup" into "your server died", which is the
|
|
110
|
+
* exact outcome this middleware exists to make impossible. There is nowhere
|
|
111
|
+
* left to report a failure of the failure reporter, so it is swallowed.
|
|
112
|
+
*/
|
|
113
|
+
function reportError(options, err) {
|
|
114
|
+
try {
|
|
115
|
+
options.onError?.(err);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// Deliberately empty — see above.
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Build the context and hand it to the client, fire-and-forget.
|
|
123
|
+
*
|
|
124
|
+
* Takes a factory rather than a value so that a throw from `extractContext`
|
|
125
|
+
* lands inside this try block. Passing `extractContext(req)` as an argument
|
|
126
|
+
* would evaluate it BEFORE the try, leaving that throw to escape into the
|
|
127
|
+
* host app after next()/done() had already run.
|
|
128
|
+
*/
|
|
129
|
+
function dispatch(buildContext, options) {
|
|
130
|
+
try {
|
|
131
|
+
const result = options.client.trackRequest(buildContext(), {
|
|
132
|
+
...options.track,
|
|
133
|
+
eventName: options.eventName ?? 'page_view',
|
|
134
|
+
});
|
|
135
|
+
// Fire-and-forget: an ingest outage must not surface in the host app.
|
|
136
|
+
void Promise.resolve(result).catch((err) => reportError(options, err));
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
reportError(options, err);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Express / Connect middleware.
|
|
144
|
+
*
|
|
145
|
+
* app.use(analyticKitExpress({ client }));
|
|
146
|
+
*
|
|
147
|
+
* `next()` is called synchronously before any I/O, so the collector adds no
|
|
148
|
+
* latency and cannot fail the request.
|
|
149
|
+
*/
|
|
150
|
+
function analyticKitExpress(options) {
|
|
151
|
+
return (req, _res, next) => {
|
|
152
|
+
next();
|
|
153
|
+
// Everything after next() is wrapped: the contract this middleware sells
|
|
154
|
+
// is that installing it cannot break the host app, and that has to hold
|
|
155
|
+
// for a malformed request object or a pathological ignore pattern too.
|
|
156
|
+
try {
|
|
157
|
+
const path = req.originalUrl ?? req.url ?? '/';
|
|
158
|
+
if (!shouldCollect(path, options))
|
|
159
|
+
return;
|
|
160
|
+
dispatch(() => extractContext(req, options), options);
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
reportError(options, err);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Fastify onRequest hook.
|
|
169
|
+
*
|
|
170
|
+
* app.addHook('onRequest', analyticKitFastify({ client }));
|
|
171
|
+
*/
|
|
172
|
+
function analyticKitFastify(options) {
|
|
173
|
+
return (req, _reply, done) => {
|
|
174
|
+
done();
|
|
175
|
+
try {
|
|
176
|
+
const path = req.originalUrl ?? req.url ?? '/';
|
|
177
|
+
if (!shouldCollect(path, options))
|
|
178
|
+
return;
|
|
179
|
+
dispatch(() => extractContext(req, options), options);
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
reportError(options, err);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Fetch-API collector for Next.js middleware, Hono, and edge runtimes.
|
|
188
|
+
*
|
|
189
|
+
* export function middleware(request: NextRequest) {
|
|
190
|
+
* collect(request);
|
|
191
|
+
* return NextResponse.next();
|
|
192
|
+
* }
|
|
193
|
+
*/
|
|
194
|
+
function analyticKitFetch(options) {
|
|
195
|
+
return (request) => {
|
|
196
|
+
// Same containment guarantee as the node adapters: a malformed URL or a
|
|
197
|
+
// hostile header must not propagate into the caller's request handler.
|
|
198
|
+
try {
|
|
199
|
+
const url = new URL(request.url);
|
|
200
|
+
const path = url.pathname + url.search;
|
|
201
|
+
if (!shouldCollect(path, options))
|
|
202
|
+
return;
|
|
203
|
+
const trustProxy = options.trustProxy ?? true;
|
|
204
|
+
dispatch(() => {
|
|
205
|
+
const xff = request.headers.get('x-forwarded-for');
|
|
206
|
+
return {
|
|
207
|
+
userAgent: request.headers.get('user-agent'),
|
|
208
|
+
ip: trustProxy ? (xff?.split(',')[0]?.trim() ?? null) : null,
|
|
209
|
+
path,
|
|
210
|
+
referrer: request.headers.get('referer') ?? request.headers.get('referrer'),
|
|
211
|
+
host: request.headers.get('host') ?? url.host,
|
|
212
|
+
method: request.method,
|
|
213
|
+
status: null,
|
|
214
|
+
protocol: detectAgentProtocol((name) => request.headers.get(name)),
|
|
215
|
+
};
|
|
216
|
+
}, options);
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
reportError(options, err);
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export interface NodeSdkConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
endpoint: string;
|
|
4
|
+
actorType?: string;
|
|
5
|
+
maxRetries?: number;
|
|
6
|
+
timeout?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare const NODE_CONFIG_DEFAULTS: {
|
|
9
|
+
readonly actorType: "human";
|
|
10
|
+
readonly maxRetries: 2;
|
|
11
|
+
readonly timeout: 5000;
|
|
12
|
+
};
|
|
13
|
+
export interface TrackOptions {
|
|
14
|
+
eventName: string;
|
|
15
|
+
/**
|
|
16
|
+
* Optional caller-supplied idempotency key. Defaults to a fresh UUID per
|
|
17
|
+
* event, which makes the SDK's own 5xx retries exactly-once. Supply your
|
|
18
|
+
* own (e.g. an order id) when the CALLER may also retry — that is the only
|
|
19
|
+
* way the server can tell a re-send from a genuinely new event.
|
|
20
|
+
*/
|
|
21
|
+
idempotencyKey?: string;
|
|
22
|
+
properties?: Record<string, unknown>;
|
|
23
|
+
actorType?: string;
|
|
24
|
+
agentId?: string;
|
|
25
|
+
taskId?: string;
|
|
26
|
+
workflowId?: string;
|
|
27
|
+
walletAddress?: string;
|
|
28
|
+
chain?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The original request's signals, as observed by a server-side collector.
|
|
32
|
+
* Every field is optional: a collector behind a proxy that strips headers,
|
|
33
|
+
* or a client with `capture_ip` off, still produces useful rows.
|
|
34
|
+
*/
|
|
35
|
+
export interface RequestContext {
|
|
36
|
+
userAgent?: string | null;
|
|
37
|
+
ip?: string | null;
|
|
38
|
+
path?: string | null;
|
|
39
|
+
referrer?: string | null;
|
|
40
|
+
host?: string | null;
|
|
41
|
+
method?: string | null;
|
|
42
|
+
status?: number | null;
|
|
43
|
+
/**
|
|
44
|
+
* Agent protocol inferred from request headers (`mcp` | `x402` | null).
|
|
45
|
+
* See `detectAgentProtocol` in `middleware.ts`. Header VALUES (session ids,
|
|
46
|
+
* payment payloads) are never captured — only this derived label.
|
|
47
|
+
*/
|
|
48
|
+
protocol?: string | null;
|
|
49
|
+
}
|
|
50
|
+
export interface TrackRequestOptions {
|
|
51
|
+
/** Defaults to 'page_view' so server-collected traffic lands in the same
|
|
52
|
+
* Web2 enrichment path as the browser SDK. */
|
|
53
|
+
eventName?: string;
|
|
54
|
+
properties?: Record<string, unknown>;
|
|
55
|
+
actorType?: string;
|
|
56
|
+
idempotencyKey?: string;
|
|
57
|
+
visitorId?: string;
|
|
58
|
+
sessionId?: string;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,oBAAoB;;;;CAIvB,CAAC;AAEX,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC;mDAC+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAQa,QAAA,oBAAoB,GAAG;IAClC,SAAS,EAAE,OAAO;IAClB,UAAU,EAAE,CAAC;IACb,OAAO,EAAE,IAAI;CACL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@analytickit/sdk-node",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Server-side event tracking + request middleware for the AgentGraph / AnalyticKit API. Captures AI crawlers and agents (GPTBot, ClaudeBot, MCP, x402, ...) that never run browser JS.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./middleware": {
|
|
14
|
+
"types": "./dist/middleware.d.ts",
|
|
15
|
+
"default": "./dist/middleware.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"README.md"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc",
|
|
24
|
+
"prepublishOnly": "npm run build",
|
|
25
|
+
"test": "npx tsx --test test/*.test.ts"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^20.0.0",
|
|
35
|
+
"tsx": "^4.0.0",
|
|
36
|
+
"typescript": "^5.4.0"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://analytickit.com"
|
|
39
|
+
}
|