@bbradar/mcp 0.1.3
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 +156 -0
- package/dist/bbradarClient.d.ts +61 -0
- package/dist/bbradarClient.js +307 -0
- package/dist/bbradarClient.js.map +1 -0
- package/dist/cache.d.ts +26 -0
- package/dist/cache.js +60 -0
- package/dist/cache.js.map +1 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.js +60 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/json.d.ts +4 -0
- package/dist/json.js +21 -0
- package/dist/json.js.map +1 -0
- package/dist/rateLimit.d.ts +11 -0
- package/dist/rateLimit.js +29 -0
- package/dist/rateLimit.js.map +1 -0
- package/dist/sanitize.d.ts +11 -0
- package/dist/sanitize.js +202 -0
- package/dist/sanitize.js.map +1 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +4418 -0
- package/dist/server.js.map +1 -0
- package/dist/url.d.ts +1 -0
- package/dist/url.js +21 -0
- package/dist/url.js.map +1 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# @bbradar/mcp
|
|
2
|
+
|
|
3
|
+
Local STDIO MCP server for [bbradar.io](https://bbradar.io) Pro subscribers. It lets MCP clients query [bbradar.io](https://bbradar.io) Pro program, target, opportunity, and recent-change data through a local npm package.
|
|
4
|
+
|
|
5
|
+
## Requirements
|
|
6
|
+
|
|
7
|
+
- Node.js 20 or newer.
|
|
8
|
+
- A [bbradar.io](https://bbradar.io) Pro API key.
|
|
9
|
+
- An MCP client that supports local STDIO servers.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
Most MCP clients can run the package directly with `npx`:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx -y @bbradar/mcp
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
For a global install:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install -g @bbradar/mcp
|
|
23
|
+
bbradar-mcp
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For a project-local install:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm install @bbradar/mcp
|
|
30
|
+
npx bbradar-mcp
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The server needs your [bbradar.io](https://bbradar.io) Pro key. In the MCP client config, add it as `BBRADAR_API_KEY`.
|
|
34
|
+
|
|
35
|
+
## Client Configuration
|
|
36
|
+
|
|
37
|
+
### OpenCode
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"$schema": "https://opencode.ai/config.json",
|
|
42
|
+
"mcp": {
|
|
43
|
+
"bbradar.io": {
|
|
44
|
+
"type": "local",
|
|
45
|
+
"command": ["npx", "-y", "@bbradar/mcp"],
|
|
46
|
+
"enabled": true,
|
|
47
|
+
"timeout": 30000,
|
|
48
|
+
"environment": {
|
|
49
|
+
"BBRADAR_API_KEY": "your_pro_mcp_api_key"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Codex
|
|
57
|
+
|
|
58
|
+
Add with the Codex CLI:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
codex mcp add bbradar.io --env BBRADAR_API_KEY="your_pro_mcp_api_key" -- npx -y @bbradar/mcp
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Or add it to `~/.codex/config.toml`:
|
|
65
|
+
|
|
66
|
+
```toml
|
|
67
|
+
[mcp_servers."bbradar.io"]
|
|
68
|
+
command = "npx"
|
|
69
|
+
args = ["-y", "@bbradar/mcp"]
|
|
70
|
+
|
|
71
|
+
[mcp_servers."bbradar.io".env]
|
|
72
|
+
BBRADAR_API_KEY = "your_pro_mcp_api_key"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Claude Code
|
|
76
|
+
|
|
77
|
+
Add a private user-level server:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
claude mcp add bbradar.io --scope user --env BBRADAR_API_KEY="your_pro_mcp_api_key" -- npx -y @bbradar/mcp
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
On native Windows, wrap `npx` with `cmd /c`:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
claude mcp add bbradar.io --scope user --env BBRADAR_API_KEY="your_pro_mcp_api_key" -- cmd /c npx -y @bbradar/mcp
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Generic MCP JSON
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"mcpServers": {
|
|
94
|
+
"bbradar.io": {
|
|
95
|
+
"command": "npx",
|
|
96
|
+
"args": ["-y", "@bbradar/mcp"],
|
|
97
|
+
"env": {
|
|
98
|
+
"BBRADAR_API_KEY": "your_pro_mcp_api_key"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Verify
|
|
106
|
+
|
|
107
|
+
After adding the MCP config, restart your client and call `get_mcp_status`. A working setup returns server status, timing, and rate-limit metadata.
|
|
108
|
+
|
|
109
|
+
## Tools
|
|
110
|
+
|
|
111
|
+
- `search_programs`
|
|
112
|
+
- `get_program`
|
|
113
|
+
- `resolve_program`
|
|
114
|
+
- `run_program_name_action`
|
|
115
|
+
- `get_program_targets`
|
|
116
|
+
- `get_recent_changes`
|
|
117
|
+
- `get_opportunities`
|
|
118
|
+
- `find_programs`
|
|
119
|
+
- `find_wildcard_programs`
|
|
120
|
+
- `find_web3_programs`
|
|
121
|
+
- `find_reward_programs`
|
|
122
|
+
- `find_web3_contests`
|
|
123
|
+
- `find_language_programs`
|
|
124
|
+
- `find_target_type_programs`
|
|
125
|
+
- `find_vdp_programs`
|
|
126
|
+
- `find_paid_programs`
|
|
127
|
+
- `find_stack_matches`
|
|
128
|
+
- `find_low_noise_programs`
|
|
129
|
+
- `find_recent_by_type`
|
|
130
|
+
- `find_programs_by_target`
|
|
131
|
+
- `find_program_candidates`
|
|
132
|
+
- `find_hunt_candidates`
|
|
133
|
+
- `find_fresh_hunt_candidates`
|
|
134
|
+
- `list_filters`
|
|
135
|
+
- `get_mcp_status`
|
|
136
|
+
- `compare_programs`
|
|
137
|
+
- `compare_programs_compact`
|
|
138
|
+
- `summarize_program_activity`
|
|
139
|
+
- `get_program_brief`
|
|
140
|
+
- `find_recently_added_wildcards`
|
|
141
|
+
- `find_low_competition_high_reward`
|
|
142
|
+
- `get_program_delta`
|
|
143
|
+
- `get_latest_added_targets`
|
|
144
|
+
- `get_program_scope_summary`
|
|
145
|
+
- `get_program_target_breakdown`
|
|
146
|
+
- `get_program_scope_delta`
|
|
147
|
+
- `get_recent_target_activity`
|
|
148
|
+
- `check_program_new_targets`
|
|
149
|
+
- `check_watchlist_new_targets`
|
|
150
|
+
- `export_targets`
|
|
151
|
+
|
|
152
|
+
## Prompts
|
|
153
|
+
|
|
154
|
+
- `find_best_programs_to_hunt`
|
|
155
|
+
- `summarize_program_scope`
|
|
156
|
+
- `prepare_recon_plan`
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type CacheStats } from "./cache.js";
|
|
2
|
+
import type { ServerConfig } from "./config.js";
|
|
3
|
+
export type QueryValue = string | number | boolean | null | undefined | readonly string[] | readonly number[] | readonly boolean[];
|
|
4
|
+
export type ApiRequestOptions = {
|
|
5
|
+
method?: "GET" | "POST";
|
|
6
|
+
path: string;
|
|
7
|
+
query?: Record<string, QueryValue>;
|
|
8
|
+
body?: unknown;
|
|
9
|
+
cache?: boolean;
|
|
10
|
+
coalesce?: boolean;
|
|
11
|
+
};
|
|
12
|
+
export type ApiResult<T> = {
|
|
13
|
+
data: T;
|
|
14
|
+
requestId: string;
|
|
15
|
+
upstreamRequestId?: string | undefined;
|
|
16
|
+
cached: boolean;
|
|
17
|
+
coalesced?: boolean | undefined;
|
|
18
|
+
status: number;
|
|
19
|
+
fetchedAt: string;
|
|
20
|
+
cacheExpiresAt?: string | undefined;
|
|
21
|
+
};
|
|
22
|
+
export declare class BBRadarApiError extends Error {
|
|
23
|
+
readonly requestId: string;
|
|
24
|
+
readonly upstreamRequestId: string | undefined;
|
|
25
|
+
readonly status: number | undefined;
|
|
26
|
+
readonly detail?: unknown;
|
|
27
|
+
readonly errors?: unknown;
|
|
28
|
+
constructor(params: {
|
|
29
|
+
message: string;
|
|
30
|
+
requestId: string;
|
|
31
|
+
upstreamRequestId?: string | undefined;
|
|
32
|
+
status?: number | undefined;
|
|
33
|
+
detail?: unknown;
|
|
34
|
+
errors?: unknown;
|
|
35
|
+
cause?: unknown;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
export declare class BBRadarClient {
|
|
39
|
+
private readonly config;
|
|
40
|
+
private readonly cache;
|
|
41
|
+
private readonly inFlight;
|
|
42
|
+
constructor(config: ServerConfig);
|
|
43
|
+
diagnostics(): {
|
|
44
|
+
response_cache: CacheStats & {
|
|
45
|
+
enabled: boolean;
|
|
46
|
+
};
|
|
47
|
+
in_flight_requests: number;
|
|
48
|
+
};
|
|
49
|
+
validateKey(): Promise<void>;
|
|
50
|
+
listPrograms(query: Record<string, QueryValue>): Promise<ApiResult<unknown>>;
|
|
51
|
+
getProgram(programId: string): Promise<ApiResult<unknown>>;
|
|
52
|
+
getProgramTargets(programId: string): Promise<ApiResult<unknown>>;
|
|
53
|
+
getRecentChanges(query: Record<string, QueryValue>): Promise<ApiResult<unknown>>;
|
|
54
|
+
searchTargets(query: Record<string, QueryValue>): Promise<ApiResult<unknown>>;
|
|
55
|
+
getOpportunities(level: string, query: Record<string, QueryValue>): Promise<ApiResult<unknown>>;
|
|
56
|
+
exportTargets(body: Record<string, unknown>): Promise<ApiResult<unknown>>;
|
|
57
|
+
request<T = unknown>(options: ApiRequestOptions): Promise<ApiResult<T>>;
|
|
58
|
+
private fetchFromApi;
|
|
59
|
+
private buildUrl;
|
|
60
|
+
private headers;
|
|
61
|
+
}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { TtlCache } from "./cache.js";
|
|
3
|
+
import { stableStringify } from "./json.js";
|
|
4
|
+
import { encodeProgramIdPath } from "./url.js";
|
|
5
|
+
export class BBRadarApiError extends Error {
|
|
6
|
+
requestId;
|
|
7
|
+
upstreamRequestId;
|
|
8
|
+
status;
|
|
9
|
+
detail;
|
|
10
|
+
errors;
|
|
11
|
+
constructor(params) {
|
|
12
|
+
super(params.message, { cause: params.cause });
|
|
13
|
+
this.name = "BBRadarApiError";
|
|
14
|
+
this.requestId = params.requestId;
|
|
15
|
+
this.upstreamRequestId = params.upstreamRequestId;
|
|
16
|
+
this.status = params.status;
|
|
17
|
+
this.detail = params.detail;
|
|
18
|
+
this.errors = params.errors;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export class BBRadarClient {
|
|
22
|
+
config;
|
|
23
|
+
cache;
|
|
24
|
+
inFlight = new Map();
|
|
25
|
+
constructor(config) {
|
|
26
|
+
this.config = config;
|
|
27
|
+
this.cache = new TtlCache(config.cacheMaxEntries, config.cacheTtlMs);
|
|
28
|
+
}
|
|
29
|
+
diagnostics() {
|
|
30
|
+
return {
|
|
31
|
+
response_cache: {
|
|
32
|
+
enabled: this.config.cacheTtlMs > 0 && this.config.cacheMaxEntries > 0,
|
|
33
|
+
...this.cache.stats()
|
|
34
|
+
},
|
|
35
|
+
in_flight_requests: this.inFlight.size
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
async validateKey() {
|
|
39
|
+
try {
|
|
40
|
+
await this.request({
|
|
41
|
+
path: "/pro/programs",
|
|
42
|
+
query: { page: 1, page_size: 1 },
|
|
43
|
+
cache: false,
|
|
44
|
+
coalesce: false
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (!(error instanceof BBRadarApiError)) {
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
if (error.status === 401) {
|
|
52
|
+
throw new Error("BBRADAR_API_KEY was rejected by the BBRadar Pro API.");
|
|
53
|
+
}
|
|
54
|
+
if (error.status === 402) {
|
|
55
|
+
throw new Error("The BBRadar API key does not have an active Pro subscription entitlement.");
|
|
56
|
+
}
|
|
57
|
+
if (error.status === 403) {
|
|
58
|
+
throw new Error("The BBRadar API key is not allowed to use MCP or lacks the required read-only scope.");
|
|
59
|
+
}
|
|
60
|
+
if (error.status === 423) {
|
|
61
|
+
throw new Error("The BBRadar Pro account or API key is locked.");
|
|
62
|
+
}
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
listPrograms(query) {
|
|
67
|
+
return this.request({
|
|
68
|
+
path: "/pro/programs",
|
|
69
|
+
query
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
getProgram(programId) {
|
|
73
|
+
return this.request({
|
|
74
|
+
path: `/pro/programs/${encodeProgramIdPath(programId)}`
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
getProgramTargets(programId) {
|
|
78
|
+
return this.request({
|
|
79
|
+
path: `/pro/programs/${encodeProgramIdPath(programId)}/targets`
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
getRecentChanges(query) {
|
|
83
|
+
return this.request({
|
|
84
|
+
path: "/pro/targets/changes",
|
|
85
|
+
query
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
searchTargets(query) {
|
|
89
|
+
return this.request({
|
|
90
|
+
path: "/pro/targets/search",
|
|
91
|
+
query
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
getOpportunities(level, query) {
|
|
95
|
+
return this.request({
|
|
96
|
+
path: `/pro/opportunities/${encodeURIComponent(level)}`,
|
|
97
|
+
query
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
exportTargets(body) {
|
|
101
|
+
return this.request({
|
|
102
|
+
method: "POST",
|
|
103
|
+
path: "/pro/targets/export",
|
|
104
|
+
body,
|
|
105
|
+
cache: false,
|
|
106
|
+
coalesce: false
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
async request(options) {
|
|
110
|
+
const method = options.method ?? "GET";
|
|
111
|
+
const requestId = randomUUID();
|
|
112
|
+
const url = this.buildUrl(options.path, options.query);
|
|
113
|
+
const requestKey = stableStringify({
|
|
114
|
+
method,
|
|
115
|
+
url: url.toString(),
|
|
116
|
+
body: options.body ?? null
|
|
117
|
+
});
|
|
118
|
+
const cacheable = method === "GET" && (options.cache ?? true) && this.config.cacheTtlMs > 0 && this.config.cacheMaxEntries > 0;
|
|
119
|
+
const coalesceable = method === "GET" && (options.coalesce ?? true);
|
|
120
|
+
if (cacheable) {
|
|
121
|
+
const cached = this.cache.get(requestKey);
|
|
122
|
+
if (cached) {
|
|
123
|
+
return {
|
|
124
|
+
...cached.value,
|
|
125
|
+
requestId,
|
|
126
|
+
cached: true,
|
|
127
|
+
cacheExpiresAt: new Date(cached.expiresAt).toISOString()
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (coalesceable) {
|
|
132
|
+
const pending = this.inFlight.get(requestKey);
|
|
133
|
+
if (pending) {
|
|
134
|
+
try {
|
|
135
|
+
const result = (await pending);
|
|
136
|
+
return {
|
|
137
|
+
...result,
|
|
138
|
+
requestId,
|
|
139
|
+
cached: false,
|
|
140
|
+
coalesced: true
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
throw cloneApiError(error, requestId);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const request = this.fetchFromApi(options, method, url, requestId);
|
|
149
|
+
if (coalesceable) {
|
|
150
|
+
this.inFlight.set(requestKey, request);
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
const result = await request;
|
|
154
|
+
if (cacheable) {
|
|
155
|
+
this.cache.set(requestKey, result);
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
...result,
|
|
159
|
+
requestId,
|
|
160
|
+
cached: false
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
if (coalesceable) {
|
|
165
|
+
this.inFlight.delete(requestKey);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async fetchFromApi(options, method, url, requestId) {
|
|
170
|
+
const controller = new AbortController();
|
|
171
|
+
const timeout = setTimeout(() => controller.abort(), this.config.requestTimeoutMs);
|
|
172
|
+
try {
|
|
173
|
+
const init = {
|
|
174
|
+
method,
|
|
175
|
+
headers: this.headers(options.body),
|
|
176
|
+
cache: "no-store",
|
|
177
|
+
signal: controller.signal
|
|
178
|
+
};
|
|
179
|
+
if (options.body !== undefined) {
|
|
180
|
+
init.body = JSON.stringify(options.body);
|
|
181
|
+
}
|
|
182
|
+
const response = await fetch(url, init);
|
|
183
|
+
const upstreamRequestId = extractRequestId(response.headers);
|
|
184
|
+
const data = await parseResponseBody(response);
|
|
185
|
+
if (!response.ok) {
|
|
186
|
+
const params = {
|
|
187
|
+
message: formatApiErrorMessage(response.status, data),
|
|
188
|
+
requestId,
|
|
189
|
+
status: response.status,
|
|
190
|
+
detail: extractObjectField(data, "detail"),
|
|
191
|
+
errors: extractObjectField(data, "errors")
|
|
192
|
+
};
|
|
193
|
+
if (upstreamRequestId) {
|
|
194
|
+
params.upstreamRequestId = upstreamRequestId;
|
|
195
|
+
}
|
|
196
|
+
throw new BBRadarApiError(params);
|
|
197
|
+
}
|
|
198
|
+
const result = {
|
|
199
|
+
data: data,
|
|
200
|
+
status: response.status,
|
|
201
|
+
fetchedAt: new Date().toISOString()
|
|
202
|
+
};
|
|
203
|
+
if (upstreamRequestId) {
|
|
204
|
+
result.upstreamRequestId = upstreamRequestId;
|
|
205
|
+
}
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
if (error instanceof BBRadarApiError) {
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
throw new BBRadarApiError({
|
|
213
|
+
message: error instanceof Error && error.name === "AbortError" ? "BBRadar API request timed out." : "BBRadar API request failed.",
|
|
214
|
+
requestId,
|
|
215
|
+
cause: error
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
finally {
|
|
219
|
+
clearTimeout(timeout);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
buildUrl(path, query) {
|
|
223
|
+
const url = new URL(`${this.config.apiBaseUrl}${path}`);
|
|
224
|
+
for (const [key, value] of Object.entries(query ?? {})) {
|
|
225
|
+
if (value === undefined || value === null) {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
if (Array.isArray(value)) {
|
|
229
|
+
if (value.length > 0) {
|
|
230
|
+
url.searchParams.set(key, value.join(","));
|
|
231
|
+
}
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
url.searchParams.set(key, String(value));
|
|
235
|
+
}
|
|
236
|
+
return url;
|
|
237
|
+
}
|
|
238
|
+
headers(body) {
|
|
239
|
+
const headers = {
|
|
240
|
+
authorization: `Bearer ${this.config.apiKey}`,
|
|
241
|
+
accept: "application/json",
|
|
242
|
+
"cache-control": "no-cache, no-store, max-age=0",
|
|
243
|
+
pragma: "no-cache",
|
|
244
|
+
"user-agent": "@bbradar/mcp"
|
|
245
|
+
};
|
|
246
|
+
if (body !== undefined) {
|
|
247
|
+
headers["content-type"] = "application/json";
|
|
248
|
+
}
|
|
249
|
+
return headers;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async function parseResponseBody(response) {
|
|
253
|
+
if (response.status === 204) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
257
|
+
const text = await response.text();
|
|
258
|
+
if (text.length === 0) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
if (contentType.includes("application/json") || contentType.includes("+json")) {
|
|
262
|
+
try {
|
|
263
|
+
return JSON.parse(text);
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
return text;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return text;
|
|
270
|
+
}
|
|
271
|
+
function extractRequestId(headers) {
|
|
272
|
+
return (headers.get("x-request-id") ??
|
|
273
|
+
headers.get("x-correlation-id") ??
|
|
274
|
+
headers.get("request-id") ??
|
|
275
|
+
undefined);
|
|
276
|
+
}
|
|
277
|
+
function extractObjectField(value, field) {
|
|
278
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
279
|
+
return undefined;
|
|
280
|
+
}
|
|
281
|
+
return value[field];
|
|
282
|
+
}
|
|
283
|
+
function formatApiErrorMessage(status, data) {
|
|
284
|
+
const detail = extractObjectField(data, "detail");
|
|
285
|
+
const message = extractObjectField(data, "message");
|
|
286
|
+
const suffix = typeof detail === "string"
|
|
287
|
+
? detail
|
|
288
|
+
: typeof message === "string"
|
|
289
|
+
? message
|
|
290
|
+
: "Request was rejected.";
|
|
291
|
+
return `BBRadar API returned ${status}: ${suffix}`;
|
|
292
|
+
}
|
|
293
|
+
function cloneApiError(error, requestId) {
|
|
294
|
+
if (!(error instanceof BBRadarApiError)) {
|
|
295
|
+
return error;
|
|
296
|
+
}
|
|
297
|
+
return new BBRadarApiError({
|
|
298
|
+
message: error.message,
|
|
299
|
+
requestId,
|
|
300
|
+
upstreamRequestId: error.upstreamRequestId,
|
|
301
|
+
status: error.status,
|
|
302
|
+
detail: error.detail,
|
|
303
|
+
errors: error.errors,
|
|
304
|
+
cause: error
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
//# sourceMappingURL=bbradarClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bbradarClient.js","sourceRoot":"","sources":["../src/bbradarClient.ts"],"names":[],"mappings":"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"}
|
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type CacheEntry<T> = {
|
|
2
|
+
value: T;
|
|
3
|
+
expiresAt: number;
|
|
4
|
+
};
|
|
5
|
+
export type CacheStats = {
|
|
6
|
+
entries: number;
|
|
7
|
+
max_entries: number;
|
|
8
|
+
ttl_ms: number;
|
|
9
|
+
hits: number;
|
|
10
|
+
misses: number;
|
|
11
|
+
sets: number;
|
|
12
|
+
evictions: number;
|
|
13
|
+
};
|
|
14
|
+
export declare class TtlCache<T> {
|
|
15
|
+
private readonly maxEntries;
|
|
16
|
+
private readonly ttlMs;
|
|
17
|
+
private readonly entries;
|
|
18
|
+
private hits;
|
|
19
|
+
private misses;
|
|
20
|
+
private sets;
|
|
21
|
+
private evictions;
|
|
22
|
+
constructor(maxEntries?: number, ttlMs?: number);
|
|
23
|
+
get(key: string): CacheEntry<T> | undefined;
|
|
24
|
+
set(key: string, value: T): void;
|
|
25
|
+
stats(): CacheStats;
|
|
26
|
+
}
|
package/dist/cache.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export class TtlCache {
|
|
2
|
+
maxEntries;
|
|
3
|
+
ttlMs;
|
|
4
|
+
entries = new Map();
|
|
5
|
+
hits = 0;
|
|
6
|
+
misses = 0;
|
|
7
|
+
sets = 0;
|
|
8
|
+
evictions = 0;
|
|
9
|
+
constructor(maxEntries = 500, ttlMs = 30_000) {
|
|
10
|
+
this.maxEntries = maxEntries;
|
|
11
|
+
this.ttlMs = ttlMs;
|
|
12
|
+
}
|
|
13
|
+
get(key) {
|
|
14
|
+
const entry = this.entries.get(key);
|
|
15
|
+
if (!entry) {
|
|
16
|
+
this.misses += 1;
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
if (entry.expiresAt <= Date.now()) {
|
|
20
|
+
this.entries.delete(key);
|
|
21
|
+
this.misses += 1;
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
this.hits += 1;
|
|
25
|
+
return entry;
|
|
26
|
+
}
|
|
27
|
+
set(key, value) {
|
|
28
|
+
if (this.ttlMs <= 0 || this.maxEntries <= 0) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (this.entries.has(key)) {
|
|
32
|
+
this.entries.delete(key);
|
|
33
|
+
}
|
|
34
|
+
while (this.entries.size >= this.maxEntries) {
|
|
35
|
+
const oldestKey = this.entries.keys().next().value;
|
|
36
|
+
if (oldestKey === undefined) {
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
this.entries.delete(oldestKey);
|
|
40
|
+
this.evictions += 1;
|
|
41
|
+
}
|
|
42
|
+
this.entries.set(key, {
|
|
43
|
+
value,
|
|
44
|
+
expiresAt: Date.now() + this.ttlMs
|
|
45
|
+
});
|
|
46
|
+
this.sets += 1;
|
|
47
|
+
}
|
|
48
|
+
stats() {
|
|
49
|
+
return {
|
|
50
|
+
entries: this.entries.size,
|
|
51
|
+
max_entries: this.maxEntries,
|
|
52
|
+
ttl_ms: this.ttlMs,
|
|
53
|
+
hits: this.hits,
|
|
54
|
+
misses: this.misses,
|
|
55
|
+
sets: this.sets,
|
|
56
|
+
evictions: this.evictions
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAeA,MAAM,OAAO,QAAQ;IAQA;IACA;IARF,OAAO,GAAG,IAAI,GAAG,EAAyB,CAAC;IACpD,IAAI,GAAG,CAAC,CAAC;IACT,MAAM,GAAG,CAAC,CAAC;IACX,IAAI,GAAG,CAAC,CAAC;IACT,SAAS,GAAG,CAAC,CAAC;IAEtB,YACmB,aAAa,GAAG,EAChB,QAAQ,MAAM;QADd,eAAU,GAAV,UAAU,CAAM;QAChB,UAAK,GAAL,KAAK,CAAS;IAC9B,CAAC;IAEJ,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEpC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YACjB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YACjB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;QACf,OAAO,KAAK,CAAC;IACf,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAQ;QACvB,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC;YAC5C,OAAO;QACT,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YAEnD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,MAAM;YACR,CAAC;YAED,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAC/B,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC;QACtB,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE;YACpB,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK;SACnC,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;IACjB,CAAC;IAED,KAAK;QACH,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI;YAC1B,WAAW,EAAE,IAAI,CAAC,UAAU;YAC5B,MAAM,EAAE,IAAI,CAAC,KAAK;YAClB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC;IACJ,CAAC;CACF"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type ServerConfig = {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
apiBaseUrl: string;
|
|
4
|
+
webBaseUrl: string;
|
|
5
|
+
cacheTtlMs: number;
|
|
6
|
+
cacheMaxEntries: number;
|
|
7
|
+
defaultRateLimitPerMinute: number;
|
|
8
|
+
exportRateLimitPerMinute: number;
|
|
9
|
+
requestTimeoutMs: number;
|
|
10
|
+
validateOnStartup: boolean;
|
|
11
|
+
};
|
|
12
|
+
export declare function loadConfig(env?: NodeJS.ProcessEnv): ServerConfig;
|