orangeslice 2.1.4 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +3 -1
  2. package/dist/careers.d.ts +47 -0
  3. package/dist/careers.js +11 -0
  4. package/dist/cli.js +0 -0
  5. package/dist/expansion.js +21 -10
  6. package/dist/index.d.ts +14 -0
  7. package/dist/index.js +20 -2
  8. package/dist/ocean.d.ts +166 -0
  9. package/dist/ocean.js +23 -0
  10. package/docs/data-enrichement/index.md +10 -2
  11. package/docs/integrations/gmail/createDraft.md +54 -0
  12. package/docs/integrations/gmail/fetchEmails.md +50 -0
  13. package/docs/integrations/gmail/fetchMessageByMessageId.md +36 -0
  14. package/docs/integrations/gmail/fetchMessageByThreadId.md +37 -0
  15. package/docs/integrations/gmail/getProfile.md +37 -0
  16. package/docs/integrations/gmail/index.md +19 -2
  17. package/docs/integrations/gmail/listLabels.md +34 -0
  18. package/docs/integrations/gmail/replyToThread.md +51 -0
  19. package/docs/integrations/hubspot/createWebhookFlow.md +137 -0
  20. package/docs/integrations/hubspot/index.md +8 -2
  21. package/docs/integrations/hubspot/updateFlow.md +13 -14
  22. package/docs/integrations/hubspot/updateWebhookFlow.md +52 -0
  23. package/docs/integrations/index.md +64 -2
  24. package/docs/integrations/salesforce/index.md +4 -0
  25. package/docs/integrations/salesforce/request.md +58 -0
  26. package/docs/services/ai/generateObject.ts +7 -3
  27. package/docs/services/ai/generateText.ts +7 -3
  28. package/docs/services/builtWith/index.md +2 -2
  29. package/docs/services/company/findCareersPage.md +137 -0
  30. package/docs/services/company/findCareersPage.ts +37 -0
  31. package/docs/services/company/linkedin/enrich.md +47 -2
  32. package/docs/services/company/scrapeCareersPage.md +150 -0
  33. package/docs/services/index.md +1 -1
  34. package/docs/services/person/linkedin/findUrl.md +2 -2
  35. package/docs/services/web/search.md +29 -14
  36. package/docs/triggers-runtime.md +26 -5
  37. package/package.json +1 -1
package/README.md CHANGED
@@ -90,8 +90,10 @@ const startups = await services.crunchbase.search({
90
90
  ## Service map
91
91
 
92
92
  - `services.company.linkedin.search/enrich`
93
+ - `services.company.findCareersPage/scrapeCareersPage`
93
94
  - `services.crunchbase.search` (returns rows array directly)
94
95
  - `services.company.getEmployeesFromLinkedin` (database-only B2B path)
96
+ - `services.ocean.search.companies/people`
95
97
  - `services.person.linkedin.search/enrich`
96
98
  - `services.web.search/batchSearch`
97
99
  - `services.ai.generateObject`
@@ -106,7 +108,7 @@ const startups = await services.crunchbase.search({
106
108
 
107
109
  All service calls go through `post()` in `src/api.ts`.
108
110
 
109
- - Submit path: `https://enrichly-production.up.railway.app/function`
111
+ - Execute paths: `https://enrichly-production.up.railway.app/execute/*` and `https://enrichly-production.up.railway.app/ctx/*`
110
112
  - Pending responses (`pending: true` / `202`) poll batch-service result endpoints.
111
113
  - Polling timeout supports long-running workflows (up to 10 minutes).
112
114
  - This package now exposes only batch-backed services.
@@ -0,0 +1,47 @@
1
+ export interface FindCareersPageParams {
2
+ website?: string;
3
+ url?: string;
4
+ }
5
+ export interface FindCareersPageResult {
6
+ inputUrl: string;
7
+ normalizedWebsiteUrl: string;
8
+ careerPageUrl: string | null;
9
+ pageType: "ats" | "official" | "not_found";
10
+ atsProvider: string | null;
11
+ detectionMethod: "input-ats" | "homepage-ats-link" | "homepage-careers-link" | "deterministic-candidate" | "candidate-ats-link" | "embedded-ats" | "candidate-redirect" | "ats-unverified" | "not-found";
12
+ checkedUrls: string[];
13
+ }
14
+ export interface ScrapeCareersPageParams {
15
+ careersPageUrl?: string;
16
+ url?: string;
17
+ }
18
+ export interface ScrapeCareersPageJob {
19
+ id: string;
20
+ title: string;
21
+ url: string;
22
+ applyUrl: string | null;
23
+ location: string | null;
24
+ locations: string[];
25
+ department: string | null;
26
+ team: string | null;
27
+ employmentType: string | null;
28
+ workplaceType: string | null;
29
+ postedAt: string | null;
30
+ postedText: string | null;
31
+ requisitionId: string | null;
32
+ }
33
+ export interface ScrapeCareersPageResult {
34
+ status: "success" | "unsupported_url" | "unsupported_provider";
35
+ inputUrl: string;
36
+ normalizedBoardUrl: string | null;
37
+ atsProvider: string | null;
38
+ companyName: string | null;
39
+ source: "api" | "html" | null;
40
+ totalJobs: number;
41
+ jobs: ScrapeCareersPageJob[];
42
+ checkedUrls: string[];
43
+ supportedProviders: string[];
44
+ message: string | null;
45
+ }
46
+ export declare function findCareersPage(params: FindCareersPageParams): Promise<FindCareersPageResult>;
47
+ export declare function scrapeCareersPage(params: ScrapeCareersPageParams): Promise<ScrapeCareersPageResult>;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.findCareersPage = findCareersPage;
4
+ exports.scrapeCareersPage = scrapeCareersPage;
5
+ const api_1 = require("./api");
6
+ async function findCareersPage(params) {
7
+ return (0, api_1.post)("/execute/find-careers-page", { ...params });
8
+ }
9
+ async function scrapeCareersPage(params) {
10
+ return (0, api_1.post)("/execute/scrape-careers-page", { ...params });
11
+ }
package/dist/cli.js CHANGED
File without changes
package/dist/expansion.js CHANGED
@@ -71,17 +71,28 @@ async function companyLinkedinEnrich(params) {
71
71
  if (!shorthand && !url && !domain) {
72
72
  throw new Error("[orangeslice] company.linkedin.enrich: provide shorthand, url, or domain");
73
73
  }
74
- const where = [];
75
- if (shorthand)
76
- where.push(`slug = ${sqlString(shorthand)}`);
77
- if (url)
78
- where.push(`linkedin_url = ${sqlString(url)}`);
79
- if (domain)
80
- where.push(`lower(website) LIKE ${sqlString(`%${domain}%`)}`);
81
74
  const fields = extended
82
- ? "*"
83
- : "name, slug, website, description, employee_count, follower_count, founded_year, locality, region, country_iso, country_name, type, size, ticker, specialties, linkedin_url, created_at, updated_at";
84
- const sql = `SELECT ${fields} FROM lkd_company WHERE ${where.join(" OR ")} LIMIT 1`;
75
+ ? "lkd.*"
76
+ : "lkd.name, lkd.slug, lkd.website, lkd.description, lkd.employee_count, lkd.follower_count, lkd.founded_year, lkd.locality, lkd.region, lkd.country_iso, lkd.country_name, lkd.type, lkd.size, lkd.ticker, lkd.specialties, lkd.linkedin_url, lkd.created_at, lkd.updated_at";
77
+ let sql;
78
+ if (domain) {
79
+ const bare = domain.replace(/^www\./, "");
80
+ sql = `SELECT ${fields}
81
+ FROM linkedin_company lc
82
+ JOIN lkd_company lkd ON lkd.linkedin_company_id = lc.id
83
+ WHERE lc.domain IN (${sqlString(bare)}, ${sqlString("www." + bare)})
84
+ ORDER BY CASE WHEN lc.website ~ ${sqlString("^https?://(www\\.)?" + bare.replace(/\./g, "\\.") + "(/([a-z]{2}(-[a-z]{2})?)?)?(\\?.*)?/?$")} THEN 0 ELSE 1 END,
85
+ lc.employee_count DESC NULLS LAST
86
+ LIMIT 1`;
87
+ }
88
+ else {
89
+ const where = [];
90
+ if (shorthand)
91
+ where.push(`lkd.slug = ${sqlString(shorthand)}`);
92
+ if (url)
93
+ where.push(`lkd.linkedin_url = ${sqlString(url)}`);
94
+ sql = `SELECT ${fields} FROM lkd_company lkd WHERE ${where.join(" OR ")} LIMIT 1`;
95
+ }
85
96
  const data = await (0, api_1.post)("/execute/sql", { sql });
86
97
  return data.rows?.[0] ?? null;
87
98
  }
package/dist/index.d.ts CHANGED
@@ -1,11 +1,15 @@
1
1
  export { configure } from "./api";
2
2
  export type { OrangesliceConfig } from "./api";
3
+ export { findCareersPage, scrapeCareersPage } from "./careers";
4
+ export type { FindCareersPageParams, FindCareersPageResult, ScrapeCareersPageParams, ScrapeCareersPageResult, ScrapeCareersPageJob } from "./careers";
3
5
  export { ctx } from "./ctx";
4
6
  export type { Spreadsheet, SpreadsheetListItem, SqlResult, SqlQueryResult, SqlActionResult, RowsAddResult } from "./ctx";
5
7
  export { linkedinSearch } from "./b2b";
6
8
  export type { LinkedInSearchParams, LinkedInSearchResponse } from "./b2b";
7
9
  export { crunchbaseSearch } from "./crunchbase";
8
10
  export type { CrunchbaseSearchParams } from "./crunchbase";
11
+ export { executeOcean, oceanSearchCompanies, oceanSearchPeople, OCEAN_OPERATION_IDS } from "./ocean";
12
+ export type { OceanOperationId, OceanCompaniesFilters, OceanPeopleFilters, OceanCompaniesSearchParams, OceanCompaniesSearchResponse, OceanCompanyResult, OceanCompanyMatch, OceanPeopleSearchParams, OceanPeopleSearchResponse, OceanPersonResult } from "./ocean";
9
13
  export { webSearch, webBatchSearch } from "./serp";
10
14
  export type { WebSearchQuery, WebSearchResult, WebSearchResponse, BatchWebSearchParams } from "./serp";
11
15
  export { generateObject } from "./generateObject";
@@ -25,11 +29,13 @@ export type { PersonLinkedinFindUrlParams, CompanyLinkedinFindUrlParams, PersonC
25
29
  import { runApifyActor } from "./apify";
26
30
  import { linkedinSearch } from "./b2b";
27
31
  import { browserExecute } from "./browser";
32
+ import { findCareersPage, scrapeCareersPage } from "./careers";
28
33
  import { crunchbaseSearch } from "./crunchbase";
29
34
  import { personLinkedinEnrich, personLinkedinFindUrl, personContactGet, companyLinkedinEnrich, companyLinkedinFindUrl, companyGetEmployeesFromLinkedin, geoParseAddress, builtWithLookupDomain, builtWithRelationships, builtWithSearchByTech } from "./expansion";
30
35
  import { scrapeWebsite } from "./firecrawl";
31
36
  import { generateObject } from "./generateObject";
32
37
  import { googleMapsScrape } from "./googleMaps";
38
+ import { oceanSearchCompanies, oceanSearchPeople } from "./ocean";
33
39
  import { webBatchSearch, webSearch } from "./serp";
34
40
  export declare const services: {
35
41
  crunchbase: {
@@ -42,6 +48,8 @@ export declare const services: {
42
48
  search: typeof linkedinSearch;
43
49
  };
44
50
  getEmployeesFromLinkedin: typeof companyGetEmployeesFromLinkedin;
51
+ findCareersPage: typeof findCareersPage;
52
+ scrapeCareersPage: typeof scrapeCareersPage;
45
53
  };
46
54
  person: {
47
55
  linkedin: {
@@ -75,6 +83,12 @@ export declare const services: {
75
83
  googleMaps: {
76
84
  scrape: typeof googleMapsScrape;
77
85
  };
86
+ ocean: {
87
+ search: {
88
+ companies: typeof oceanSearchCompanies;
89
+ people: typeof oceanSearchPeople;
90
+ };
91
+ };
78
92
  builtWith: {
79
93
  lookupDomain: typeof builtWithLookupDomain;
80
94
  relationships: typeof builtWithRelationships;
package/dist/index.js CHANGED
@@ -1,14 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.services = exports.builtWithSearchByTech = exports.builtWithRelationships = exports.builtWithLookupDomain = exports.geoParseAddress = exports.companyGetEmployeesFromLinkedin = exports.companyLinkedinFindUrl = exports.companyLinkedinEnrich = exports.personContactGet = exports.personLinkedinFindUrl = exports.personLinkedinEnrich = exports.PREDICT_LEADS_OPERATION_IDS = exports.predictLeads = exports.executePredictLeads = exports.googleMapsScrape = exports.runApifyActor = exports.browserExecute = exports.scrapeWebsite = exports.generateObject = exports.webBatchSearch = exports.webSearch = exports.crunchbaseSearch = exports.linkedinSearch = exports.ctx = exports.configure = void 0;
3
+ exports.services = exports.builtWithSearchByTech = exports.builtWithRelationships = exports.builtWithLookupDomain = exports.geoParseAddress = exports.companyGetEmployeesFromLinkedin = exports.companyLinkedinFindUrl = exports.companyLinkedinEnrich = exports.personContactGet = exports.personLinkedinFindUrl = exports.personLinkedinEnrich = exports.PREDICT_LEADS_OPERATION_IDS = exports.predictLeads = exports.executePredictLeads = exports.googleMapsScrape = exports.runApifyActor = exports.browserExecute = exports.scrapeWebsite = exports.generateObject = exports.webBatchSearch = exports.webSearch = exports.OCEAN_OPERATION_IDS = exports.oceanSearchPeople = exports.oceanSearchCompanies = exports.executeOcean = exports.crunchbaseSearch = exports.linkedinSearch = exports.ctx = exports.scrapeCareersPage = exports.findCareersPage = exports.configure = void 0;
4
4
  var api_1 = require("./api");
5
5
  Object.defineProperty(exports, "configure", { enumerable: true, get: function () { return api_1.configure; } });
6
+ var careers_1 = require("./careers");
7
+ Object.defineProperty(exports, "findCareersPage", { enumerable: true, get: function () { return careers_1.findCareersPage; } });
8
+ Object.defineProperty(exports, "scrapeCareersPage", { enumerable: true, get: function () { return careers_1.scrapeCareersPage; } });
6
9
  var ctx_1 = require("./ctx");
7
10
  Object.defineProperty(exports, "ctx", { enumerable: true, get: function () { return ctx_1.ctx; } });
8
11
  var b2b_1 = require("./b2b");
9
12
  Object.defineProperty(exports, "linkedinSearch", { enumerable: true, get: function () { return b2b_1.linkedinSearch; } });
10
13
  var crunchbase_1 = require("./crunchbase");
11
14
  Object.defineProperty(exports, "crunchbaseSearch", { enumerable: true, get: function () { return crunchbase_1.crunchbaseSearch; } });
15
+ var ocean_1 = require("./ocean");
16
+ Object.defineProperty(exports, "executeOcean", { enumerable: true, get: function () { return ocean_1.executeOcean; } });
17
+ Object.defineProperty(exports, "oceanSearchCompanies", { enumerable: true, get: function () { return ocean_1.oceanSearchCompanies; } });
18
+ Object.defineProperty(exports, "oceanSearchPeople", { enumerable: true, get: function () { return ocean_1.oceanSearchPeople; } });
19
+ Object.defineProperty(exports, "OCEAN_OPERATION_IDS", { enumerable: true, get: function () { return ocean_1.OCEAN_OPERATION_IDS; } });
12
20
  var serp_1 = require("./serp");
13
21
  Object.defineProperty(exports, "webSearch", { enumerable: true, get: function () { return serp_1.webSearch; } });
14
22
  Object.defineProperty(exports, "webBatchSearch", { enumerable: true, get: function () { return serp_1.webBatchSearch; } });
@@ -40,11 +48,13 @@ Object.defineProperty(exports, "builtWithSearchByTech", { enumerable: true, get:
40
48
  const apify_2 = require("./apify");
41
49
  const b2b_2 = require("./b2b");
42
50
  const browser_2 = require("./browser");
51
+ const careers_2 = require("./careers");
43
52
  const crunchbase_2 = require("./crunchbase");
44
53
  const expansion_2 = require("./expansion");
45
54
  const firecrawl_2 = require("./firecrawl");
46
55
  const generateObject_2 = require("./generateObject");
47
56
  const googleMaps_2 = require("./googleMaps");
57
+ const ocean_2 = require("./ocean");
48
58
  const predictLeads_2 = require("./predictLeads");
49
59
  const serp_2 = require("./serp");
50
60
  exports.services = {
@@ -57,7 +67,9 @@ exports.services = {
57
67
  enrich: expansion_2.companyLinkedinEnrich,
58
68
  search: b2b_2.linkedinSearch
59
69
  },
60
- getEmployeesFromLinkedin: expansion_2.companyGetEmployeesFromLinkedin
70
+ getEmployeesFromLinkedin: expansion_2.companyGetEmployeesFromLinkedin,
71
+ findCareersPage: careers_2.findCareersPage,
72
+ scrapeCareersPage: careers_2.scrapeCareersPage
61
73
  },
62
74
  person: {
63
75
  linkedin: {
@@ -91,6 +103,12 @@ exports.services = {
91
103
  googleMaps: {
92
104
  scrape: googleMaps_2.googleMapsScrape
93
105
  },
106
+ ocean: {
107
+ search: {
108
+ companies: ocean_2.oceanSearchCompanies,
109
+ people: ocean_2.oceanSearchPeople
110
+ }
111
+ },
94
112
  builtWith: {
95
113
  lookupDomain: expansion_2.builtWithLookupDomain,
96
114
  relationships: expansion_2.builtWithRelationships,
@@ -0,0 +1,166 @@
1
+ export declare const OCEAN_OPERATION_IDS: {
2
+ readonly searchCompanies: "search-companies";
3
+ readonly searchPeople: "search-people";
4
+ };
5
+ export type OceanOperationId = (typeof OCEAN_OPERATION_IDS)[keyof typeof OCEAN_OPERATION_IDS];
6
+ export interface OceanCompaniesFilters {
7
+ lookalikeDomains?: string[];
8
+ minScore?: number;
9
+ companySizes?: Array<"0-1" | "2-10" | "11-50" | "51-200" | "201-500" | "501-1000" | "1001-5000" | "5001-10000" | "10001+">;
10
+ countries?: string[];
11
+ industries?: string[];
12
+ technologies?: string[];
13
+ technologyCategories?: string[];
14
+ keywords?: string[];
15
+ revenueRanges?: string[];
16
+ ecommerce?: boolean;
17
+ }
18
+ export interface OceanPeopleFilters {
19
+ seniorities?: string[];
20
+ departments?: string[];
21
+ jobTitleKeywords?: string[];
22
+ countries?: string[];
23
+ lookalikePeopleIds?: string[];
24
+ }
25
+ export interface OceanCompaniesSearchParams {
26
+ companiesFilters?: OceanCompaniesFilters;
27
+ size?: number;
28
+ from?: number;
29
+ searchAfter?: string;
30
+ includeDomains?: string[];
31
+ excludeDomains?: string[];
32
+ }
33
+ export interface OceanPhone {
34
+ country?: string;
35
+ number: string;
36
+ primary?: boolean;
37
+ }
38
+ export interface OceanMediaProfile {
39
+ url?: string;
40
+ handle?: string;
41
+ name?: string;
42
+ }
43
+ export interface OceanLocation {
44
+ primary?: boolean;
45
+ latitude?: number;
46
+ longitude?: number;
47
+ country?: string;
48
+ locality?: string;
49
+ region?: string;
50
+ postalCode?: string;
51
+ streetAddress?: string;
52
+ state?: string;
53
+ }
54
+ export interface OceanDepartmentSize {
55
+ department: string;
56
+ size: number;
57
+ }
58
+ export interface OceanHeadcountGrowth {
59
+ threeMonths?: number;
60
+ threeMonthsPercentage?: number;
61
+ sixMonths?: number;
62
+ sixMonthsPercentage?: number;
63
+ twelveMonths?: number;
64
+ twelveMonthsPercentage?: number;
65
+ }
66
+ export interface OceanCompanyResult {
67
+ domain: string;
68
+ name?: string;
69
+ legalName?: string;
70
+ description?: string;
71
+ countries?: string[];
72
+ primaryCountry?: string;
73
+ companySize?: string;
74
+ industryCategories?: string[];
75
+ industries?: string[];
76
+ linkedinIndustry?: string;
77
+ ecommerce?: boolean;
78
+ keywords?: string[];
79
+ employeeCountOcean?: number;
80
+ employeeCountLinkedin?: number;
81
+ revenue?: string;
82
+ yearFounded?: number;
83
+ emails?: string[];
84
+ phones?: OceanPhone[];
85
+ logo?: string;
86
+ technologies?: string[];
87
+ technologyCategories?: string[];
88
+ rootUrl?: string;
89
+ medias?: Record<string, OceanMediaProfile>;
90
+ locations?: OceanLocation[];
91
+ departmentSizes?: OceanDepartmentSize[];
92
+ headcountGrowth?: OceanHeadcountGrowth;
93
+ updatedAt?: string;
94
+ }
95
+ export interface OceanCompanyMatch {
96
+ company: OceanCompanyResult;
97
+ relevance?: string;
98
+ }
99
+ export interface OceanCompaniesSearchResponse {
100
+ total: number;
101
+ searchAfter?: string;
102
+ companies: OceanCompanyMatch[];
103
+ redirectMap?: Record<string, string>;
104
+ }
105
+ export interface OceanPersonExperience {
106
+ dateFrom?: string;
107
+ dateTo?: string;
108
+ description?: string;
109
+ domain?: string;
110
+ jobTitle?: string;
111
+ }
112
+ export interface OceanContactField {
113
+ address?: string;
114
+ status?: string;
115
+ }
116
+ export interface OceanPhoneField {
117
+ numbers?: string[];
118
+ status?: string;
119
+ }
120
+ export interface OceanPersonCompanySnapshot {
121
+ companySize?: string;
122
+ logo?: string;
123
+ name?: string;
124
+ }
125
+ export interface OceanPersonResult {
126
+ id: string;
127
+ domain?: string;
128
+ name?: string;
129
+ firstName?: string;
130
+ lastName?: string;
131
+ country?: string;
132
+ state?: string;
133
+ location?: string;
134
+ linkedinUrl?: string;
135
+ seniorities?: string[];
136
+ departments?: string[];
137
+ photo?: string;
138
+ jobTitle?: string;
139
+ jobTitleEnglish?: string;
140
+ currentJobDescription?: string;
141
+ experiences?: OceanPersonExperience[];
142
+ summary?: string;
143
+ skills?: string[];
144
+ phone?: OceanPhoneField;
145
+ email?: OceanContactField;
146
+ updatedAt?: string;
147
+ company?: OceanPersonCompanySnapshot;
148
+ }
149
+ export interface OceanPeopleSearchParams {
150
+ companiesFilters?: OceanCompaniesFilters;
151
+ peopleFilters?: OceanPeopleFilters;
152
+ size?: number;
153
+ from?: number;
154
+ searchAfter?: string;
155
+ enableEmailSearch?: boolean;
156
+ enablePhoneSearch?: boolean;
157
+ }
158
+ export interface OceanPeopleSearchResponse {
159
+ total: number;
160
+ searchAfter?: string;
161
+ people: OceanPersonResult[];
162
+ redirectMap?: Record<string, string>;
163
+ }
164
+ export declare function executeOcean<T = unknown>(operationId: OceanOperationId, params?: Record<string, unknown>): Promise<T>;
165
+ export declare function oceanSearchCompanies(params: OceanCompaniesSearchParams): Promise<OceanCompaniesSearchResponse>;
166
+ export declare function oceanSearchPeople(params: OceanPeopleSearchParams): Promise<OceanPeopleSearchResponse>;
package/dist/ocean.js ADDED
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OCEAN_OPERATION_IDS = void 0;
4
+ exports.executeOcean = executeOcean;
5
+ exports.oceanSearchCompanies = oceanSearchCompanies;
6
+ exports.oceanSearchPeople = oceanSearchPeople;
7
+ const api_1 = require("./api");
8
+ exports.OCEAN_OPERATION_IDS = {
9
+ searchCompanies: "search-companies",
10
+ searchPeople: "search-people"
11
+ };
12
+ async function executeOcean(operationId, params) {
13
+ return (0, api_1.post)("/execute/oceanio", {
14
+ operationId,
15
+ params: params ?? {}
16
+ });
17
+ }
18
+ async function oceanSearchCompanies(params) {
19
+ return executeOcean(exports.OCEAN_OPERATION_IDS.searchCompanies, params);
20
+ }
21
+ async function oceanSearchPeople(params) {
22
+ return executeOcean(exports.OCEAN_OPERATION_IDS.searchPeople, params);
23
+ }
@@ -5,12 +5,18 @@ description: Patterns for enriching company data, tech stack detection, hiring d
5
5
 
6
6
  # Data Enrichment
7
7
 
8
- Standard pattern: **Search → Scrape → Extract**
8
+ Standard pattern: **Search/Domain → Scrape → Extract**
9
9
 
10
- 1. `web.search` with `site:` to find subpages likely to contain the data
10
+ 1. Start with a company `domain` when you already have it, otherwise use `web.search` with `site:` to find relevant pages
11
11
  2. `scrape.website` to get page content as markdown
12
12
  3. `ai.generateObject` to extract structured fields
13
13
 
14
+ For company enrichment/classification, prefer the website over LinkedIn `industry`.
15
+
16
+ - LinkedIn `industry` is acceptable as lightweight lookup context
17
+ - LinkedIn `industry` is too sparse/generic to be your main enrichment signal
18
+ - Preferred workflow: `domain` -> `scrape.website` -> `ai.generateObject`
19
+
14
20
  ---
15
21
 
16
22
  ## Example: Does this law firm handle medical malpractice?
@@ -42,6 +48,8 @@ async function checkMedMalPractice(domain: string) {
42
48
 
43
49
  ---
44
50
 
51
+ ---
52
+
45
53
  ## When to Use
46
54
 
47
55
  | Use Search → Scrape → Extract | Use `browser.execute` instead |
@@ -0,0 +1,54 @@
1
+ # createDraft
2
+
3
+ Create a Gmail draft without sending it yet.
4
+
5
+ ```typescript
6
+ // Create a new draft
7
+ const draft = await integrations.gmail.createDraft({
8
+ recipient_email: "jane@example.com",
9
+ subject: "Draft follow-up",
10
+ body: "Sharing a quick follow-up before I send this."
11
+ });
12
+
13
+ // Draft a reply in an existing thread
14
+ await integrations.gmail.createDraft({
15
+ thread_id: "19bf77729bcb3a44",
16
+ body: "Thanks for the update. I will review this today."
17
+ });
18
+ ```
19
+
20
+ ## Input
21
+
22
+ | Parameter | Type | Required | Description |
23
+ | ------------------ | ---------- | -------- | -------------------------------------------- |
24
+ | `recipient_email` | `string` | No | Primary `To` recipient |
25
+ | `extra_recipients` | `string[]` | No | Additional `To` recipients |
26
+ | `cc` | `string[]` | No | CC recipients |
27
+ | `bcc` | `string[]` | No | BCC recipients |
28
+ | `subject` | `string` | No | Draft subject |
29
+ | `body` | `string` | No | Draft body content |
30
+ | `message_body` | `string` | No | Alternate body field accepted by some tools |
31
+ | `is_html` | `boolean` | No | Set to `true` when `body` contains HTML |
32
+ | `attachment` | `object` | No | Optional attachment payload |
33
+ | `thread_id` | `string` | No | Existing thread to draft a reply into |
34
+ | `from_email` | `string` | No | Optional verified send-as alias |
35
+ | `user_id` | `string` | No | Gmail user id (`\"me\"` by default) |
36
+
37
+ ## Output
38
+
39
+ ```typescript
40
+ {
41
+ successful: boolean;
42
+ data?: {
43
+ id?: string;
44
+ draft_id?: string;
45
+ message?: GmailMessage;
46
+ };
47
+ error?: string;
48
+ }
49
+ ```
50
+
51
+ ## Notes
52
+
53
+ - Creating a draft is a mutating action and should be used intentionally
54
+ - If you pass `thread_id`, leave `subject` empty to stay in the existing thread
@@ -0,0 +1,50 @@
1
+ # fetchEmails
2
+
3
+ Fetch inbox messages or Gmail search results from the connected account.
4
+
5
+ ```typescript
6
+ // Read the current inbox
7
+ const inbox = await integrations.gmail.fetchEmails({
8
+ query: "in:inbox",
9
+ max_results: 10
10
+ });
11
+
12
+ // Search for unread emails from a sender
13
+ const unread = await integrations.gmail.fetchEmails({
14
+ query: "in:inbox is:unread from:alice@example.com",
15
+ max_results: 25
16
+ });
17
+ ```
18
+
19
+ ## Input
20
+
21
+ | Parameter | Type | Required | Description |
22
+ | --------------------- | ---------- | -------- | ----------------------------------------------------- |
23
+ | `query` | `string` | No | Gmail search query such as `in:inbox is:unread` |
24
+ | `verbose` | `boolean` | No | Fetch richer message details |
25
+ | `ids_only` | `boolean` | No | Only return message/thread identifiers |
26
+ | `label_ids` | `string[]` | No | Filter by Gmail label IDs |
27
+ | `page_token` | `string` | No | Pagination token from a previous call |
28
+ | `max_results` | `number` | No | Maximum messages to fetch in this page |
29
+ | `include_payload` | `boolean` | No | Include payload/body data when available |
30
+ | `include_spam_trash` | `boolean` | No | Include spam and trash |
31
+ | `user_id` | `string` | No | Gmail user id (`\"me\"` by default) |
32
+
33
+ ## Output
34
+
35
+ ```typescript
36
+ {
37
+ successful: boolean;
38
+ data?: {
39
+ messages?: GmailMessage[];
40
+ nextPageToken?: string;
41
+ resultSizeEstimate?: number;
42
+ };
43
+ error?: string;
44
+ }
45
+ ```
46
+
47
+ ## Notes
48
+
49
+ - Results are not guaranteed to be sorted by recency, so sort client-side if order matters
50
+ - For large mailboxes, fetch IDs first and then hydrate specific messages with `fetchMessageByMessageId(...)`
@@ -0,0 +1,36 @@
1
+ # fetchMessageByMessageId
2
+
3
+ Fetch a single Gmail message by its Gmail API message ID.
4
+
5
+ ```typescript
6
+ const message = await integrations.gmail.fetchMessageByMessageId({
7
+ message_id: "19b11732c1b578fd",
8
+ format: "full"
9
+ });
10
+
11
+ console.log(message.data?.subject);
12
+ console.log(message.data?.threadId);
13
+ ```
14
+
15
+ ## Input
16
+
17
+ | Parameter | Type | Required | Description |
18
+ | ------------- | ----------------------------------------- | -------- | -------------------------------------- |
19
+ | `message_id` | `string` | Yes | Gmail API message ID |
20
+ | `format` | `\"minimal\" | \"full\" | \"raw\" | \"metadata\"` | No | Response format |
21
+ | `user_id` | `string` | No | Gmail user id (`\"me\"` by default) |
22
+
23
+ ## Output
24
+
25
+ ```typescript
26
+ {
27
+ successful: boolean;
28
+ data?: GmailMessage;
29
+ error?: string;
30
+ }
31
+ ```
32
+
33
+ ## Notes
34
+
35
+ - Use real Gmail `message_id` values returned by Gmail list/search actions
36
+ - `format: "full"` is best when you need headers, payload parts, or body data
@@ -0,0 +1,37 @@
1
+ # fetchMessageByThreadId
2
+
3
+ Fetch all messages belonging to a Gmail thread.
4
+
5
+ ```typescript
6
+ const thread = await integrations.gmail.fetchMessageByThreadId({
7
+ thread_id: "19bf77729bcb3a44"
8
+ });
9
+
10
+ for (const message of thread.data?.messages || []) {
11
+ console.log(message.subject);
12
+ }
13
+ ```
14
+
15
+ ## Input
16
+
17
+ | Parameter | Type | Required | Description |
18
+ | ------------ | -------- | -------- | ----------------------------------- |
19
+ | `thread_id` | `string` | Yes | Gmail API thread ID |
20
+ | `user_id` | `string` | No | Gmail user id (`\"me\"` by default) |
21
+
22
+ ## Output
23
+
24
+ ```typescript
25
+ {
26
+ successful: boolean;
27
+ data?: {
28
+ messages?: GmailMessage[];
29
+ };
30
+ error?: string;
31
+ }
32
+ ```
33
+
34
+ ## Notes
35
+
36
+ - Message order is not guaranteed, so sort by `internalDate` if you need oldest/newest order
37
+ - Read threads first before calling `replyToThread(...)` so you have the correct `thread_id`
@@ -0,0 +1,37 @@
1
+ # getProfile
2
+
3
+ Read Gmail profile metadata for the connected account.
4
+
5
+ ```typescript
6
+ const profile = await integrations.gmail.getProfile();
7
+
8
+ console.log(profile.data?.emailAddress);
9
+ console.log(profile.data?.messagesTotal);
10
+ console.log(profile.data?.threadsTotal);
11
+ ```
12
+
13
+ ## Input
14
+
15
+ | Parameter | Type | Required | Description |
16
+ | --------- | -------- | -------- | ----------------------------------- |
17
+ | `user_id` | `string` | No | Gmail user id (`\"me\"` by default) |
18
+
19
+ ## Output
20
+
21
+ ```typescript
22
+ {
23
+ successful: boolean;
24
+ data?: {
25
+ emailAddress?: string;
26
+ messagesTotal?: number;
27
+ threadsTotal?: number;
28
+ historyId?: string;
29
+ };
30
+ error?: string;
31
+ }
32
+ ```
33
+
34
+ ## Notes
35
+
36
+ - This is a lightweight way to confirm which mailbox is connected
37
+ - Mailbox totals are useful for diagnostics, health checks, and quick account introspection