orangeslice 2.1.4 → 2.1.5
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/expansion.js +21 -10
- package/docs/integrations/hubspot/createWebhookFlow.md +137 -0
- package/docs/integrations/hubspot/index.md +8 -2
- package/docs/integrations/hubspot/updateFlow.md +13 -14
- package/docs/integrations/hubspot/updateWebhookFlow.md +52 -0
- package/docs/integrations/index.md +50 -1
- package/docs/integrations/salesforce/index.md +4 -0
- package/docs/integrations/salesforce/request.md +58 -0
- package/docs/services/ai/generateObject.ts +7 -3
- package/docs/services/ai/generateText.ts +7 -3
- package/docs/services/company/linkedin/enrich.md +0 -1
- package/docs/triggers-runtime.md +26 -5
- package/package.json +1 -1
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
|
-
|
|
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
|
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# createWebhookFlow
|
|
2
|
+
|
|
3
|
+
Create a HubSpot workflow that sends a webhook from the user's HubSpot portal.
|
|
4
|
+
|
|
5
|
+
This helper is for OAuth-authorized workflow webhooks, not HubSpot's app-level Webhooks API.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
const flow = await integrations.hubspot.createWebhookFlow({
|
|
9
|
+
name: "Orange Slice - Enrich Missing Contact Emails",
|
|
10
|
+
description: "Enroll new lead contacts missing email and send to Orange Slice",
|
|
11
|
+
objectTypeId: "0-1", // Contacts
|
|
12
|
+
webhookUrl: "https://www.orangeslice.ai/api/triggers/<trigger-id>/webhook",
|
|
13
|
+
method: "POST",
|
|
14
|
+
enrollmentCriteria: {
|
|
15
|
+
type: "EVENT_BASED",
|
|
16
|
+
shouldReEnroll: false,
|
|
17
|
+
eventFilterBranches: [
|
|
18
|
+
{
|
|
19
|
+
eventTypeId: "4-1463224", // CRM Object Created
|
|
20
|
+
operator: "HAS_COMPLETED",
|
|
21
|
+
filterBranchType: "UNIFIED_EVENTS",
|
|
22
|
+
filterBranchOperator: "AND",
|
|
23
|
+
filterBranches: [],
|
|
24
|
+
filters: []
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
listMembershipFilterBranches: [],
|
|
28
|
+
refinementCriteria: {
|
|
29
|
+
filterBranchType: "AND",
|
|
30
|
+
filterBranchOperator: "AND",
|
|
31
|
+
filterBranches: [],
|
|
32
|
+
filters: [
|
|
33
|
+
{
|
|
34
|
+
property: "lifecyclestage",
|
|
35
|
+
filterType: "PROPERTY",
|
|
36
|
+
operation: {
|
|
37
|
+
operationType: "ENUMERATION",
|
|
38
|
+
operator: "IS_ANY_OF",
|
|
39
|
+
includeObjectsWithNoValueSet: false,
|
|
40
|
+
values: ["lead"]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
property: "email",
|
|
45
|
+
filterType: "PROPERTY",
|
|
46
|
+
operation: {
|
|
47
|
+
operationType: "MULTISTRING",
|
|
48
|
+
operator: "IS_EQUAL_TO",
|
|
49
|
+
includeObjectsWithNoValueSet: true,
|
|
50
|
+
values: []
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Input
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
{
|
|
63
|
+
name?: string;
|
|
64
|
+
description?: string;
|
|
65
|
+
type?: "CONTACT_FLOW" | "PLATFORM_FLOW";
|
|
66
|
+
objectTypeId: string;
|
|
67
|
+
isEnabled?: boolean;
|
|
68
|
+
webhookActionId?: string;
|
|
69
|
+
nextAvailableActionId?: string;
|
|
70
|
+
webhookUrl: string;
|
|
71
|
+
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS" | "CONNECT" | "TRACE";
|
|
72
|
+
queryParams?: Array<{ name: string; value: any }>;
|
|
73
|
+
headers?: Array<{ name: string; value: any }>;
|
|
74
|
+
requestBody?: string | { type: "STATIC"; value: string };
|
|
75
|
+
authSettings?: {
|
|
76
|
+
type: "NONE" | "AUTH_KEY" | "SIGNATURE" | "OAUTH";
|
|
77
|
+
[key: string]: any;
|
|
78
|
+
};
|
|
79
|
+
enrollmentCriteria?: any;
|
|
80
|
+
enrollmentSchedule?: any;
|
|
81
|
+
timeWindows?: any[];
|
|
82
|
+
blockedDates?: any[];
|
|
83
|
+
suppressionListIds?: string[];
|
|
84
|
+
canEnrollFromSalesforce?: boolean;
|
|
85
|
+
customProperties?: Record<string, string>;
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Output
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
HubSpotFlow;
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Notes
|
|
96
|
+
|
|
97
|
+
This uses the HubSpot workflows API, not the app-level Webhooks API. The connected HubSpot user must authorize your app with the `automation` OAuth scope.
|
|
98
|
+
|
|
99
|
+
HubSpot's v4 workflow payload is stricter in practice than our local generated types suggest. The following details are important and were confirmed to work:
|
|
100
|
+
|
|
101
|
+
- Include top-level `flowType: "WORKFLOW"` when creating workflows via `createFlow(...)`.
|
|
102
|
+
- Use a webhook action with `type: "WEBHOOK"` rather than trying to guess an `actionTypeId`.
|
|
103
|
+
- If you pass `isEnabled: true`, this helper creates the workflow disabled first, then performs a second update call with the full workflow payload HubSpot expects for activation.
|
|
104
|
+
- HubSpot accepts a webhook action shape like:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
{
|
|
108
|
+
type: "WEBHOOK",
|
|
109
|
+
actionId: "1",
|
|
110
|
+
method: "POST",
|
|
111
|
+
webhookUrl: "https://example.com/webhook",
|
|
112
|
+
requestBody: { type: "STATIC", value: "" },
|
|
113
|
+
queryParams: [],
|
|
114
|
+
headers: [],
|
|
115
|
+
authSettings: { type: "NONE", value: null }
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
- For the contact lifecycle stage filter, use `operationType: "ENUMERATION"`.
|
|
120
|
+
- For "email is missing", HubSpot accepted:
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
{
|
|
124
|
+
property: "email",
|
|
125
|
+
filterType: "PROPERTY",
|
|
126
|
+
operation: {
|
|
127
|
+
operationType: "MULTISTRING",
|
|
128
|
+
operator: "IS_EQUAL_TO",
|
|
129
|
+
includeObjectsWithNoValueSet: true,
|
|
130
|
+
values: []
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
- The CRM Object Created event trigger is `eventTypeId: "4-1463224"`.
|
|
136
|
+
|
|
137
|
+
If the helper fails, fall back to `integrations.hubspot.createFlow(...)` with the exact working payload shape above.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: HubSpot CRM
|
|
2
|
+
description: HubSpot CRM and workflows
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# HubSpot Integration
|
|
6
6
|
|
|
7
|
-
Typed functions for HubSpot CRM operations.
|
|
7
|
+
Typed functions for HubSpot CRM operations and workflows.
|
|
8
8
|
|
|
9
9
|
## Contacts
|
|
10
10
|
|
|
@@ -39,6 +39,8 @@ Typed functions for HubSpot CRM operations.
|
|
|
39
39
|
- `integrations.hubspot.getFlow(flowId)` - Get workflow details by ID
|
|
40
40
|
- `integrations.hubspot.createFlow(input)` - Create a new workflow
|
|
41
41
|
- `integrations.hubspot.updateFlow(flowId, input)` - Update an existing workflow
|
|
42
|
+
- `integrations.hubspot.createWebhookFlow(input)` - Create a workflow containing a webhook action using OAuth `automation` scope. For advanced payloads, `createFlow(...)` may be more reliable.
|
|
43
|
+
- `integrations.hubspot.updateWebhookFlow(flowId, input)` - Update the webhook action in an existing workflow
|
|
42
44
|
- `integrations.hubspot.deleteFlow(flowId)` - Delete a workflow
|
|
43
45
|
|
|
44
46
|
## Lists
|
|
@@ -49,6 +51,10 @@ Typed functions for HubSpot CRM operations.
|
|
|
49
51
|
|
|
50
52
|
- `integrations.hubspot.listProperties(objectType, options?)` - List all property definitions for an object type
|
|
51
53
|
|
|
54
|
+
Use `createWebhookFlow` / `updateWebhookFlow` when a user authorizes your app with HubSpot OAuth and grants the `automation` scope.
|
|
55
|
+
|
|
56
|
+
In practice, HubSpot's workflows v4 API may require extra top-level fields such as `flowType`, `nextAvailableActionId`, and `crmObjectCreationStatus`, plus a strict `WEBHOOK` action payload. See `createWebhookFlow.md` for the currently working payload shape.
|
|
57
|
+
|
|
52
58
|
## Owners
|
|
53
59
|
|
|
54
60
|
- `integrations.hubspot.listOwners(options?)` - List all owners (users) with pagination
|
|
@@ -3,12 +3,7 @@
|
|
|
3
3
|
Update an existing workflow.
|
|
4
4
|
|
|
5
5
|
```typescript
|
|
6
|
-
// First get the current flow to obtain revisionId
|
|
7
|
-
const currentFlow = await integrations.hubspot.getFlow("12345678");
|
|
8
|
-
|
|
9
|
-
// Update the flow
|
|
10
6
|
const updatedFlow = await integrations.hubspot.updateFlow("12345678", {
|
|
11
|
-
revisionId: currentFlow.revisionId,
|
|
12
7
|
name: "Updated Workflow Name",
|
|
13
8
|
isEnabled: true
|
|
14
9
|
});
|
|
@@ -16,15 +11,15 @@ const updatedFlow = await integrations.hubspot.updateFlow("12345678", {
|
|
|
16
11
|
|
|
17
12
|
## Input
|
|
18
13
|
|
|
19
|
-
| Parameter | Type | Description
|
|
20
|
-
| -------------------------- | ----------- |
|
|
21
|
-
| `flowId` | `string` | The ID of the workflow to update
|
|
22
|
-
| `input.revisionId` | `string` |
|
|
23
|
-
| `input.name` | `string` | Updated name
|
|
24
|
-
| `input.description` | `string` | Updated description
|
|
25
|
-
| `input.isEnabled` | `boolean` | Enable/disable the workflow
|
|
26
|
-
| `input.actions` | `unknown[]` | Updated workflow actions
|
|
27
|
-
| `input.enrollmentCriteria` | `unknown` | Updated enrollment criteria
|
|
14
|
+
| Parameter | Type | Description |
|
|
15
|
+
| -------------------------- | ----------- | ---------------------------------------------------------------------------------- |
|
|
16
|
+
| `flowId` | `string` | The ID of the workflow to update |
|
|
17
|
+
| `input.revisionId` | `string` | Optional current revision ID. If omitted, the helper fetches the latest flow first |
|
|
18
|
+
| `input.name` | `string` | Updated name |
|
|
19
|
+
| `input.description` | `string` | Updated description |
|
|
20
|
+
| `input.isEnabled` | `boolean` | Enable/disable the workflow |
|
|
21
|
+
| `input.actions` | `unknown[]` | Updated workflow actions |
|
|
22
|
+
| `input.enrollmentCriteria` | `unknown` | Updated enrollment criteria |
|
|
28
23
|
|
|
29
24
|
## Output
|
|
30
25
|
|
|
@@ -43,3 +38,7 @@ Returns the updated workflow object.
|
|
|
43
38
|
updatedAt: string;
|
|
44
39
|
}
|
|
45
40
|
```
|
|
41
|
+
|
|
42
|
+
## Notes
|
|
43
|
+
|
|
44
|
+
This helper now fetches the current workflow and preserves HubSpot-required top-level fields such as `type`, `objectTypeId`, `flowType`, `nextAvailableActionId`, and `crmObjectCreationStatus` before sending the update request.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# updateWebhookFlow
|
|
2
|
+
|
|
3
|
+
Update the webhook action in an existing HubSpot workflow.
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
const updated = await integrations.hubspot.updateWebhookFlow("12345678", {
|
|
7
|
+
webhookUrl: "https://example.com/webhooks/hubspot/v2",
|
|
8
|
+
isEnabled: true
|
|
9
|
+
});
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Input
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
flowId: string
|
|
16
|
+
|
|
17
|
+
input: {
|
|
18
|
+
name?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
isEnabled?: boolean;
|
|
21
|
+
webhookUrl?: string;
|
|
22
|
+
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS" | "CONNECT" | "TRACE";
|
|
23
|
+
queryParams?: Array<{ name: string; value: any }>;
|
|
24
|
+
headers?: Array<{ name: string; value: any }>;
|
|
25
|
+
requestBody?: string;
|
|
26
|
+
authSettings?: {
|
|
27
|
+
type: "AUTH_KEY" | "SIGNATURE" | "OAUTH";
|
|
28
|
+
[key: string]: any;
|
|
29
|
+
};
|
|
30
|
+
enrollmentCriteria?: any;
|
|
31
|
+
enrollmentSchedule?: any;
|
|
32
|
+
timeWindows?: any[];
|
|
33
|
+
blockedDates?: any[];
|
|
34
|
+
suppressionListIds?: string[];
|
|
35
|
+
canEnrollFromSalesforce?: boolean;
|
|
36
|
+
customProperties?: Record<string, string>;
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Output
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
HubSpotFlow;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Notes
|
|
47
|
+
|
|
48
|
+
This helper fetches the current workflow, preserves its existing revision and non-webhook settings, and updates the first webhook action it finds.
|
|
49
|
+
|
|
50
|
+
When working with HubSpot workflow webhooks, prefer preserving any existing top-level workflow fields such as `flowType`, `nextAvailableActionId`, and `crmObjectCreationStatus`. HubSpot's v4 workflow API is sensitive to omitted fields during updates.
|
|
51
|
+
|
|
52
|
+
This helper now preserves those top-level workflow fields automatically before sending the `updateFlow(...)` request.
|
|
@@ -6,7 +6,7 @@ Access external APIs through `integrations.<provider>.<function>()`.
|
|
|
6
6
|
|
|
7
7
|
### HubSpot
|
|
8
8
|
|
|
9
|
-
CRM operations
|
|
9
|
+
CRM operations plus workflows.
|
|
10
10
|
|
|
11
11
|
```typescript
|
|
12
12
|
// Create a contact
|
|
@@ -22,6 +22,55 @@ const deals = await integrations.hubspot.searchDeals({
|
|
|
22
22
|
}
|
|
23
23
|
]
|
|
24
24
|
});
|
|
25
|
+
|
|
26
|
+
// Create a workflow that sends a webhook from the user's HubSpot portal
|
|
27
|
+
await integrations.hubspot.createWebhookFlow({
|
|
28
|
+
name: "Orange Slice - Enrich Missing Contact Emails",
|
|
29
|
+
objectTypeId: "0-1",
|
|
30
|
+
webhookUrl: "https://www.orangeslice.ai/api/triggers/<trigger-id>/webhook",
|
|
31
|
+
enrollmentCriteria: {
|
|
32
|
+
type: "EVENT_BASED",
|
|
33
|
+
shouldReEnroll: false,
|
|
34
|
+
eventFilterBranches: [
|
|
35
|
+
{
|
|
36
|
+
eventTypeId: "4-1463224",
|
|
37
|
+
operator: "HAS_COMPLETED",
|
|
38
|
+
filterBranchType: "UNIFIED_EVENTS",
|
|
39
|
+
filterBranchOperator: "AND",
|
|
40
|
+
filterBranches: [],
|
|
41
|
+
filters: []
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
listMembershipFilterBranches: [],
|
|
45
|
+
refinementCriteria: {
|
|
46
|
+
filterBranchType: "AND",
|
|
47
|
+
filterBranchOperator: "AND",
|
|
48
|
+
filterBranches: [],
|
|
49
|
+
filters: [
|
|
50
|
+
{
|
|
51
|
+
property: "lifecyclestage",
|
|
52
|
+
filterType: "PROPERTY",
|
|
53
|
+
operation: {
|
|
54
|
+
operationType: "ENUMERATION",
|
|
55
|
+
operator: "IS_ANY_OF",
|
|
56
|
+
includeObjectsWithNoValueSet: false,
|
|
57
|
+
values: ["lead"]
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
property: "email",
|
|
62
|
+
filterType: "PROPERTY",
|
|
63
|
+
operation: {
|
|
64
|
+
operationType: "MULTISTRING",
|
|
65
|
+
operator: "IS_EQUAL_TO",
|
|
66
|
+
includeObjectsWithNoValueSet: true,
|
|
67
|
+
values: []
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
25
74
|
```
|
|
26
75
|
|
|
27
76
|
See [hubspot/](./hubspot/) for all available functions.
|
|
@@ -25,6 +25,10 @@ Typed functions for Salesforce CRM operations using SOQL queries and the REST AP
|
|
|
25
25
|
- `integrations.salesforce.describeGlobal()` - List all available SObjects
|
|
26
26
|
- `integrations.salesforce.describeSObject(sobject)` - Get schema for an SObject
|
|
27
27
|
|
|
28
|
+
## Generic Request Operations
|
|
29
|
+
|
|
30
|
+
- `integrations.salesforce.request(input)` - Make an authenticated request to any Salesforce endpoint
|
|
31
|
+
|
|
28
32
|
## Collection/Batch Operations
|
|
29
33
|
|
|
30
34
|
- `integrations.salesforce.createRecords(input)` - Create up to 200 records
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const result = await integrations.salesforce.request({
|
|
2
|
+
path: "/services/data/v62.0/actions/standard",
|
|
3
|
+
});
|
|
4
|
+
|
|
5
|
+
const compositeResult = await integrations.salesforce.request({
|
|
6
|
+
method: "POST",
|
|
7
|
+
path: "/services/data/v62.0/composite/",
|
|
8
|
+
body: {
|
|
9
|
+
allOrNone: true,
|
|
10
|
+
compositeRequest: [
|
|
11
|
+
{
|
|
12
|
+
method: "GET",
|
|
13
|
+
url: "/services/data/v62.0/sobjects/Lead/00Qxx000001abcDEAY",
|
|
14
|
+
referenceId: "lead"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const apexResult = await integrations.salesforce.request({
|
|
23
|
+
method: "POST",
|
|
24
|
+
path: "/services/apexrest/leadconvert/00Qxx000001abcDEAY",
|
|
25
|
+
body: {
|
|
26
|
+
doNotCreateOpportunity: true
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
Use `request()` when Salesforce has an endpoint that Orange Slice does not expose as a first-class helper.
|
|
31
|
+
|
|
32
|
+
## Input
|
|
33
|
+
|
|
34
|
+
| Field | Type | Required | Description |
|
|
35
|
+
| --------- | ------------------------------------------------------------------ | -------- | -------------------------------------------------------- |
|
|
36
|
+
| `path` | `string` | Yes | Absolute URL or instance-relative path starting with `/` |
|
|
37
|
+
| `method` | `"GET" \| "POST" \| "PUT" \| "PATCH" \| "DELETE"` | No | HTTP method. Defaults to `GET` |
|
|
38
|
+
| `query` | `Record<string, string \| number \| boolean \| null \| undefined>` | No | Query params appended to the URL |
|
|
39
|
+
| `headers` | `Record<string, string>` | No | Additional request headers |
|
|
40
|
+
| `body` | `unknown` | No | Request body. Objects are JSON-stringified automatically |
|
|
41
|
+
|
|
42
|
+
## Response
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
{
|
|
48
|
+
status: number;
|
|
49
|
+
headers: Record<string, string>;
|
|
50
|
+
data: unknown;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Notes
|
|
55
|
+
|
|
56
|
+
- OAuth and the Salesforce instance URL are handled automatically.
|
|
57
|
+
- `path` must be a full URL or start with `/`.
|
|
58
|
+
- This is the escape hatch for non-CRUD Salesforce APIs such as Apex REST, composite APIs, quick actions, and other special endpoints.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Credits: 1 (
|
|
1
|
+
/** Credits: 1 (low) or 10 (medium) */
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Generate an object using AI.
|
|
@@ -17,12 +17,16 @@
|
|
|
17
17
|
* for each one individually. The runtime handles parallelization for you.
|
|
18
18
|
*
|
|
19
19
|
* The field will be present in the output but can have a null value when the AI has no data.
|
|
20
|
+
*
|
|
21
|
+
* Intelligence guidance:
|
|
22
|
+
* - Prefer `low` for classification, tagging, extraction, normalization, and other constrained schema-filling tasks.
|
|
23
|
+
* - Prefer `medium` for more nuanced generation quality, like writing outreach hooks, personalized messaging, or other higher-judgment copy that still returns structured fields.
|
|
20
24
|
*/
|
|
21
25
|
type generateObject = (params: {
|
|
22
26
|
/** The prompt to generate the object from */
|
|
23
27
|
prompt: string;
|
|
24
28
|
/** A JSON schema object describing the output shape */
|
|
25
29
|
schema: any;
|
|
26
|
-
/** Optional
|
|
27
|
-
|
|
30
|
+
/** Optional intelligence level. Defaults to "low" (gpt-5-mini, 1 credit). Prefer `low` for classification/extraction and `medium` for higher-quality writing tasks like outreach (gemini-3-flash-preview, 10 credits). */
|
|
31
|
+
intelligence?: "low" | "medium";
|
|
28
32
|
}) => Promise<{ object: Record<string, any> }>;
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
/** Credits: 1 (
|
|
1
|
+
/** Credits: 1 (low) or 10 (medium) */
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Generate text using AI, optionally with web search.
|
|
5
5
|
* IMPORTANT: Always incorporate the user's guidelines (i.e. no fabrication, writing style, format) into your prompt. See index.md.
|
|
6
|
+
*
|
|
7
|
+
* Intelligence guidance:
|
|
8
|
+
* - Prefer `low` for classification-like prompts, terse transformations, extraction-adjacent formatting, and other constrained text tasks.
|
|
9
|
+
* - Prefer `medium` for higher-quality writing tasks like outreach, hooks, personalized messaging, and nuanced copy generation.
|
|
6
10
|
*/
|
|
7
11
|
type generateText = (params: {
|
|
8
12
|
/** The prompt to generate the text from */
|
|
9
13
|
prompt: string;
|
|
10
14
|
/** Whether to enable web search */
|
|
11
15
|
enableWebSearch?: boolean;
|
|
12
|
-
/** Optional
|
|
13
|
-
|
|
16
|
+
/** Optional intelligence level. Defaults to "low" (gpt-5-mini, 1 credit). Prefer `low` for constrained text tasks and `medium` for higher-quality writing like outreach (gemini-3-flash-preview, 10 credits). */
|
|
17
|
+
intelligence?: "low" | "medium";
|
|
14
18
|
}) => Promise<{ text: string }>;
|
|
@@ -49,7 +49,6 @@ interface B2BCompany {
|
|
|
49
49
|
company_size: string | null; // Size range label
|
|
50
50
|
ticker: string | null; // Stock ticker
|
|
51
51
|
logo: string | null; // Logo URL
|
|
52
|
-
specialties: string[] | null; // Company specialties
|
|
53
52
|
twitter_handle: string | null; // Twitter handle
|
|
54
53
|
linkedin_url: string | null; // Full LinkedIn URL
|
|
55
54
|
created_at: string | null; // Record created timestamp
|
package/docs/triggers-runtime.md
CHANGED
|
@@ -5,11 +5,21 @@ description: Trigger mental model + runtime API + webhook shape access. Read bef
|
|
|
5
5
|
|
|
6
6
|
# Triggers Runtime (Agent)
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Core Rule: Triggers Push Data, Columns Do Work
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
**Triggers are thin data ingesters, NOT processing engines.** Push bare minimum data into rows; all enrichment, AI, scoring, and transformation belongs in code columns.
|
|
11
|
+
|
|
12
|
+
The spreadsheet is a live workspace, not a log. Columns make work visible, debuggable, retryable per-row, and composable across data sources. Processing inside triggers hides failures in run logs.
|
|
13
|
+
|
|
14
|
+
**Trigger code should only:**
|
|
15
|
+
|
|
16
|
+
- Parse/extract fields from `ctx.trigger.payload`
|
|
17
|
+
- Light dedup (`SELECT` to check if row exists)
|
|
18
|
+
- `addRows()` with raw data + `{ run: true }` to kick off columns
|
|
19
|
+
- Paginate via self-invocation for large ingestion
|
|
20
|
+
- Route to the right sheet based on payload type
|
|
21
|
+
|
|
22
|
+
**Never put in trigger code:** `services.*` enrichment, AI calls, scoring, or per-row transformation loops — the sheet IS the loop.
|
|
13
23
|
|
|
14
24
|
## Webhook Data Model (from DB schema)
|
|
15
25
|
|
|
@@ -175,11 +185,22 @@ interface Ctx {
|
|
|
175
185
|
## Minimal Example
|
|
176
186
|
|
|
177
187
|
```ts
|
|
188
|
+
// Inspect recent webhook payloads to understand shape
|
|
178
189
|
const t = await ctx.triggers.byName("Inbound Lead Webhook");
|
|
179
190
|
const recent = await t.webhooks.list({ limit: 10 });
|
|
180
191
|
const samplePayload = recent[0]?.payload;
|
|
181
192
|
|
|
193
|
+
// Trigger code: push minimal data, let columns do the work
|
|
182
194
|
await t.update({
|
|
183
|
-
code: `
|
|
195
|
+
code: `
|
|
196
|
+
const leads = Array.isArray(ctx.trigger.payload) ? ctx.trigger.payload : [ctx.trigger.payload];
|
|
197
|
+
const sheet = await ctx.sheet("Inbound Leads");
|
|
198
|
+
await sheet.addRows(
|
|
199
|
+
leads.map(l => ({ "Name": l.name, "Email": l.email, "Source": "webhook" })),
|
|
200
|
+
{ run: true }
|
|
201
|
+
);
|
|
202
|
+
return { pushed: leads.length };
|
|
203
|
+
`
|
|
184
204
|
});
|
|
205
|
+
// Then create enrichment columns on "Inbound Leads" to do the actual work
|
|
185
206
|
```
|