orangeslice 1.8.4 → 1.8.6-beta.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/dist/api.d.ts +5 -0
- package/dist/api.js +26 -4
- package/dist/cli.js +76 -9
- package/dist/expansion.d.ts +43 -0
- package/dist/expansion.js +23 -0
- package/dist/index.d.ts +14 -7
- package/dist/index.js +16 -6
- package/docs/integrations/gmail/index.md +12 -0
- package/docs/integrations/gmail/sendEmail.md +51 -0
- package/docs/integrations/index.md +24 -0
- package/docs/prospecting/index.md +10 -0
- package/docs/services/person/linkedin/enrich.md +1 -0
- package/package.json +1 -1
package/dist/api.d.ts
CHANGED
package/dist/api.js
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.configure = configure;
|
|
3
4
|
exports.post = post;
|
|
4
5
|
/**
|
|
5
6
|
* Batch-only routing:
|
|
6
7
|
* - Submit all calls to Railway batch-service /function
|
|
7
8
|
* - Poll batch-service /function/result on pending responses
|
|
8
9
|
*/
|
|
9
|
-
const
|
|
10
|
+
const DEFAULT_BASE_URL = "https://enrichly-production.up.railway.app/function";
|
|
10
11
|
const POLL_TIMEOUT_MS = 600000;
|
|
11
12
|
const DEFAULT_POLL_INTERVAL_MS = 1000;
|
|
13
|
+
const _config = {};
|
|
14
|
+
function configure(opts) {
|
|
15
|
+
if (opts.apiKey !== undefined)
|
|
16
|
+
_config.apiKey = opts.apiKey;
|
|
17
|
+
if (opts.baseUrl !== undefined)
|
|
18
|
+
_config.baseUrl = opts.baseUrl;
|
|
19
|
+
}
|
|
20
|
+
function resolveBaseUrl() {
|
|
21
|
+
return _config.baseUrl || process.env.ORANGESLICE_BASE_URL || DEFAULT_BASE_URL;
|
|
22
|
+
}
|
|
23
|
+
function resolveApiKey() {
|
|
24
|
+
return _config.apiKey || process.env.ORANGESLICE_API_KEY || "";
|
|
25
|
+
}
|
|
12
26
|
function sleep(ms) {
|
|
13
27
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
14
28
|
}
|
|
@@ -102,14 +116,22 @@ async function pollBatchUntilComplete(baseUrl, functionId, pending) {
|
|
|
102
116
|
throw new Error(`[orangeslice] ${functionId}: polling timed out after ${POLL_TIMEOUT_MS}ms`);
|
|
103
117
|
}
|
|
104
118
|
async function post(functionId, payload, options = {}) {
|
|
105
|
-
// Kept for backwards compatibility with older call sites.
|
|
106
119
|
void options;
|
|
107
|
-
const baseUrl =
|
|
120
|
+
const baseUrl = resolveBaseUrl();
|
|
121
|
+
const apiKey = resolveApiKey();
|
|
122
|
+
if (!apiKey) {
|
|
123
|
+
throw new Error("[orangeslice] No API key configured. " +
|
|
124
|
+
"Set ORANGESLICE_API_KEY in your environment or call configure({ apiKey: 'osk_...' }).");
|
|
125
|
+
}
|
|
108
126
|
const url = `${baseUrl}?functionId=${functionId}`;
|
|
109
127
|
const body = JSON.stringify(payload);
|
|
128
|
+
const headers = {
|
|
129
|
+
"Content-Type": "application/json",
|
|
130
|
+
Authorization: `Bearer ${apiKey}`
|
|
131
|
+
};
|
|
110
132
|
const res = await fetchWithRedirect(url, {
|
|
111
133
|
method: "POST",
|
|
112
|
-
headers
|
|
134
|
+
headers,
|
|
113
135
|
body
|
|
114
136
|
});
|
|
115
137
|
if (!res.ok) {
|
package/dist/cli.js
CHANGED
|
@@ -37,6 +37,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
37
37
|
const child_process_1 = require("child_process");
|
|
38
38
|
const fs = __importStar(require("fs"));
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
|
+
const readline = __importStar(require("readline"));
|
|
40
41
|
const LEGACY_DOCS_DIR = path.join(__dirname, "..", "docs");
|
|
41
42
|
const TARGET_DIR = path.join(process.cwd(), "orangeslice-docs");
|
|
42
43
|
const AGENTS_FILE = path.join(TARGET_DIR, "AGENTS.md");
|
|
@@ -110,6 +111,74 @@ function installOrangeslice(cwd) {
|
|
|
110
111
|
console.log(" Installing orangeslice...");
|
|
111
112
|
(0, child_process_1.execSync)("npm install orangeslice", { stdio: "inherit", cwd });
|
|
112
113
|
}
|
|
114
|
+
function prompt(question) {
|
|
115
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
116
|
+
return new Promise((resolve) => {
|
|
117
|
+
rl.question(question, (answer) => {
|
|
118
|
+
rl.close();
|
|
119
|
+
resolve(answer.trim());
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
function readEnvFile(envPath) {
|
|
124
|
+
const entries = new Map();
|
|
125
|
+
if (!fs.existsSync(envPath))
|
|
126
|
+
return entries;
|
|
127
|
+
const lines = fs.readFileSync(envPath, "utf8").split("\n");
|
|
128
|
+
for (const line of lines) {
|
|
129
|
+
const match = line.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)/);
|
|
130
|
+
if (match)
|
|
131
|
+
entries.set(match[1], match[2]);
|
|
132
|
+
}
|
|
133
|
+
return entries;
|
|
134
|
+
}
|
|
135
|
+
function writeEnvVar(envPath, key, value) {
|
|
136
|
+
const entries = readEnvFile(envPath);
|
|
137
|
+
entries.set(key, value);
|
|
138
|
+
const lines = [];
|
|
139
|
+
if (fs.existsSync(envPath)) {
|
|
140
|
+
const original = fs.readFileSync(envPath, "utf8").split("\n");
|
|
141
|
+
let replaced = false;
|
|
142
|
+
for (const line of original) {
|
|
143
|
+
const match = line.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)/);
|
|
144
|
+
if (match && match[1] === key) {
|
|
145
|
+
lines.push(`${key}=${value}`);
|
|
146
|
+
replaced = true;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
lines.push(line);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (!replaced) {
|
|
153
|
+
if (lines.length > 0 && lines[lines.length - 1] !== "")
|
|
154
|
+
lines.push("");
|
|
155
|
+
lines.push(`${key}=${value}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
lines.push(`${key}=${value}`, "");
|
|
160
|
+
}
|
|
161
|
+
fs.writeFileSync(envPath, lines.join("\n"), "utf8");
|
|
162
|
+
}
|
|
163
|
+
async function setupApiKey(cwd) {
|
|
164
|
+
const envPath = path.join(cwd, ".env");
|
|
165
|
+
const existing = readEnvFile(envPath).get("ORANGESLICE_API_KEY");
|
|
166
|
+
if (existing) {
|
|
167
|
+
console.log(` ✓ API key already configured in .env (${existing.slice(0, 12)}...)\n`);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
console.log(" API key required. Get one at: https://www.orangeslice.ai/dashboard/api-keys\n");
|
|
171
|
+
const key = await prompt(" Paste your API key (osk_...): ");
|
|
172
|
+
if (!key) {
|
|
173
|
+
console.log("\n ⚠ Skipped. Set ORANGESLICE_API_KEY in .env or call configure({ apiKey }) before using the SDK.\n");
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (!key.startsWith("osk_")) {
|
|
177
|
+
console.log("\n ⚠ Key doesn't start with osk_ — saving anyway. Double-check it's correct.\n");
|
|
178
|
+
}
|
|
179
|
+
writeEnvVar(envPath, "ORANGESLICE_API_KEY", key);
|
|
180
|
+
console.log(`\n ✓ API key saved to .env\n`);
|
|
181
|
+
}
|
|
113
182
|
async function main() {
|
|
114
183
|
console.log("\norangeslice\n");
|
|
115
184
|
const docsDir = resolveDocsDir();
|
|
@@ -124,29 +193,27 @@ async function main() {
|
|
|
124
193
|
ensurePackageJson(cwd);
|
|
125
194
|
installOrangeslice(cwd);
|
|
126
195
|
console.log(" ✓ Package installed in current directory\n");
|
|
196
|
+
// API key setup
|
|
197
|
+
await setupApiKey(cwd);
|
|
127
198
|
console.log("\nReady - services-style API\n");
|
|
128
|
-
console.log(" import { services } from 'orangeslice';\n");
|
|
199
|
+
console.log(" import { configure, services } from 'orangeslice';\n");
|
|
200
|
+
console.log(" // Option A: env var (loaded automatically from .env by your framework)");
|
|
201
|
+
console.log(" // ORANGESLICE_API_KEY=osk_... in .env\n");
|
|
202
|
+
console.log(" // Option B: programmatic");
|
|
203
|
+
console.log(" configure({ apiKey: 'osk_...' });\n");
|
|
129
204
|
console.log(" Agent setup (do this first):");
|
|
130
205
|
console.log(" Ask your agent to read:");
|
|
131
206
|
console.log(" 1) ./orangeslice-docs/AGENTS.md");
|
|
132
207
|
console.log(" 2) ./orangeslice-docs/services/index.md");
|
|
133
208
|
console.log(' Then tell it: "Use these docs as source of truth for all orangeslice operations."\n');
|
|
134
|
-
console.log(" Routing note:");
|
|
135
|
-
console.log(" - all services submit to the batch-service /function endpoint");
|
|
136
|
-
console.log(" - pending jobs poll batch-service /function/result endpoints");
|
|
137
|
-
console.log(" - this package currently includes only batch-backed services\n");
|
|
138
209
|
console.log(" // LinkedIn B2B SQL");
|
|
139
210
|
console.log(' const { rows } = await services.company.linkedin.search({ sql: "SELECT * FROM linkedin_company LIMIT 10" });\n');
|
|
140
211
|
console.log(" // Web search");
|
|
141
212
|
console.log(" const page = await services.web.search({ query: 'best CRM software' });\n");
|
|
142
|
-
console.log(" // Batched web search");
|
|
143
|
-
console.log(" const pages = await services.web.batchSearch({ queries: [{ query: 'site:linkedin.com/in stripe' }] });\n");
|
|
144
213
|
console.log(" // AI structured output");
|
|
145
214
|
console.log(" const { object } = await services.ai.generateObject({ prompt: '...', schema: {...} });\n");
|
|
146
215
|
console.log(" // Browser automation (Kernel)");
|
|
147
216
|
console.log(' const browser = await services.browser.execute({ code: "return await page.title();" });\n');
|
|
148
|
-
console.log(" // Apify actor");
|
|
149
|
-
console.log(" const actor = await services.apify.runActor({ actor: 'apify/web-scraper', input: {} });\n");
|
|
150
217
|
console.log(" Always parallelize independent calls with Promise.all.\n");
|
|
151
218
|
}
|
|
152
219
|
main().catch(console.error);
|
package/dist/expansion.d.ts
CHANGED
|
@@ -28,8 +28,51 @@ export interface CompanyGetEmployeesFromLinkedinResult {
|
|
|
28
28
|
nextPage: number | null;
|
|
29
29
|
totalResults: number | null;
|
|
30
30
|
}
|
|
31
|
+
export interface PersonLinkedinFindUrlParams {
|
|
32
|
+
name?: string;
|
|
33
|
+
title?: string;
|
|
34
|
+
company?: string;
|
|
35
|
+
keyword?: string;
|
|
36
|
+
location?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface CompanyLinkedinFindUrlParams {
|
|
39
|
+
companyName?: string;
|
|
40
|
+
website?: string;
|
|
41
|
+
location?: string;
|
|
42
|
+
}
|
|
43
|
+
export interface PersonContactGetParams {
|
|
44
|
+
linkedinUrl?: string;
|
|
45
|
+
required: Array<"email" | "work_email" | "phone">;
|
|
46
|
+
sources?: Array<"bcr">;
|
|
47
|
+
maxCoverage?: boolean;
|
|
48
|
+
domain?: string;
|
|
49
|
+
firstName?: string;
|
|
50
|
+
lastName?: string;
|
|
51
|
+
company?: string;
|
|
52
|
+
phoneNumber?: string;
|
|
53
|
+
userId?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface PersonContactGetResult {
|
|
56
|
+
work_emails: string[];
|
|
57
|
+
work_phones: string[];
|
|
58
|
+
personal_emails: string[];
|
|
59
|
+
personal_phones: string[];
|
|
60
|
+
unknown_phones: string[];
|
|
61
|
+
}
|
|
31
62
|
export declare function personLinkedinEnrich(params: Record<string, unknown>): Promise<unknown>;
|
|
32
63
|
export declare function companyLinkedinEnrich(params: Record<string, unknown>): Promise<unknown>;
|
|
64
|
+
/**
|
|
65
|
+
* Find a LinkedIn person profile URL from name/title/company context.
|
|
66
|
+
*/
|
|
67
|
+
export declare function personLinkedinFindUrl(params: PersonLinkedinFindUrlParams): Promise<string | null>;
|
|
68
|
+
/**
|
|
69
|
+
* Find a LinkedIn company URL from website/company context.
|
|
70
|
+
*/
|
|
71
|
+
export declare function companyLinkedinFindUrl(params: CompanyLinkedinFindUrlParams): Promise<string | null>;
|
|
72
|
+
/**
|
|
73
|
+
* Run contact waterfall through Inngest and poll until completion.
|
|
74
|
+
*/
|
|
75
|
+
export declare function personContactGet(params: PersonContactGetParams): Promise<PersonContactGetResult>;
|
|
33
76
|
export declare function companyGetEmployeesFromLinkedin(params: CompanyGetEmployeesFromLinkedinParams): Promise<CompanyGetEmployeesFromLinkedinResult>;
|
|
34
77
|
export declare function geoParseAddress(params: Record<string, unknown>): Promise<unknown>;
|
|
35
78
|
export declare function builtWithLookupDomain(params: Record<string, unknown>): Promise<unknown>;
|
package/dist/expansion.js
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.personLinkedinEnrich = personLinkedinEnrich;
|
|
4
4
|
exports.companyLinkedinEnrich = companyLinkedinEnrich;
|
|
5
|
+
exports.personLinkedinFindUrl = personLinkedinFindUrl;
|
|
6
|
+
exports.companyLinkedinFindUrl = companyLinkedinFindUrl;
|
|
7
|
+
exports.personContactGet = personContactGet;
|
|
5
8
|
exports.companyGetEmployeesFromLinkedin = companyGetEmployeesFromLinkedin;
|
|
6
9
|
exports.geoParseAddress = geoParseAddress;
|
|
7
10
|
exports.builtWithLookupDomain = builtWithLookupDomain;
|
|
@@ -85,6 +88,26 @@ async function companyLinkedinEnrich(params) {
|
|
|
85
88
|
const data = await (0, api_1.post)("b2b", { sql }, { direct: true });
|
|
86
89
|
return data.rows?.[0] ?? null;
|
|
87
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Find a LinkedIn person profile URL from name/title/company context.
|
|
93
|
+
*/
|
|
94
|
+
async function personLinkedinFindUrl(params) {
|
|
95
|
+
const url = await (0, api_1.post)("linkedinFindProfileUrl", params);
|
|
96
|
+
return typeof url === "string" && url.trim().length > 0 ? url : null;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Find a LinkedIn company URL from website/company context.
|
|
100
|
+
*/
|
|
101
|
+
async function companyLinkedinFindUrl(params) {
|
|
102
|
+
const url = await (0, api_1.post)("findLinkedinCompanyUrl", params);
|
|
103
|
+
return typeof url === "string" && url.trim().length > 0 ? url : null;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Run contact waterfall through Inngest and poll until completion.
|
|
107
|
+
*/
|
|
108
|
+
async function personContactGet(params) {
|
|
109
|
+
return (0, api_1.post)("contactInfoWaterfall", { ...params });
|
|
110
|
+
}
|
|
88
111
|
async function companyGetEmployeesFromLinkedin(params) {
|
|
89
112
|
return (0, api_1.post)("b2b-get-employees-for-company", params);
|
|
90
113
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { configure } from "./api";
|
|
2
|
+
export type { OrangesliceConfig } from "./api";
|
|
1
3
|
export { linkedinSearch } from "./b2b";
|
|
2
4
|
export type { LinkedInSearchParams, LinkedInSearchResponse } from "./b2b";
|
|
3
5
|
export { webSearch, webBatchSearch } from "./serp";
|
|
@@ -12,19 +14,20 @@ export { runApifyActor } from "./apify";
|
|
|
12
14
|
export type { RunActorParams, RunActorResult, DatasetListParams } from "./apify";
|
|
13
15
|
export { googleMapsScrape } from "./googleMaps";
|
|
14
16
|
export type { GoogleMapsScrapeParams } from "./googleMaps";
|
|
15
|
-
export { personLinkedinEnrich, companyLinkedinEnrich, companyGetEmployeesFromLinkedin, geoParseAddress, builtWithLookupDomain, builtWithRelationships, builtWithSearchByTech } from "./expansion";
|
|
16
|
-
export type { CompanyGetEmployeesFromLinkedinParams, CompanyGetEmployeesFromLinkedinResult, CompanyEmployeeFromB2B } from "./expansion";
|
|
17
|
+
export { personLinkedinEnrich, personLinkedinFindUrl, personContactGet, companyLinkedinEnrich, companyLinkedinFindUrl, companyGetEmployeesFromLinkedin, geoParseAddress, builtWithLookupDomain, builtWithRelationships, builtWithSearchByTech } from "./expansion";
|
|
18
|
+
export type { PersonLinkedinFindUrlParams, CompanyLinkedinFindUrlParams, PersonContactGetParams, PersonContactGetResult, CompanyGetEmployeesFromLinkedinParams, CompanyGetEmployeesFromLinkedinResult, CompanyEmployeeFromB2B } from "./expansion";
|
|
19
|
+
import { runApifyActor } from "./apify";
|
|
17
20
|
import { linkedinSearch } from "./b2b";
|
|
18
|
-
import { webBatchSearch, webSearch } from "./serp";
|
|
19
|
-
import { generateObject } from "./generateObject";
|
|
20
|
-
import { scrapeWebsite } from "./firecrawl";
|
|
21
21
|
import { browserExecute } from "./browser";
|
|
22
|
-
import {
|
|
22
|
+
import { personLinkedinEnrich, personLinkedinFindUrl, personContactGet, companyLinkedinEnrich, companyLinkedinFindUrl, companyGetEmployeesFromLinkedin, geoParseAddress, builtWithLookupDomain, builtWithRelationships, builtWithSearchByTech } from "./expansion";
|
|
23
|
+
import { scrapeWebsite } from "./firecrawl";
|
|
24
|
+
import { generateObject } from "./generateObject";
|
|
23
25
|
import { googleMapsScrape } from "./googleMaps";
|
|
24
|
-
import {
|
|
26
|
+
import { webBatchSearch, webSearch } from "./serp";
|
|
25
27
|
export declare const services: {
|
|
26
28
|
company: {
|
|
27
29
|
linkedin: {
|
|
30
|
+
findUrl: typeof companyLinkedinFindUrl;
|
|
28
31
|
enrich: typeof companyLinkedinEnrich;
|
|
29
32
|
search: typeof linkedinSearch;
|
|
30
33
|
};
|
|
@@ -32,9 +35,13 @@ export declare const services: {
|
|
|
32
35
|
};
|
|
33
36
|
person: {
|
|
34
37
|
linkedin: {
|
|
38
|
+
findUrl: typeof personLinkedinFindUrl;
|
|
35
39
|
enrich: typeof personLinkedinEnrich;
|
|
36
40
|
search: typeof linkedinSearch;
|
|
37
41
|
};
|
|
42
|
+
contact: {
|
|
43
|
+
get: typeof personContactGet;
|
|
44
|
+
};
|
|
38
45
|
};
|
|
39
46
|
web: {
|
|
40
47
|
search: typeof webSearch;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
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.companyLinkedinEnrich = exports.personLinkedinEnrich = exports.googleMapsScrape = exports.runApifyActor = exports.browserExecute = exports.scrapeWebsite = exports.generateObject = exports.webBatchSearch = exports.webSearch = exports.linkedinSearch = 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.googleMapsScrape = exports.runApifyActor = exports.browserExecute = exports.scrapeWebsite = exports.generateObject = exports.webBatchSearch = exports.webSearch = exports.linkedinSearch = exports.configure = void 0;
|
|
4
|
+
var api_1 = require("./api");
|
|
5
|
+
Object.defineProperty(exports, "configure", { enumerable: true, get: function () { return api_1.configure; } });
|
|
4
6
|
var b2b_1 = require("./b2b");
|
|
5
7
|
Object.defineProperty(exports, "linkedinSearch", { enumerable: true, get: function () { return b2b_1.linkedinSearch; } });
|
|
6
8
|
var serp_1 = require("./serp");
|
|
@@ -18,23 +20,27 @@ var googleMaps_1 = require("./googleMaps");
|
|
|
18
20
|
Object.defineProperty(exports, "googleMapsScrape", { enumerable: true, get: function () { return googleMaps_1.googleMapsScrape; } });
|
|
19
21
|
var expansion_1 = require("./expansion");
|
|
20
22
|
Object.defineProperty(exports, "personLinkedinEnrich", { enumerable: true, get: function () { return expansion_1.personLinkedinEnrich; } });
|
|
23
|
+
Object.defineProperty(exports, "personLinkedinFindUrl", { enumerable: true, get: function () { return expansion_1.personLinkedinFindUrl; } });
|
|
24
|
+
Object.defineProperty(exports, "personContactGet", { enumerable: true, get: function () { return expansion_1.personContactGet; } });
|
|
21
25
|
Object.defineProperty(exports, "companyLinkedinEnrich", { enumerable: true, get: function () { return expansion_1.companyLinkedinEnrich; } });
|
|
26
|
+
Object.defineProperty(exports, "companyLinkedinFindUrl", { enumerable: true, get: function () { return expansion_1.companyLinkedinFindUrl; } });
|
|
22
27
|
Object.defineProperty(exports, "companyGetEmployeesFromLinkedin", { enumerable: true, get: function () { return expansion_1.companyGetEmployeesFromLinkedin; } });
|
|
23
28
|
Object.defineProperty(exports, "geoParseAddress", { enumerable: true, get: function () { return expansion_1.geoParseAddress; } });
|
|
24
29
|
Object.defineProperty(exports, "builtWithLookupDomain", { enumerable: true, get: function () { return expansion_1.builtWithLookupDomain; } });
|
|
25
30
|
Object.defineProperty(exports, "builtWithRelationships", { enumerable: true, get: function () { return expansion_1.builtWithRelationships; } });
|
|
26
31
|
Object.defineProperty(exports, "builtWithSearchByTech", { enumerable: true, get: function () { return expansion_1.builtWithSearchByTech; } });
|
|
32
|
+
const apify_2 = require("./apify");
|
|
27
33
|
const b2b_2 = require("./b2b");
|
|
28
|
-
const serp_2 = require("./serp");
|
|
29
|
-
const generateObject_2 = require("./generateObject");
|
|
30
|
-
const firecrawl_2 = require("./firecrawl");
|
|
31
34
|
const browser_2 = require("./browser");
|
|
32
|
-
const apify_2 = require("./apify");
|
|
33
|
-
const googleMaps_2 = require("./googleMaps");
|
|
34
35
|
const expansion_2 = require("./expansion");
|
|
36
|
+
const firecrawl_2 = require("./firecrawl");
|
|
37
|
+
const generateObject_2 = require("./generateObject");
|
|
38
|
+
const googleMaps_2 = require("./googleMaps");
|
|
39
|
+
const serp_2 = require("./serp");
|
|
35
40
|
exports.services = {
|
|
36
41
|
company: {
|
|
37
42
|
linkedin: {
|
|
43
|
+
findUrl: expansion_2.companyLinkedinFindUrl,
|
|
38
44
|
enrich: expansion_2.companyLinkedinEnrich,
|
|
39
45
|
search: b2b_2.linkedinSearch
|
|
40
46
|
},
|
|
@@ -42,8 +48,12 @@ exports.services = {
|
|
|
42
48
|
},
|
|
43
49
|
person: {
|
|
44
50
|
linkedin: {
|
|
51
|
+
findUrl: expansion_2.personLinkedinFindUrl,
|
|
45
52
|
enrich: expansion_2.personLinkedinEnrich,
|
|
46
53
|
search: b2b_2.linkedinSearch
|
|
54
|
+
},
|
|
55
|
+
contact: {
|
|
56
|
+
get: expansion_2.personContactGet
|
|
47
57
|
}
|
|
48
58
|
},
|
|
49
59
|
web: {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Gmail email sending via Google integration
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Gmail Integration
|
|
6
|
+
|
|
7
|
+
Typed functions for Gmail actions powered by Orange Slice Google integrations.
|
|
8
|
+
|
|
9
|
+
## Email
|
|
10
|
+
|
|
11
|
+
- `integrations.gmail.sendEmail(input)` - Send an email through the connected Gmail account
|
|
12
|
+
- Heavy rate limit: `sendEmail` is capped at **20 calls/day** per connected Gmail account
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# sendEmail
|
|
2
|
+
|
|
3
|
+
Send an email from the connected Gmail account.
|
|
4
|
+
|
|
5
|
+
> Rate limit note for AI: `integrations.gmail.sendEmail(...)` is heavily rate-limited to **20 calls/day** per connected Gmail account. Use sparingly and batch/aggregate where possible.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// Basic email
|
|
9
|
+
const result = await integrations.gmail.sendEmail({
|
|
10
|
+
recipient_email: "jane@example.com",
|
|
11
|
+
subject: "Hello from Orange Slice",
|
|
12
|
+
body: "Hi Jane, this is a test email."
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
// HTML email with additional recipients
|
|
16
|
+
await integrations.gmail.sendEmail({
|
|
17
|
+
recipient_email: "primary@example.com",
|
|
18
|
+
extra_recipients: ["secondary@example.com"],
|
|
19
|
+
cc: ["manager@example.com"],
|
|
20
|
+
subject: "Weekly digest",
|
|
21
|
+
body: "<h3>Weekly Digest</h3><p>Everything looks good.</p>",
|
|
22
|
+
is_html: true
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Input
|
|
27
|
+
|
|
28
|
+
| Parameter | Type | Required | Description |
|
|
29
|
+
| ------------------ | ----------- | -------- | ----------- |
|
|
30
|
+
| `recipient_email` | `string` | No\* | Primary `To` recipient |
|
|
31
|
+
| `extra_recipients` | `string[]` | No | Additional `To` recipients |
|
|
32
|
+
| `cc` | `string[]` | No | CC recipients |
|
|
33
|
+
| `bcc` | `string[]` | No | BCC recipients |
|
|
34
|
+
| `subject` | `string` | No\* | Email subject |
|
|
35
|
+
| `body` | `string` | No\* | Email body (plain text or HTML) |
|
|
36
|
+
| `is_html` | `boolean` | No | Set to `true` when body is HTML |
|
|
37
|
+
| `from_email` | `string` | No | Optional verified send-as alias |
|
|
38
|
+
| `attachment` | `object` | No | Optional attachment payload |
|
|
39
|
+
| `user_id` | `string` | No | Gmail user id (`"me"` by default) |
|
|
40
|
+
|
|
41
|
+
\*Gmail requires at least one recipient (`recipient_email`, `cc`, or `bcc`) and at least one of `subject` or `body`.
|
|
42
|
+
|
|
43
|
+
## Output
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
{
|
|
47
|
+
successful: boolean;
|
|
48
|
+
data?: unknown;
|
|
49
|
+
error?: string;
|
|
50
|
+
}
|
|
51
|
+
```
|
|
@@ -148,3 +148,27 @@ const invite = await integrations.slack.conversationsInviteShared({
|
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
See [slack/](./slack/) for all available functions.
|
|
151
|
+
|
|
152
|
+
### Gmail
|
|
153
|
+
|
|
154
|
+
Send emails from connected Google Gmail accounts.
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// Send a plain text email
|
|
158
|
+
const result = await integrations.gmail.sendEmail({
|
|
159
|
+
recipient_email: "john@example.com",
|
|
160
|
+
subject: "Quick update",
|
|
161
|
+
body: "Hey John - sharing a quick status update."
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Send HTML with CC recipients
|
|
165
|
+
await integrations.gmail.sendEmail({
|
|
166
|
+
recipient_email: "team@example.com",
|
|
167
|
+
cc: ["manager@example.com"],
|
|
168
|
+
subject: "Weekly summary",
|
|
169
|
+
body: "<h2>Weekly Summary</h2><p>All systems operational.</p>",
|
|
170
|
+
is_html: true
|
|
171
|
+
});
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
See [gmail/](./gmail/) for available functions.
|
|
@@ -216,6 +216,16 @@ type search = (params: {
|
|
|
216
216
|
}>;
|
|
217
217
|
```
|
|
218
218
|
|
|
219
|
+
## Prospecting Continuation Trigger (Get More Leads)
|
|
220
|
+
|
|
221
|
+
For **every prospecting workflow**, aggressively default to creating a continuation trigger after the initial setup so the user can get more leads and run the workflow again without rebuilding anything.
|
|
222
|
+
|
|
223
|
+
1. Read `triggers-runtime`
|
|
224
|
+
2. Create or update a continuation trigger named `Get more <topic> leads` (fallback: `Get more leads`)
|
|
225
|
+
3. Configure the trigger to continue the same prospecting strategy (next pages / additional query batches / source expansion) and run the workflow
|
|
226
|
+
|
|
227
|
+
Only skip this when the user explicitly says they do not want a continuation trigger.
|
|
228
|
+
|
|
219
229
|
---
|
|
220
230
|
|
|
221
231
|
## Examples
|
|
@@ -94,6 +94,7 @@ interface B2BPersonExperience {
|
|
|
94
94
|
company_name: string;
|
|
95
95
|
company_domain: string | null;
|
|
96
96
|
company_linkedin_url: string | null;
|
|
97
|
+
company_employee_count: number | null; // Employee count of the company
|
|
97
98
|
locality: string | null; // City/region of the job
|
|
98
99
|
start_date: string | null; // "YYYY-MM-DD"
|
|
99
100
|
start_date_year: number | null;
|