@trylighthouse/mcp-server 0.1.101
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 +198 -0
- package/build/api.d.ts +38 -0
- package/build/api.js +59 -0
- package/build/index.d.ts +3 -0
- package/build/index.js +86 -0
- package/build/leanDiscovery.d.ts +11 -0
- package/build/leanDiscovery.js +93 -0
- package/build/server.d.ts +2 -0
- package/build/server.js +2903 -0
- package/package.json +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Lighthouse MCP Server
|
|
2
|
+
|
|
3
|
+
An [MCP](https://modelcontextprotocol.io/) server that connects AI assistants (Claude, Cursor, etc.) to the Lighthouse CRM API.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
### 1. Get your API key
|
|
8
|
+
|
|
9
|
+
Go to **Settings → API Keys** in Lighthouse and generate a key.
|
|
10
|
+
|
|
11
|
+
### 2. Configure your AI client
|
|
12
|
+
|
|
13
|
+
#### Claude Desktop
|
|
14
|
+
|
|
15
|
+
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"mcpServers": {
|
|
20
|
+
"lighthouse": {
|
|
21
|
+
"command": "npx",
|
|
22
|
+
"args": ["-y", "@trylighthouse/mcp-server@latest"],
|
|
23
|
+
"env": {
|
|
24
|
+
"LIGHTHOUSE_API_KEY": "your-api-key"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
#### Claude Code
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
claude mcp add lighthouse -- npx -y @trylighthouse/mcp-server@latest
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Set the env var: `export LIGHTHOUSE_API_KEY=your-api-key`
|
|
38
|
+
|
|
39
|
+
#### Cursor
|
|
40
|
+
|
|
41
|
+
Add to `.cursor/mcp.json`:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"mcpServers": {
|
|
46
|
+
"lighthouse": {
|
|
47
|
+
"command": "npx",
|
|
48
|
+
"args": ["-y", "@trylighthouse/mcp-server@latest"],
|
|
49
|
+
"env": {
|
|
50
|
+
"LIGHTHOUSE_API_KEY": "your-api-key"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Available Tools
|
|
58
|
+
|
|
59
|
+
### Records
|
|
60
|
+
|
|
61
|
+
Records support built-in types (`company`, `person`, `deal`) and custom object types (use the permalink as `record_type`).
|
|
62
|
+
|
|
63
|
+
| Tool | Description |
|
|
64
|
+
|------|-------------|
|
|
65
|
+
| `lighthouse_crm_search_records` | Search/filter records with CRM-style filters and sorting |
|
|
66
|
+
| `lighthouse_crm_get_record` | Get a single record by ID |
|
|
67
|
+
| `lighthouse_crm_create_record` | Create a new record |
|
|
68
|
+
| `lighthouse_crm_update_record` | Update a record's fields |
|
|
69
|
+
| `lighthouse_crm_delete_record` | Delete a record |
|
|
70
|
+
|
|
71
|
+
### Attributes & Options
|
|
72
|
+
|
|
73
|
+
| Tool | Description |
|
|
74
|
+
|------|-------------|
|
|
75
|
+
| `lighthouse_crm_get_attributes` | List all field definitions for a record type |
|
|
76
|
+
| `lighthouse_crm_get_attribute` | Get a single field definition |
|
|
77
|
+
| `lighthouse_crm_create_attribute` | Create a custom field |
|
|
78
|
+
| `lighthouse_crm_update_attribute` | Update a custom field |
|
|
79
|
+
| `lighthouse_crm_delete_attribute` | Delete a custom field |
|
|
80
|
+
| `lighthouse_crm_get_color_palette` | Get available colors for select options |
|
|
81
|
+
| `lighthouse_crm_list_options` | List options for a select/status field |
|
|
82
|
+
| `lighthouse_crm_create_option` | Create a field option |
|
|
83
|
+
| `lighthouse_crm_delete_option` | Delete a field option |
|
|
84
|
+
|
|
85
|
+
### Lists
|
|
86
|
+
|
|
87
|
+
| Tool | Description |
|
|
88
|
+
|------|-------------|
|
|
89
|
+
| `lighthouse_crm_list_lists` | Get all CRM lists |
|
|
90
|
+
| `lighthouse_crm_create_list` | Create a new list |
|
|
91
|
+
| `lighthouse_crm_get_list` | Get a single list |
|
|
92
|
+
| `lighthouse_crm_update_list` | Update a list |
|
|
93
|
+
| `lighthouse_crm_delete_list` | Delete a list |
|
|
94
|
+
| `lighthouse_crm_get_list_records` | Get records in a list |
|
|
95
|
+
| `lighthouse_crm_add_to_list` | Add a record to a list |
|
|
96
|
+
| `lighthouse_crm_remove_from_list` | Remove a record from a list |
|
|
97
|
+
| `lighthouse_crm_share_list_with_teams` | Share a list with teams |
|
|
98
|
+
| `lighthouse_crm_revoke_list_from_teams` | Revoke team access to a list |
|
|
99
|
+
| `lighthouse_crm_update_list_sharing` | Update list sharing scope |
|
|
100
|
+
|
|
101
|
+
### Notes
|
|
102
|
+
|
|
103
|
+
Notes can be linked to multiple records at once (via the `records` map). After creation, use the link/unlink tools to add or remove associations.
|
|
104
|
+
|
|
105
|
+
| Tool | Description |
|
|
106
|
+
|------|-------------|
|
|
107
|
+
| `lighthouse_crm_list_notes` | List notes for a record |
|
|
108
|
+
| `lighthouse_crm_create_note` | Create a note linked to one or more records |
|
|
109
|
+
| `lighthouse_crm_get_note` | Get a single note |
|
|
110
|
+
| `lighthouse_crm_delete_note` | Delete a note |
|
|
111
|
+
| `lighthouse_crm_link_note_record` | Link an existing note to an additional record |
|
|
112
|
+
| `lighthouse_crm_unlink_note_record` | Remove a note's link to a record |
|
|
113
|
+
|
|
114
|
+
### Tasks
|
|
115
|
+
|
|
116
|
+
Tasks can be linked to any record type including custom objects. Use the permalink as the key in `records` (e.g., `{"company": [ids], "news": [ids]}`).
|
|
117
|
+
|
|
118
|
+
| Tool | Description |
|
|
119
|
+
|------|-------------|
|
|
120
|
+
| `lighthouse_crm_list_tasks` | List tasks with optional filtering and sorting |
|
|
121
|
+
| `lighthouse_crm_get_task` | Get a single task |
|
|
122
|
+
| `lighthouse_crm_create_task` | Create a task, optionally linked to records |
|
|
123
|
+
| `lighthouse_crm_update_task` | Update a task |
|
|
124
|
+
| `lighthouse_crm_delete_task` | Delete a task |
|
|
125
|
+
|
|
126
|
+
### Files
|
|
127
|
+
|
|
128
|
+
| Tool | Description |
|
|
129
|
+
|------|-------------|
|
|
130
|
+
| `lighthouse_crm_list_files` | List files attached to a record |
|
|
131
|
+
| `lighthouse_crm_upload_file` | Upload a file and attach it to a record |
|
|
132
|
+
| `lighthouse_crm_download_file` | Download a file |
|
|
133
|
+
| `lighthouse_crm_delete_file` | Delete a file |
|
|
134
|
+
|
|
135
|
+
### Views
|
|
136
|
+
|
|
137
|
+
| Tool | Description |
|
|
138
|
+
|------|-------------|
|
|
139
|
+
| `lighthouse_crm_list_views` | List saved CRM views |
|
|
140
|
+
| `lighthouse_crm_get_view` | Get a single view |
|
|
141
|
+
| `lighthouse_crm_update_view` | Update a view |
|
|
142
|
+
| `lighthouse_crm_delete_view` | Delete a view |
|
|
143
|
+
| `lighthouse_crm_share_view_with_teams` | Share a view with teams |
|
|
144
|
+
| `lighthouse_crm_revoke_view_from_teams` | Revoke team access to a view |
|
|
145
|
+
| `lighthouse_crm_update_view_sharing` | Update view sharing scope |
|
|
146
|
+
|
|
147
|
+
### Workspace
|
|
148
|
+
|
|
149
|
+
| Tool | Description |
|
|
150
|
+
|------|-------------|
|
|
151
|
+
| `lighthouse_workspace_me` | Get current authenticated user |
|
|
152
|
+
| `lighthouse_workspace_list_users` | List workspace users |
|
|
153
|
+
| `lighthouse_workspace_get_user` | Get a workspace user |
|
|
154
|
+
| `lighthouse_workspace_list_teams` | List workspace teams |
|
|
155
|
+
| `lighthouse_workspace_get_team` | Get a workspace team |
|
|
156
|
+
|
|
157
|
+
### Discovery
|
|
158
|
+
|
|
159
|
+
| Tool | Description |
|
|
160
|
+
|------|-------------|
|
|
161
|
+
| `lighthouse_discovery_get_attributes` | Get discovery filter attributes |
|
|
162
|
+
| `lighthouse_discovery_search_companies` | Search the company database |
|
|
163
|
+
| `lighthouse_discovery_search_investors` | Search investors (VC funds, angels, etc.) |
|
|
164
|
+
| `lighthouse_discovery_search_organizations` | Search non-profits, governments, and other organizations |
|
|
165
|
+
| `lighthouse_discovery_search_schools` | Search schools and universities |
|
|
166
|
+
| `lighthouse_discovery_search_people` | Search the people database |
|
|
167
|
+
| `lighthouse_discovery_lookup_by_domain` | Look up companies by domain |
|
|
168
|
+
| `lighthouse_discovery_lookup_by_linkedin` | Look up companies by LinkedIn URL |
|
|
169
|
+
| `lighthouse_discovery_lookup_people_by_linkedin` | Look up people by LinkedIn URL |
|
|
170
|
+
| `lighthouse_discovery_get_saved_searches` | List saved discovery searches |
|
|
171
|
+
| `lighthouse_discovery_get_search_results` | Get results of a saved search |
|
|
172
|
+
| `lighthouse_discovery_get_locations` | Get location filter options |
|
|
173
|
+
| `lighthouse_discovery_get_industries` | Get industry filter options |
|
|
174
|
+
| `lighthouse_discovery_get_tags` | Get tag filter options |
|
|
175
|
+
|
|
176
|
+
### Reports & Dashboards
|
|
177
|
+
|
|
178
|
+
| Tool | Description |
|
|
179
|
+
|------|-------------|
|
|
180
|
+
| `lighthouse_reports_list_dashboards` | List dashboards |
|
|
181
|
+
| `lighthouse_reports_create_dashboard` | Create a dashboard |
|
|
182
|
+
| `lighthouse_reports_get_dashboard` | Get a dashboard |
|
|
183
|
+
| `lighthouse_reports_update_dashboard` | Update a dashboard |
|
|
184
|
+
| `lighthouse_reports_delete_dashboard` | Delete a dashboard |
|
|
185
|
+
| `lighthouse_reports_list_widgets` | List widgets in a dashboard |
|
|
186
|
+
| `lighthouse_reports_create_widget` | Create a widget |
|
|
187
|
+
| `lighthouse_reports_update_widget` | Update a widget |
|
|
188
|
+
| `lighthouse_reports_delete_widget` | Delete a widget |
|
|
189
|
+
| `lighthouse_reports_get_widget_data` | Get widget data |
|
|
190
|
+
| `lighthouse_reports_share_dashboard_with_teams` | Share a dashboard with teams |
|
|
191
|
+
| `lighthouse_reports_revoke_dashboard_from_teams` | Revoke team access to a dashboard |
|
|
192
|
+
|
|
193
|
+
## Environment Variables
|
|
194
|
+
|
|
195
|
+
| Variable | Required | Description |
|
|
196
|
+
|----------|----------|-------------|
|
|
197
|
+
| `LIGHTHOUSE_API_KEY` | Yes | Your Lighthouse API key |
|
|
198
|
+
| `LIGHTHOUSE_API_URL` | No | Override API base URL (default: `https://api.trylighthouse.vc`) |
|
package/build/api.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export declare class LighthouseAPI {
|
|
2
|
+
private baseUrl;
|
|
3
|
+
private apiKey;
|
|
4
|
+
private currentTool;
|
|
5
|
+
constructor(apiKey?: string);
|
|
6
|
+
setCurrentTool(toolName: string | null): void;
|
|
7
|
+
private request;
|
|
8
|
+
get(path: string, params?: Record<string, unknown>): Promise<{
|
|
9
|
+
status: number;
|
|
10
|
+
data: unknown;
|
|
11
|
+
error: unknown;
|
|
12
|
+
meta?: unknown;
|
|
13
|
+
}>;
|
|
14
|
+
post(path: string, body?: Record<string, unknown>): Promise<{
|
|
15
|
+
status: number;
|
|
16
|
+
data: unknown;
|
|
17
|
+
error: unknown;
|
|
18
|
+
meta?: unknown;
|
|
19
|
+
}>;
|
|
20
|
+
patch(path: string, body?: Record<string, unknown>): Promise<{
|
|
21
|
+
status: number;
|
|
22
|
+
data: unknown;
|
|
23
|
+
error: unknown;
|
|
24
|
+
meta?: unknown;
|
|
25
|
+
}>;
|
|
26
|
+
put(path: string, body?: Record<string, unknown>): Promise<{
|
|
27
|
+
status: number;
|
|
28
|
+
data: unknown;
|
|
29
|
+
error: unknown;
|
|
30
|
+
meta?: unknown;
|
|
31
|
+
}>;
|
|
32
|
+
delete(path: string, body?: Record<string, unknown>): Promise<{
|
|
33
|
+
status: number;
|
|
34
|
+
data: unknown;
|
|
35
|
+
error: unknown;
|
|
36
|
+
meta?: unknown;
|
|
37
|
+
}>;
|
|
38
|
+
}
|
package/build/api.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const DEFAULT_BASE_URL = "https://api.trylighthouse.vc";
|
|
2
|
+
export class LighthouseAPI {
|
|
3
|
+
baseUrl;
|
|
4
|
+
apiKey;
|
|
5
|
+
currentTool = null;
|
|
6
|
+
constructor(apiKey) {
|
|
7
|
+
const key = apiKey || process.env.LIGHTHOUSE_API_KEY;
|
|
8
|
+
if (!key) {
|
|
9
|
+
throw new Error("LIGHTHOUSE_API_KEY environment variable is required. " +
|
|
10
|
+
"Generate one at Settings → API Keys in Lighthouse.");
|
|
11
|
+
}
|
|
12
|
+
this.apiKey = key;
|
|
13
|
+
this.baseUrl = (process.env.LIGHTHOUSE_API_URL || DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
14
|
+
}
|
|
15
|
+
setCurrentTool(toolName) {
|
|
16
|
+
this.currentTool = toolName;
|
|
17
|
+
}
|
|
18
|
+
async request(method, path, body) {
|
|
19
|
+
const versioned = (/^\/v\d+\//.test(path) || path.startsWith("/mcp/")) ? path : `/v1${path}`;
|
|
20
|
+
const url = `${this.baseUrl}${versioned}`;
|
|
21
|
+
const headers = {
|
|
22
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
23
|
+
"Content-Type": "application/json",
|
|
24
|
+
"X-Lighthouse-Origin": "mcp",
|
|
25
|
+
};
|
|
26
|
+
if (this.currentTool) {
|
|
27
|
+
headers["X-Lighthouse-MCP-Tool"] = this.currentTool;
|
|
28
|
+
}
|
|
29
|
+
const res = await fetch(url, {
|
|
30
|
+
method,
|
|
31
|
+
headers,
|
|
32
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
33
|
+
});
|
|
34
|
+
const json = await res.json();
|
|
35
|
+
return json;
|
|
36
|
+
}
|
|
37
|
+
async get(path, params) {
|
|
38
|
+
const qs = params
|
|
39
|
+
? "?" +
|
|
40
|
+
Object.entries(params)
|
|
41
|
+
.filter(([, v]) => v !== undefined && v !== null)
|
|
42
|
+
.map(([k, v]) => `${k}=${encodeURIComponent(typeof v === "object" ? JSON.stringify(v) : String(v))}`)
|
|
43
|
+
.join("&")
|
|
44
|
+
: "";
|
|
45
|
+
return this.request("GET", path + qs);
|
|
46
|
+
}
|
|
47
|
+
async post(path, body) {
|
|
48
|
+
return this.request("POST", path, body);
|
|
49
|
+
}
|
|
50
|
+
async patch(path, body) {
|
|
51
|
+
return this.request("PATCH", path, body);
|
|
52
|
+
}
|
|
53
|
+
async put(path, body) {
|
|
54
|
+
return this.request("PUT", path, body);
|
|
55
|
+
}
|
|
56
|
+
async delete(path, body) {
|
|
57
|
+
return this.request("DELETE", path, body);
|
|
58
|
+
}
|
|
59
|
+
}
|
package/build/index.d.ts
ADDED
package/build/index.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
4
|
+
import { createServer as createHttpServer } from "node:http";
|
|
5
|
+
import { createServer } from "./server.js";
|
|
6
|
+
export { createServer } from "./server.js";
|
|
7
|
+
export { LighthouseAPI } from "./api.js";
|
|
8
|
+
async function main() {
|
|
9
|
+
const port = process.env.PORT;
|
|
10
|
+
if (port) {
|
|
11
|
+
const sessions = new Map();
|
|
12
|
+
const httpServer = createHttpServer(async (req, res) => {
|
|
13
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
14
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, mcp-session-id");
|
|
15
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
16
|
+
res.setHeader("Access-Control-Expose-Headers", "mcp-session-id");
|
|
17
|
+
if (req.method === "OPTIONS") {
|
|
18
|
+
res.writeHead(204);
|
|
19
|
+
res.end();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (req.url === "/health") {
|
|
23
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
24
|
+
res.end(JSON.stringify({ status: "ok" }));
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const parsedUrl = new URL(req.url || "/", `http://localhost:${port}`);
|
|
28
|
+
if (parsedUrl.pathname !== "/mcp") {
|
|
29
|
+
res.writeHead(404);
|
|
30
|
+
res.end("Not found. Use /mcp");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const apiKey = parsedUrl.searchParams.get("api_key");
|
|
34
|
+
if (!apiKey) {
|
|
35
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
36
|
+
res.end(JSON.stringify({ error: "Missing api_key query parameter" }));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
40
|
+
if (sessionId && sessions.has(sessionId)) {
|
|
41
|
+
const session = sessions.get(sessionId);
|
|
42
|
+
if (session.apiKey !== apiKey) {
|
|
43
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
44
|
+
res.end(JSON.stringify({ error: "This session belongs to a different api_key" }));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
await session.transport.handleRequest(req, res);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (req.method === "POST") {
|
|
51
|
+
const mcpServer = createServer(apiKey);
|
|
52
|
+
const transport = new StreamableHTTPServerTransport({
|
|
53
|
+
sessionIdGenerator: () => crypto.randomUUID(),
|
|
54
|
+
});
|
|
55
|
+
transport.onclose = () => {
|
|
56
|
+
const sid = transport.sessionId;
|
|
57
|
+
if (sid)
|
|
58
|
+
sessions.delete(sid);
|
|
59
|
+
};
|
|
60
|
+
await mcpServer.connect(transport);
|
|
61
|
+
await transport.handleRequest(req, res);
|
|
62
|
+
const sid = transport.sessionId;
|
|
63
|
+
if (sid) {
|
|
64
|
+
sessions.set(sid, { server: mcpServer, transport, apiKey });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
res.writeHead(405);
|
|
69
|
+
res.end("Method not allowed. Send POST to start a session");
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
httpServer.listen(Number(port), () => {
|
|
73
|
+
console.error(`Lighthouse MCP server running on http://0.0.0.0:${port}/mcp`);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const server = createServer();
|
|
78
|
+
const transport = new StdioServerTransport();
|
|
79
|
+
await server.connect(transport);
|
|
80
|
+
console.error("Lighthouse MCP server running on stdio");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
main().catch((error) => {
|
|
84
|
+
console.error("Fatal error:", error);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare function leanCompany(item: unknown): unknown;
|
|
2
|
+
export declare function leanPerson(item: unknown): unknown;
|
|
3
|
+
type DiscoveryType = "company" | "person";
|
|
4
|
+
export declare function leanItems(items: unknown, type: DiscoveryType): unknown;
|
|
5
|
+
export declare function leanDiscovery(res: {
|
|
6
|
+
status?: number;
|
|
7
|
+
data?: unknown;
|
|
8
|
+
error?: unknown;
|
|
9
|
+
meta?: unknown;
|
|
10
|
+
} | null | undefined, type: DiscoveryType | "auto"): typeof res;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const COMPANY_DROP = ["growth_metrics", "growth_metrics_v2", "workforce_data", "signals", "signals_v2"];
|
|
2
|
+
const PERSON_DROP = ["signals", "signals_v2"];
|
|
3
|
+
const COMPANY_ASSOCIATED_PEOPLE_CAP = 10;
|
|
4
|
+
const PERSON_ASSOCIATED_COMPANIES_CAP = 10;
|
|
5
|
+
const PERSON_EDUCATION_CAP = 8;
|
|
6
|
+
function isPlainObject(v) {
|
|
7
|
+
return v != null && typeof v === "object" && !Array.isArray(v);
|
|
8
|
+
}
|
|
9
|
+
function capArray(value, cap) {
|
|
10
|
+
return Array.isArray(value) ? value.slice(0, cap) : value;
|
|
11
|
+
}
|
|
12
|
+
export function leanCompany(item) {
|
|
13
|
+
if (!isPlainObject(item))
|
|
14
|
+
return item;
|
|
15
|
+
const lean = { ...item };
|
|
16
|
+
for (const key of COMPANY_DROP)
|
|
17
|
+
delete lean[key];
|
|
18
|
+
if ("associated_people" in lean) {
|
|
19
|
+
lean.associated_people = capArray(lean.associated_people, COMPANY_ASSOCIATED_PEOPLE_CAP);
|
|
20
|
+
}
|
|
21
|
+
return lean;
|
|
22
|
+
}
|
|
23
|
+
export function leanPerson(item) {
|
|
24
|
+
if (!isPlainObject(item))
|
|
25
|
+
return item;
|
|
26
|
+
const lean = { ...item };
|
|
27
|
+
for (const key of PERSON_DROP)
|
|
28
|
+
delete lean[key];
|
|
29
|
+
if ("associated_companies" in lean) {
|
|
30
|
+
lean.associated_companies = capArray(lean.associated_companies, PERSON_ASSOCIATED_COMPANIES_CAP);
|
|
31
|
+
}
|
|
32
|
+
if ("education" in lean) {
|
|
33
|
+
lean.education = capArray(lean.education, PERSON_EDUCATION_CAP);
|
|
34
|
+
}
|
|
35
|
+
return lean;
|
|
36
|
+
}
|
|
37
|
+
export function leanItems(items, type) {
|
|
38
|
+
if (!Array.isArray(items))
|
|
39
|
+
return items;
|
|
40
|
+
const project = type === "person" ? leanPerson : leanCompany;
|
|
41
|
+
return items.map((item) => project(item));
|
|
42
|
+
}
|
|
43
|
+
function inferType(item) {
|
|
44
|
+
if ("associated_companies" in item ||
|
|
45
|
+
"education" in item ||
|
|
46
|
+
"founder_score" in item ||
|
|
47
|
+
"first_name" in item ||
|
|
48
|
+
"last_name" in item) {
|
|
49
|
+
return "person";
|
|
50
|
+
}
|
|
51
|
+
return "company";
|
|
52
|
+
}
|
|
53
|
+
function leanOne(item, type) {
|
|
54
|
+
if (!isPlainObject(item))
|
|
55
|
+
return item;
|
|
56
|
+
const t = type ?? inferType(item);
|
|
57
|
+
return t === "person" ? leanPerson(item) : leanCompany(item);
|
|
58
|
+
}
|
|
59
|
+
export function leanDiscovery(res, type) {
|
|
60
|
+
if (!res || res.error)
|
|
61
|
+
return res;
|
|
62
|
+
const t = type === "auto" ? undefined : type;
|
|
63
|
+
const data = res.data;
|
|
64
|
+
if (Array.isArray(data)) {
|
|
65
|
+
return { ...res, data: data.map((item) => leanOne(item, t)) };
|
|
66
|
+
}
|
|
67
|
+
if (isPlainObject(data)) {
|
|
68
|
+
const next = { ...data };
|
|
69
|
+
let touched = false;
|
|
70
|
+
if (Array.isArray(next.items)) {
|
|
71
|
+
const itemType = next.type === "company" || next.type === "person" ? next.type : t;
|
|
72
|
+
next.items = next.items.map((item) => leanOne(item, itemType));
|
|
73
|
+
touched = true;
|
|
74
|
+
}
|
|
75
|
+
if (Array.isArray(next.results)) {
|
|
76
|
+
next.results = next.results.map((item) => leanOne(item, t));
|
|
77
|
+
touched = true;
|
|
78
|
+
}
|
|
79
|
+
if (Array.isArray(next.companies)) {
|
|
80
|
+
next.companies = next.companies.map((item) => leanOne(item, "company"));
|
|
81
|
+
touched = true;
|
|
82
|
+
}
|
|
83
|
+
if (Array.isArray(next.people)) {
|
|
84
|
+
next.people = next.people.map((item) => leanOne(item, "person"));
|
|
85
|
+
touched = true;
|
|
86
|
+
}
|
|
87
|
+
if (!touched) {
|
|
88
|
+
return { ...res, data: leanOne(data, t) };
|
|
89
|
+
}
|
|
90
|
+
return { ...res, data: next };
|
|
91
|
+
}
|
|
92
|
+
return res;
|
|
93
|
+
}
|