orangeslice 1.2.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,21 +1,53 @@
1
1
  # orangeslice
2
2
 
3
- Rate-limited B2B API client for AI agents. Call `orangeslice.b2b.sql()` anywhere, anytime - concurrency and rate limiting handled automatically.
3
+ Turn any AI agent into a B2B sales research assistant with access to **1B+ LinkedIn profiles**.
4
4
 
5
- ## Documentation
5
+ ```bash
6
+ npx orangeslice
7
+ ```
8
+
9
+ This copies documentation to `./orangeslice-docs/` and installs the package. Point your AI agent (Claude Code, Cursor, etc.) to `./orangeslice-docs/AGENTS.md` and it becomes your sales research agent.
10
+
11
+ ## What Your Agent Can Do
12
+
13
+ | Function | Capability |
14
+ |----------|------------|
15
+ | `b2b` | Query 1B+ LinkedIn profiles, companies, funding, jobs |
16
+ | `serp` | Google search for news, articles, reviews |
17
+ | `firecrawl` | Scrape websites, extract social URLs |
18
+
19
+ ## Quick Example
20
+
21
+ ```typescript
22
+ import { orangeslice } from 'orangeslice';
23
+
24
+ // B2B Database - Company + people research
25
+ const company = await orangeslice.b2b.sql(`
26
+ SELECT company_name, employee_count, description
27
+ FROM linkedin_company WHERE domain = 'stripe.com'
28
+ `);
6
29
 
7
- **Before writing queries, read the docs in [`./docs/`](./docs/):**
30
+ // Google Search - Find news and articles
31
+ const news = await orangeslice.serp.search("Stripe funding 2024");
32
+
33
+ // Website Scraping - Get page content + social links
34
+ const about = await orangeslice.firecrawl.scrape("https://stripe.com/about");
35
+ console.log(about.markdown); // Page as markdown
36
+ console.log(about.socialUrls); // LinkedIn, Twitter, etc.
37
+ ```
38
+
39
+ All calls are rate-limited automatically.
40
+
41
+ ## Documentation
8
42
 
9
43
  | Doc | What it covers |
10
44
  |-----|----------------|
11
- | [B2B_DATABASE.md](./docs/B2B_DATABASE.md) | Database overview, API endpoint, request format |
45
+ | [**AGENTS.md**](./docs/AGENTS.md) | **Start here** - Sales agent instructions |
46
+ | [B2B_DATABASE.md](./docs/B2B_DATABASE.md) | Database overview, query examples |
12
47
  | [B2B_SCHEMA.md](./docs/B2B_SCHEMA.md) | All tables and columns |
13
- | [B2B_EMPLOYEE_SEARCH.md](./docs/B2B_EMPLOYEE_SEARCH.md) | How to search for people/employees |
48
+ | [B2B_EMPLOYEE_SEARCH.md](./docs/B2B_EMPLOYEE_SEARCH.md) | Finding people by title/company |
14
49
  | [B2B_GENERALIZATION_RULES.md](./docs/B2B_GENERALIZATION_RULES.md) | Query patterns and best practices |
15
50
  | [B2B_NLP_QUERY_MAPPINGS.md](./docs/B2B_NLP_QUERY_MAPPINGS.md) | Natural language to SQL mappings |
16
- | [B2B_TABLE_INDICES.ts](./docs/B2B_TABLE_INDICES.ts) | TypeScript types for all tables |
17
-
18
- Start with `B2B_DATABASE.md` and `B2B_SCHEMA.md` to understand the data model.
19
51
 
20
52
  ## Installation
21
53
 
package/dist/b2b.js CHANGED
@@ -7,7 +7,7 @@ exports.query = query;
7
7
  const queue_1 = require("./queue");
8
8
  // Default config
9
9
  let config = {
10
- proxyUrl: process.env.B2B_SQL_PROXY_URL || "http://165.22.151.131:3000/query",
10
+ proxyUrl: process.env.ORANGESLICE_API_URL || "https://orangeslice.ai/api/function?functionId=b2b",
11
11
  concurrency: 2,
12
12
  minDelayMs: 100, // 100ms between requests = max 10/sec
13
13
  };
package/dist/cli.js CHANGED
@@ -63,18 +63,18 @@ async function main() {
63
63
  console.log(" (skipped - no package.json or npm not available)\n");
64
64
  }
65
65
  // 3. Show usage
66
- console.log("\n Done! Your AI agent can now:\n");
67
- console.log(" // Read docs in ./orangeslice-docs/ to understand the B2B schema");
68
- console.log(" // Then query with automatic rate limiting:");
69
- console.log("");
66
+ console.log("\n Done! Your AI agent is ready.\n");
67
+ console.log(" Point your AI agent (Claude, Cursor, etc.) to:\n");
68
+ console.log(" ./orangeslice-docs/AGENTS.md\n");
69
+ console.log(" This tells the agent how to act as your sales research assistant");
70
+ console.log(" with access to 1B+ LinkedIn profiles.\n");
71
+ console.log(" Example usage:\n");
70
72
  console.log(' import { orangeslice } from "orangeslice";');
71
73
  console.log("");
72
- console.log(" const companies = await orangeslice.b2b.sql(`");
73
- console.log(" SELECT company_name, employee_count");
74
+ console.log(" const company = await orangeslice.b2b.sql(`");
75
+ console.log(" SELECT company_name, employee_count, description");
74
76
  console.log(" FROM linkedin_company");
75
77
  console.log(" WHERE domain = 'stripe.com'");
76
- console.log(" `);");
77
- console.log("");
78
- console.log(" Start by reading: ./orangeslice-docs/B2B_DATABASE.md\n");
78
+ console.log(" `);\n");
79
79
  }
80
80
  main().catch(console.error);
@@ -0,0 +1,49 @@
1
+ export interface SocialUrls {
2
+ emailGeneral: string[];
3
+ facebookProfile: string[];
4
+ instagramProfile: string[];
5
+ twitterUser: string[];
6
+ youtubeChannel: string[];
7
+ youtubeVideo: string[];
8
+ tiktokProfile: string[];
9
+ linkedinProfile: string[];
10
+ linkedinCompany: string[];
11
+ }
12
+ export interface PageData {
13
+ markdown: string;
14
+ links: string[];
15
+ }
16
+ export interface FirecrawlResponse {
17
+ markdown: string;
18
+ data: PageData[];
19
+ socialUrls: SocialUrls;
20
+ error?: string;
21
+ }
22
+ /**
23
+ * Scrape a website and get markdown content.
24
+ * Automatically rate-limited.
25
+ *
26
+ * @param url - URL to scrape
27
+ * @param limit - Number of pages to crawl (default 1 for single page scrape)
28
+ *
29
+ * @example
30
+ * // Single page scrape
31
+ * const page = await firecrawl.scrape("https://stripe.com/about");
32
+ *
33
+ * // Multi-page crawl
34
+ * const site = await firecrawl.scrape("https://stripe.com", 5);
35
+ */
36
+ export declare function scrape(url: string, limit?: number): Promise<FirecrawlResponse>;
37
+ /**
38
+ * Scrape a website and return just the markdown content
39
+ */
40
+ export declare function markdown(url: string): Promise<string>;
41
+ /**
42
+ * Scrape a website and extract social URLs
43
+ */
44
+ export declare function socials(url: string): Promise<SocialUrls>;
45
+ export declare const firecrawl: {
46
+ scrape: typeof scrape;
47
+ markdown: typeof markdown;
48
+ socials: typeof socials;
49
+ };
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.firecrawl = void 0;
4
+ exports.scrape = scrape;
5
+ exports.markdown = markdown;
6
+ exports.socials = socials;
7
+ const queue_1 = require("./queue");
8
+ const API_URL = process.env.ORANGESLICE_API_URL || "https://orangeslice.ai/api/function?functionId=firecrawl";
9
+ // Shared queue for all Firecrawl requests
10
+ const queue = (0, queue_1.createQueue)(2);
11
+ const rateLimiter = (0, queue_1.createRateLimiter)(500); // 500ms between requests (crawls are expensive)
12
+ /**
13
+ * Scrape a website and get markdown content.
14
+ * Automatically rate-limited.
15
+ *
16
+ * @param url - URL to scrape
17
+ * @param limit - Number of pages to crawl (default 1 for single page scrape)
18
+ *
19
+ * @example
20
+ * // Single page scrape
21
+ * const page = await firecrawl.scrape("https://stripe.com/about");
22
+ *
23
+ * // Multi-page crawl
24
+ * const site = await firecrawl.scrape("https://stripe.com", 5);
25
+ */
26
+ async function scrape(url, limit = 1) {
27
+ return queue(async () => {
28
+ return rateLimiter(async () => {
29
+ const response = await fetch(API_URL, {
30
+ method: "POST",
31
+ headers: { "Content-Type": "application/json" },
32
+ body: JSON.stringify({ url, limit }),
33
+ });
34
+ if (!response.ok) {
35
+ throw new Error(`Firecrawl request failed: ${response.status} ${response.statusText}`);
36
+ }
37
+ const data = (await response.json());
38
+ if (data.error) {
39
+ throw new Error(`Firecrawl error: ${data.error}`);
40
+ }
41
+ return data;
42
+ });
43
+ });
44
+ }
45
+ /**
46
+ * Scrape a website and return just the markdown content
47
+ */
48
+ async function markdown(url) {
49
+ const data = await scrape(url, 1);
50
+ return data.markdown;
51
+ }
52
+ /**
53
+ * Scrape a website and extract social URLs
54
+ */
55
+ async function socials(url) {
56
+ const data = await scrape(url, 1);
57
+ return data.socialUrls;
58
+ }
59
+ // Export as namespace
60
+ exports.firecrawl = {
61
+ scrape,
62
+ markdown,
63
+ socials,
64
+ };
package/dist/index.d.ts CHANGED
@@ -1,23 +1,23 @@
1
1
  import { b2b } from "./b2b";
2
- export { b2b };
2
+ import { serp } from "./serp";
3
+ import { firecrawl } from "./firecrawl";
4
+ export { b2b, serp, firecrawl };
3
5
  /**
4
- * Main orangeslice namespace
6
+ * Main orangeslice namespace - AI sales agent toolkit
5
7
  *
6
8
  * @example
7
9
  * import { orangeslice } from 'orangeslice';
8
10
  *
9
- * // Configure (optional)
10
- * orangeslice.b2b.configure({ concurrency: 3 });
11
- *
12
- * // Query - automatically rate-limited
11
+ * // B2B Database - 1B+ LinkedIn profiles
13
12
  * const companies = await orangeslice.b2b.sql("SELECT * FROM linkedin_company WHERE domain = 'stripe.com'");
14
13
  *
15
- * // Multiple parallel calls are queued automatically
16
- * const results = await Promise.all([
17
- * orangeslice.b2b.sql("SELECT * FROM linkedin_company WHERE universal_name = 'stripe'"),
18
- * orangeslice.b2b.sql("SELECT * FROM linkedin_company WHERE universal_name = 'openai'"),
19
- * orangeslice.b2b.sql("SELECT * FROM linkedin_company WHERE universal_name = 'meta'"),
20
- * ]);
14
+ * // Google Search
15
+ * const results = await orangeslice.serp.search("best CRM software 2024");
16
+ *
17
+ * // Website Scraping
18
+ * const page = await orangeslice.firecrawl.scrape("https://stripe.com/about");
19
+ *
20
+ * // All calls are automatically rate-limited and queued
21
21
  */
22
22
  export declare const orangeslice: {
23
23
  b2b: {
@@ -25,5 +25,14 @@ export declare const orangeslice: {
25
25
  query: typeof import("./b2b").query;
26
26
  configure: typeof import("./b2b").configure;
27
27
  };
28
+ serp: {
29
+ search: typeof import("./serp").search;
30
+ organic: typeof import("./serp").organic;
31
+ };
32
+ firecrawl: {
33
+ scrape: typeof import("./firecrawl").scrape;
34
+ markdown: typeof import("./firecrawl").markdown;
35
+ socials: typeof import("./firecrawl").socials;
36
+ };
28
37
  };
29
38
  export default orangeslice;
package/dist/index.js CHANGED
@@ -1,28 +1,32 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.orangeslice = exports.b2b = void 0;
3
+ exports.orangeslice = exports.firecrawl = exports.serp = exports.b2b = void 0;
4
4
  const b2b_1 = require("./b2b");
5
5
  Object.defineProperty(exports, "b2b", { enumerable: true, get: function () { return b2b_1.b2b; } });
6
+ const serp_1 = require("./serp");
7
+ Object.defineProperty(exports, "serp", { enumerable: true, get: function () { return serp_1.serp; } });
8
+ const firecrawl_1 = require("./firecrawl");
9
+ Object.defineProperty(exports, "firecrawl", { enumerable: true, get: function () { return firecrawl_1.firecrawl; } });
6
10
  /**
7
- * Main orangeslice namespace
11
+ * Main orangeslice namespace - AI sales agent toolkit
8
12
  *
9
13
  * @example
10
14
  * import { orangeslice } from 'orangeslice';
11
15
  *
12
- * // Configure (optional)
13
- * orangeslice.b2b.configure({ concurrency: 3 });
14
- *
15
- * // Query - automatically rate-limited
16
+ * // B2B Database - 1B+ LinkedIn profiles
16
17
  * const companies = await orangeslice.b2b.sql("SELECT * FROM linkedin_company WHERE domain = 'stripe.com'");
17
18
  *
18
- * // Multiple parallel calls are queued automatically
19
- * const results = await Promise.all([
20
- * orangeslice.b2b.sql("SELECT * FROM linkedin_company WHERE universal_name = 'stripe'"),
21
- * orangeslice.b2b.sql("SELECT * FROM linkedin_company WHERE universal_name = 'openai'"),
22
- * orangeslice.b2b.sql("SELECT * FROM linkedin_company WHERE universal_name = 'meta'"),
23
- * ]);
19
+ * // Google Search
20
+ * const results = await orangeslice.serp.search("best CRM software 2024");
21
+ *
22
+ * // Website Scraping
23
+ * const page = await orangeslice.firecrawl.scrape("https://stripe.com/about");
24
+ *
25
+ * // All calls are automatically rate-limited and queued
24
26
  */
25
27
  exports.orangeslice = {
26
28
  b2b: b2b_1.b2b,
29
+ serp: serp_1.serp,
30
+ firecrawl: firecrawl_1.firecrawl,
27
31
  };
28
32
  exports.default = exports.orangeslice;
package/dist/serp.d.ts ADDED
@@ -0,0 +1,41 @@
1
+ export interface SerpResult {
2
+ title: string;
3
+ link: string;
4
+ snippet: string;
5
+ position?: number;
6
+ }
7
+ export interface SerpResponse {
8
+ organic_results?: SerpResult[];
9
+ related_questions?: Array<{
10
+ question: string;
11
+ snippet: string;
12
+ }>;
13
+ error?: string;
14
+ }
15
+ export interface SerpOptions {
16
+ /** Regex pattern to filter links */
17
+ linkRegexPattern?: string;
18
+ /** Enable advanced search features */
19
+ advance_search?: boolean;
20
+ /** Page number (default 1) */
21
+ page?: number;
22
+ /** Time-based search filter (e.g., "qdr:d" for past day, "qdr:w" for past week) */
23
+ tbs?: string;
24
+ }
25
+ /**
26
+ * Search Google via SERP API.
27
+ * Automatically rate-limited.
28
+ *
29
+ * @example
30
+ * const results = await serp.search("best CRM software 2024");
31
+ * const filtered = await serp.search("site:linkedin.com CEO stripe", { linkRegexPattern: "linkedin.com/in/" });
32
+ */
33
+ export declare function search(query: string, options?: SerpOptions): Promise<SerpResponse>;
34
+ /**
35
+ * Search and return just the organic results
36
+ */
37
+ export declare function organic(query: string, options?: SerpOptions): Promise<SerpResult[]>;
38
+ export declare const serp: {
39
+ search: typeof search;
40
+ organic: typeof organic;
41
+ };
package/dist/serp.js ADDED
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serp = void 0;
4
+ exports.search = search;
5
+ exports.organic = organic;
6
+ const queue_1 = require("./queue");
7
+ const API_URL = process.env.ORANGESLICE_API_URL || "https://orangeslice.ai/api/function?functionId=serp";
8
+ // Shared queue for all SERP requests
9
+ const queue = (0, queue_1.createQueue)(2);
10
+ const rateLimiter = (0, queue_1.createRateLimiter)(200); // 200ms between requests
11
+ /**
12
+ * Search Google via SERP API.
13
+ * Automatically rate-limited.
14
+ *
15
+ * @example
16
+ * const results = await serp.search("best CRM software 2024");
17
+ * const filtered = await serp.search("site:linkedin.com CEO stripe", { linkRegexPattern: "linkedin.com/in/" });
18
+ */
19
+ async function search(query, options = {}) {
20
+ return queue(async () => {
21
+ return rateLimiter(async () => {
22
+ const response = await fetch(API_URL, {
23
+ method: "POST",
24
+ headers: { "Content-Type": "application/json" },
25
+ body: JSON.stringify({
26
+ query,
27
+ ...options,
28
+ }),
29
+ });
30
+ if (!response.ok) {
31
+ throw new Error(`SERP request failed: ${response.status} ${response.statusText}`);
32
+ }
33
+ const data = (await response.json());
34
+ if (data.error) {
35
+ throw new Error(`SERP error: ${data.error}`);
36
+ }
37
+ return data;
38
+ });
39
+ });
40
+ }
41
+ /**
42
+ * Search and return just the organic results
43
+ */
44
+ async function organic(query, options = {}) {
45
+ const data = await search(query, options);
46
+ return data.organic_results || [];
47
+ }
48
+ // Export as namespace
49
+ exports.serp = {
50
+ search,
51
+ organic,
52
+ };
package/docs/AGENTS.md ADDED
@@ -0,0 +1,319 @@
1
+ # Sales Agent
2
+
3
+ You are a B2B sales research agent with access to:
4
+ - **1.15 billion LinkedIn profiles** and millions of companies
5
+ - **Google Search** (SERP API)
6
+ - **Website scraping** (Firecrawl)
7
+
8
+ ## What You Can Do
9
+
10
+ | Capability | Tool | Example |
11
+ |------------|------|---------|
12
+ | **Company research** | `b2b` | Look up any company by domain, name, or LinkedIn URL |
13
+ | **Find decision makers** | `b2b` | Find C-suite, VPs, Directors at target companies |
14
+ | **Employee lookup** | `b2b` | Search employees by title, role, or department |
15
+ | **Funding intelligence** | `b2b` | Find recently funded companies and their investors |
16
+ | **Google search** | `serp` | Search for company news, press releases, reviews |
17
+ | **Website scraping** | `firecrawl` | Extract content from company websites |
18
+
19
+
20
+ ## Quick Start
21
+
22
+ ```typescript
23
+ import { orangeslice } from 'orangeslice';
24
+
25
+ // 1. B2B Database - Company & people research
26
+ const company = await orangeslice.b2b.sql(`
27
+ SELECT company_name, domain, employee_count, description
28
+ FROM linkedin_company WHERE domain = 'stripe.com'
29
+ `);
30
+
31
+ // 2. Google Search - Find news, articles, reviews
32
+ const news = await orangeslice.serp.search("Stripe funding 2024");
33
+
34
+ // 3. Website Scraping - Get company page content
35
+ const about = await orangeslice.firecrawl.scrape("https://stripe.com/about");
36
+ ```
37
+
38
+ All calls are automatically rate-limited. Fire away freely.
39
+
40
+ ## Sales Workflows
41
+
42
+ ### 1. Research a Target Account
43
+
44
+ ```sql
45
+ -- Step 1: Get company details
46
+ SELECT id, company_name, domain, employee_count, locality, description
47
+ FROM linkedin_company
48
+ WHERE domain = 'openai.com';
49
+
50
+ -- Step 2: Find their leadership team
51
+ SELECT lp.first_name, lp.last_name, lp.headline, pos.title, lp.public_profile_url
52
+ FROM linkedin_profile lp
53
+ JOIN linkedin_profile_position3 pos ON pos.linkedin_profile_id = lp.id
54
+ WHERE pos.linkedin_company_id = 11130470 -- OpenAI's ID from step 1
55
+ AND pos.end_date IS NULL
56
+ AND (pos.title ILIKE 'ceo%' OR pos.title ILIKE 'cto%' OR pos.title ILIKE 'cfo%'
57
+ OR pos.title ILIKE '%vp%' OR pos.title ILIKE '%head of%')
58
+ LIMIT 30;
59
+ ```
60
+
61
+ ### 2. Find Your Ideal Customer Profile (ICP)
62
+
63
+ ```sql
64
+ -- Software companies, 100-500 employees, with recent funding
65
+ SELECT lc.company_name, lc.domain, lc.employee_count,
66
+ cf.round_name, cf.round_date, cf.round_amount
67
+ FROM linkedin_company lc
68
+ JOIN linkedin_crunchbase_funding cf ON cf.linkedin_company_id = lc.id
69
+ WHERE lc.industry_code = 4 -- Software Development
70
+ AND lc.employee_count BETWEEN 100 AND 500
71
+ AND cf.round_date >= '2024-01-01'
72
+ ORDER BY cf.round_date DESC
73
+ LIMIT 50;
74
+ ```
75
+
76
+ ### 3. Find Specific Personas
77
+
78
+ ```sql
79
+ -- Heads of Sales at mid-market companies
80
+ SELECT lp.first_name, lp.last_name, lp.headline,
81
+ pos.title, lc.company_name, lc.employee_count
82
+ FROM linkedin_profile lp
83
+ JOIN linkedin_profile_position3 pos ON pos.linkedin_profile_id = lp.id
84
+ JOIN linkedin_company lc ON lc.id = pos.linkedin_company_id
85
+ WHERE pos.end_date IS NULL
86
+ AND lc.employee_count BETWEEN 100 AND 1000
87
+ AND (pos.title ILIKE '%head of sales%'
88
+ OR pos.title ILIKE '%vp sales%'
89
+ OR pos.title ILIKE '%chief revenue%')
90
+ LIMIT 30;
91
+ ```
92
+
93
+ ### 4. Competitive Intelligence
94
+
95
+ ```sql
96
+ -- Who works at competitor company?
97
+ SELECT lp.first_name, lp.last_name, lp.headline, pos.title
98
+ FROM linkedin_profile lp
99
+ JOIN linkedin_profile_position3 pos ON pos.linkedin_profile_id = lp.id
100
+ WHERE pos.linkedin_company_id = 2135371 -- Competitor's ID
101
+ AND pos.end_date IS NULL
102
+ AND pos.title ILIKE '%sales%'
103
+ LIMIT 50;
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Google Search (SERP)
109
+
110
+ Search the web for company news, press releases, reviews, and more.
111
+
112
+ ```typescript
113
+ // Basic search
114
+ const results = await orangeslice.serp.search("Stripe Series C funding");
115
+
116
+ // Get just organic results
117
+ const organic = await orangeslice.serp.organic("best CRM software 2024");
118
+
119
+ // Filter by site
120
+ const linkedin = await orangeslice.serp.search("site:linkedin.com/in CEO Ramp");
121
+
122
+ // Time-based search (past week)
123
+ const recent = await orangeslice.serp.search("OpenAI news", { tbs: "qdr:w" });
124
+ ```
125
+
126
+ ### SERP Options
127
+
128
+ | Option | Type | Description |
129
+ |--------|------|-------------|
130
+ | `linkRegexPattern` | string | Filter results by URL pattern |
131
+ | `advance_search` | boolean | Enable advanced search features |
132
+ | `page` | number | Page number (default 1) |
133
+ | `tbs` | string | Time filter: `qdr:d` (day), `qdr:w` (week), `qdr:m` (month) |
134
+
135
+ ### Use Cases
136
+
137
+ - Find company news and press releases
138
+ - Research competitors' public announcements
139
+ - Find LinkedIn profiles via Google
140
+ - Check company reviews on G2, Capterra, etc.
141
+
142
+ ---
143
+
144
+ ## Website Scraping (Firecrawl)
145
+
146
+ Scrape any website and get markdown content + extracted social URLs.
147
+
148
+ ```typescript
149
+ // Scrape a single page
150
+ const page = await orangeslice.firecrawl.scrape("https://stripe.com/about");
151
+ console.log(page.markdown); // Page content as markdown
152
+ console.log(page.socialUrls); // Extracted social links
153
+
154
+ // Just get markdown
155
+ const content = await orangeslice.firecrawl.markdown("https://company.com/team");
156
+
157
+ // Just get social URLs
158
+ const socials = await orangeslice.firecrawl.socials("https://company.com");
159
+ // Returns: { linkedinCompany: [...], twitterUser: [...], ... }
160
+
161
+ // Multi-page crawl (up to 5 pages)
162
+ const site = await orangeslice.firecrawl.scrape("https://company.com", 5);
163
+ ```
164
+
165
+ ### Social URLs Extracted
166
+
167
+ | Field | Description |
168
+ |-------|-------------|
169
+ | `linkedinCompany` | Company LinkedIn pages |
170
+ | `linkedinProfile` | Individual LinkedIn profiles |
171
+ | `twitterUser` | Twitter/X profiles |
172
+ | `facebookProfile` | Facebook pages |
173
+ | `instagramProfile` | Instagram profiles |
174
+ | `youtubeChannel` | YouTube channels |
175
+ | `tiktokProfile` | TikTok profiles |
176
+ | `emailGeneral` | Email addresses |
177
+
178
+ ### Use Cases
179
+
180
+ - Scrape company "About" or "Team" pages
181
+ - Find social media links from company websites
182
+ - Extract contact emails from websites
183
+ - Get company descriptions from their own sites
184
+
185
+ ---
186
+
187
+ ## Key Tables
188
+
189
+ | Table | Records | Use For |
190
+ |-------|---------|---------|
191
+ | `linkedin_company` | Millions | Company lookup, enrichment |
192
+ | `linkedin_profile` | 1.15B | Profile details |
193
+ | `linkedin_profile_position3` | 2.6B | Job history, current employer |
194
+ | `linkedin_crunchbase_funding` | - | Funding rounds |
195
+ | `linkedin_job` | 1.48B | Job postings |
196
+
197
+ ## Performance Rules
198
+
199
+ ### ✅ Fast Queries (use these)
200
+ ```sql
201
+ -- By domain (indexed)
202
+ WHERE domain = 'stripe.com'
203
+
204
+ -- By universal_name (indexed)
205
+ WHERE universal_name = 'stripe'
206
+
207
+ -- By company ID (indexed)
208
+ WHERE linkedin_company_id = 2135371
209
+
210
+ -- By profile ID (indexed)
211
+ WHERE linkedin_profile_id = 12345
212
+ ```
213
+
214
+ ### ⚠️ Slow Queries (avoid these)
215
+ ```sql
216
+ -- Text search on names (no index)
217
+ WHERE company_name ILIKE '%stripe%' -- SLOW
218
+
219
+ -- Headline search (full scan)
220
+ WHERE headline ILIKE '%sales%' -- SLOW
221
+
222
+ -- COUNT on huge companies
223
+ SELECT COUNT(*) FROM ... WHERE linkedin_company_id = 1586 -- TIMEOUT
224
+ ```
225
+
226
+ ### Company Size Matters
227
+
228
+ | Company Size | Simple Query | Aggregations |
229
+ |-------------|--------------|--------------|
230
+ | Small (<1K) | 4-20ms | 5-50ms |
231
+ | Medium (1K-10K) | 10-30ms | 100-500ms |
232
+ | Large (10K-100K) | 10-40ms | 1-15s |
233
+ | Massive (100K+) | 15-65ms | **TIMEOUT** |
234
+
235
+ **For Amazon/Google (100K+ employees):** Only use simple `LIMIT` queries, no `COUNT` or `GROUP BY`.
236
+
237
+ ## Common Company IDs
238
+
239
+ | Company | ID | Employees |
240
+ |---------|-----|-----------|
241
+ | Amazon | 1586 | 770K |
242
+ | Google | 1441 | 330K |
243
+ | Stripe | 2135371 | ~9K |
244
+ | OpenAI | 11130470 | ~7K |
245
+ | Ramp | 1406226 | ~3.5K |
246
+
247
+ ## Title Search Patterns
248
+
249
+ | Role | ILIKE Pattern |
250
+ |------|---------------|
251
+ | C-Suite | `ceo%`, `cto%`, `cfo%`, `%chief%` |
252
+ | VPs | `%vp %`, `%vice president%` |
253
+ | Directors | `%director%`, `%head of%` |
254
+ | Sales | `%account exec%`, `%sales rep%`, `%ae %` |
255
+ | SDRs | `%sales development%`, `%sdr%`, `%bdr%` |
256
+ | Engineering | `%engineer%`, `%developer%` |
257
+ | Recruiters | `%recruit%`, `%talent%`, `%sourcer%` |
258
+
259
+ ## What You Cannot Do
260
+
261
+ ❌ **No direct contact data** - email addresses and phone numbers are restricted
262
+ ❌ **No Indeed data** - Indeed tables are restricted
263
+ ❌ **No traffic/web data** - Domain traffic and web analytics restricted
264
+
265
+ ## Rate Limits
266
+
267
+ The `orangeslice` package automatically handles rate limiting:
268
+
269
+ | Function | Concurrency | Min Delay |
270
+ |----------|-------------|-----------|
271
+ | `b2b` | 2 concurrent | 100ms |
272
+ | `serp` | 2 concurrent | 200ms |
273
+ | `firecrawl` | 2 concurrent | 500ms |
274
+
275
+ You can fire off many calls - they'll be queued automatically.
276
+
277
+ ## Detailed Documentation
278
+
279
+ For comprehensive schema and query patterns, see:
280
+ - `B2B_DATABASE.md` - Full database guide with examples
281
+ - `B2B_SCHEMA.md` - Complete table schemas
282
+ - `B2B_EMPLOYEE_SEARCH.md` - Finding employees by title
283
+
284
+ ## Example Session
285
+
286
+ **User:** "Research Ramp - give me everything"
287
+
288
+ **Agent:**
289
+ ```typescript
290
+ import { orangeslice } from 'orangeslice';
291
+
292
+ // 1. B2B Database - Company info + leadership
293
+ const company = await orangeslice.b2b.sql(`
294
+ SELECT id, company_name, domain, employee_count, locality, description
295
+ FROM linkedin_company WHERE domain = 'ramp.com'
296
+ `);
297
+
298
+ const leadership = await orangeslice.b2b.sql(`
299
+ SELECT lp.first_name, lp.last_name, lp.headline, pos.title
300
+ FROM linkedin_profile lp
301
+ JOIN linkedin_profile_position3 pos ON pos.linkedin_profile_id = lp.id
302
+ WHERE pos.linkedin_company_id = 1406226
303
+ AND pos.end_date IS NULL
304
+ AND (pos.title ILIKE 'ceo%' OR pos.title ILIKE 'cto%' OR pos.title ILIKE '%vp%')
305
+ LIMIT 20
306
+ `);
307
+
308
+ // 2. Google Search - Recent news
309
+ const news = await orangeslice.serp.search("Ramp fintech funding 2024", { tbs: "qdr:m" });
310
+
311
+ // 3. Website Scraping - About page + socials
312
+ const about = await orangeslice.firecrawl.scrape("https://ramp.com/about");
313
+ console.log(about.markdown); // Company description
314
+ console.log(about.socialUrls); // LinkedIn, Twitter, etc.
315
+ ```
316
+
317
+ ---
318
+
319
+ **Start by understanding what the user wants to research, then use the appropriate tools to find the information.**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "orangeslice",
3
- "version": "1.2.0",
4
- "description": "Rate-limited B2B API client for AI agents",
3
+ "version": "1.4.0",
4
+ "description": "Turn any AI agent into a B2B sales research assistant with 1B+ LinkedIn profiles",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "bin": {
@@ -21,7 +21,11 @@
21
21
  "b2b",
22
22
  "rate-limit",
23
23
  "ai-agent",
24
- "linkedin"
24
+ "linkedin",
25
+ "sales-agent",
26
+ "claude-code",
27
+ "cursor",
28
+ "mcp"
25
29
  ],
26
30
  "author": "",
27
31
  "license": "MIT",