runline 0.1.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/.pi/extensions/runline-context/index.ts +135 -0
- package/.pi/extensions/runline-context/package.json +17 -0
- package/README.md +273 -0
- package/dist/commands/actions.d.ts +3 -0
- package/dist/commands/actions.js +43 -0
- package/dist/commands/connection.d.ts +11 -0
- package/dist/commands/connection.js +56 -0
- package/dist/commands/exec.d.ts +5 -0
- package/dist/commands/exec.js +46 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +26 -0
- package/dist/commands/plugin.d.ts +10 -0
- package/dist/commands/plugin.js +57 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.js +2 -0
- package/dist/config/loader.d.ts +11 -0
- package/dist/config/loader.js +82 -0
- package/dist/config/types.d.ts +9 -0
- package/dist/config/types.js +5 -0
- package/dist/core/engine.d.ts +21 -0
- package/dist/core/engine.js +280 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +9 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +127 -0
- package/dist/plugin/api.d.ts +32 -0
- package/dist/plugin/api.js +68 -0
- package/dist/plugin/installer.d.ts +27 -0
- package/dist/plugin/installer.js +181 -0
- package/dist/plugin/loader.d.ts +13 -0
- package/dist/plugin/loader.js +164 -0
- package/dist/plugin/registry.d.ts +18 -0
- package/dist/plugin/registry.js +43 -0
- package/dist/plugin/types.d.ts +40 -0
- package/dist/plugin/types.js +1 -0
- package/dist/plugins/actionNetwork/src/index.js +353 -0
- package/dist/plugins/activeCampaign/src/index.js +711 -0
- package/dist/plugins/adalo/src/index.js +131 -0
- package/dist/plugins/affinity/src/index.js +279 -0
- package/dist/plugins/agileCrm/src/index.js +415 -0
- package/dist/plugins/airtable/src/index.js +280 -0
- package/dist/plugins/airtop/src/index.js +527 -0
- package/dist/plugins/apiTemplateIo/src/index.js +86 -0
- package/dist/plugins/asana/src/index.js +413 -0
- package/dist/plugins/autopilot/src/index.js +203 -0
- package/dist/plugins/bambooHr/src/index.js +252 -0
- package/dist/plugins/bannerbear/src/index.js +100 -0
- package/dist/plugins/baserow/src/index.js +180 -0
- package/dist/plugins/beeminder/src/index.js +298 -0
- package/dist/plugins/bitly/src/index.js +107 -0
- package/dist/plugins/bitwarden/src/index.js +383 -0
- package/dist/plugins/box/src/index.js +300 -0
- package/dist/plugins/brandfetch/src/index.js +80 -0
- package/dist/plugins/brevo/src/index.js +305 -0
- package/dist/plugins/bubble/src/index.js +181 -0
- package/dist/plugins/chargebee/src/index.js +126 -0
- package/dist/plugins/circleci/src/index.js +111 -0
- package/dist/plugins/ciscoWebex/src/index.js +245 -0
- package/dist/plugins/clearbit/src/index.js +103 -0
- package/dist/plugins/clickup/src/index.js +1043 -0
- package/dist/plugins/clockify/src/index.js +443 -0
- package/dist/plugins/cloudflare/src/index.js +93 -0
- package/dist/plugins/cockpit/src/index.js +131 -0
- package/dist/plugins/coda/src/index.js +327 -0
- package/dist/plugins/coingecko/src/index.js +244 -0
- package/dist/plugins/contentful/src/index.js +146 -0
- package/dist/plugins/convertkit/src/index.js +270 -0
- package/dist/plugins/copper/src/index.js +140 -0
- package/dist/plugins/cortex/src/index.js +147 -0
- package/dist/plugins/currents/src/index.js +405 -0
- package/dist/plugins/customerIo/src/index.js +184 -0
- package/dist/plugins/databricks/src/index.js +342 -0
- package/dist/plugins/deepl/src/index.js +87 -0
- package/dist/plugins/demio/src/index.js +111 -0
- package/dist/plugins/dhl/src/index.js +40 -0
- package/dist/plugins/discord/src/index.js +275 -0
- package/dist/plugins/discourse/src/index.js +273 -0
- package/dist/plugins/disqus/src/index.js +145 -0
- package/dist/plugins/docker/src/index.js +76 -0
- package/dist/plugins/drift/src/index.js +89 -0
- package/dist/plugins/dropbox/src/index.js +159 -0
- package/dist/plugins/dropcontact/src/index.js +59 -0
- package/dist/plugins/egoi/src/index.js +151 -0
- package/dist/plugins/elasticsearch/src/index.js +157 -0
- package/dist/plugins/emelia/src/index.js +174 -0
- package/dist/plugins/erpnext/src/index.js +121 -0
- package/dist/plugins/facebookGraph/src/index.js +57 -0
- package/dist/plugins/freshdesk/src/index.js +320 -0
- package/dist/plugins/freshservice/src/index.js +146 -0
- package/dist/plugins/freshworksCrm/src/index.js +149 -0
- package/dist/plugins/getresponse/src/index.js +140 -0
- package/dist/plugins/ghost/src/index.js +192 -0
- package/dist/plugins/github/src/index.js +630 -0
- package/dist/plugins/gitlab/src/index.js +358 -0
- package/dist/plugins/gong/src/index.js +126 -0
- package/dist/plugins/gotify/src/index.js +77 -0
- package/dist/plugins/gotowebinar/src/index.js +316 -0
- package/dist/plugins/grafana/src/index.js +250 -0
- package/dist/plugins/graphql/src/index.js +78 -0
- package/dist/plugins/grist/src/index.js +106 -0
- package/dist/plugins/hackernews/src/index.js +89 -0
- package/dist/plugins/halopsa/src/index.js +79 -0
- package/dist/plugins/harvest/src/index.js +163 -0
- package/dist/plugins/helpscout/src/index.js +176 -0
- package/dist/plugins/highlevel/src/index.js +172 -0
- package/dist/plugins/homeAssistant/src/index.js +148 -0
- package/dist/plugins/hubspot/src/index.js +176 -0
- package/dist/plugins/humanticAi/src/index.js +60 -0
- package/dist/plugins/hunter/src/index.js +59 -0
- package/dist/plugins/intercom/src/index.js +156 -0
- package/dist/plugins/iterable/src/index.js +139 -0
- package/dist/plugins/jenkins/src/index.js +132 -0
- package/dist/plugins/jira/src/index.js +229 -0
- package/dist/plugins/keap/src/index.js +502 -0
- package/dist/plugins/kobotoolbox/src/index.js +281 -0
- package/dist/plugins/lemlist/src/index.js +231 -0
- package/dist/plugins/linear/src/index.js +133 -0
- package/dist/plugins/lingvanex/src/index.js +31 -0
- package/dist/plugins/linkedin/src/index.js +80 -0
- package/dist/plugins/lonescale/src/index.js +119 -0
- package/dist/plugins/magento/src/index.js +300 -0
- package/dist/plugins/mailcheck/src/index.js +27 -0
- package/dist/plugins/mailchimp/src/index.js +321 -0
- package/dist/plugins/mailerlite/src/index.js +123 -0
- package/dist/plugins/mailgun/src/index.js +48 -0
- package/dist/plugins/mailjet/src/index.js +155 -0
- package/dist/plugins/mandrill/src/index.js +145 -0
- package/dist/plugins/marketstack/src/index.js +97 -0
- package/dist/plugins/matrix/src/index.js +194 -0
- package/dist/plugins/mattermost/src/index.js +331 -0
- package/dist/plugins/mautic/src/index.js +311 -0
- package/dist/plugins/medium/src/index.js +77 -0
- package/dist/plugins/messagebird/src/index.js +57 -0
- package/dist/plugins/metabase/src/index.js +130 -0
- package/dist/plugins/misp/src/index.js +476 -0
- package/dist/plugins/mocean/src/index.js +67 -0
- package/dist/plugins/monday/src/index.js +231 -0
- package/dist/plugins/monicaCrm/src/index.js +52 -0
- package/dist/plugins/msg91/src/index.js +31 -0
- package/dist/plugins/nasa/src/index.js +146 -0
- package/dist/plugins/netlify/src/index.js +151 -0
- package/dist/plugins/netscalerAdc/src/index.js +131 -0
- package/dist/plugins/nextcloud/src/index.js +263 -0
- package/dist/plugins/nocodb/src/index.js +130 -0
- package/dist/plugins/notion/src/index.js +112 -0
- package/dist/plugins/npm/src/index.js +104 -0
- package/dist/plugins/odoo/src/index.js +157 -0
- package/dist/plugins/okta/src/index.js +141 -0
- package/dist/plugins/oneSimpleApi/src/index.js +155 -0
- package/dist/plugins/onfleet/src/index.js +254 -0
- package/dist/plugins/openThesaurus/src/index.js +32 -0
- package/dist/plugins/openweathermap/src/index.js +60 -0
- package/dist/plugins/oura/src/index.js +62 -0
- package/dist/plugins/paddle/src/index.js +247 -0
- package/dist/plugins/pagerduty/src/index.js +201 -0
- package/dist/plugins/paypal/src/index.js +106 -0
- package/dist/plugins/peekalink/src/index.js +35 -0
- package/dist/plugins/phantombuster/src/index.js +94 -0
- package/dist/plugins/philipsHue/src/index.js +98 -0
- package/dist/plugins/pipedrive/src/index.js +169 -0
- package/dist/plugins/plivo/src/index.js +66 -0
- package/dist/plugins/postbin/src/index.js +93 -0
- package/dist/plugins/posthog/src/index.js +113 -0
- package/dist/plugins/profitwell/src/index.js +50 -0
- package/dist/plugins/pushbullet/src/index.js +102 -0
- package/dist/plugins/pushcut/src/index.js +39 -0
- package/dist/plugins/pushover/src/index.js +65 -0
- package/dist/plugins/quickbase/src/index.js +153 -0
- package/dist/plugins/quickbooks/src/index.js +73 -0
- package/dist/plugins/quickchart/src/index.js +36 -0
- package/dist/plugins/raindrop/src/index.js +209 -0
- package/dist/plugins/reddit/src/index.js +185 -0
- package/dist/plugins/rocketchat/src/index.js +53 -0
- package/dist/plugins/rundeck/src/index.js +62 -0
- package/dist/plugins/salesforce/src/index.js +94 -0
- package/dist/plugins/salesmate/src/index.js +83 -0
- package/dist/plugins/securityScorecard/src/index.js +200 -0
- package/dist/plugins/segment/src/index.js +125 -0
- package/dist/plugins/sendgrid/src/index.js +187 -0
- package/dist/plugins/sendy/src/index.js +138 -0
- package/dist/plugins/sentry/src/index.js +233 -0
- package/dist/plugins/servicenow/src/index.js +108 -0
- package/dist/plugins/shopify/src/index.js +222 -0
- package/dist/plugins/signl4/src/index.js +61 -0
- package/dist/plugins/slack/src/index.js +236 -0
- package/dist/plugins/sms77/src/index.js +63 -0
- package/dist/plugins/splunk/src/index.js +207 -0
- package/dist/plugins/spotify/src/index.js +188 -0
- package/dist/plugins/stackby/src/index.js +82 -0
- package/dist/plugins/storyblok/src/index.js +141 -0
- package/dist/plugins/strapi/src/index.js +152 -0
- package/dist/plugins/strava/src/index.js +137 -0
- package/dist/plugins/stripe/src/index.js +222 -0
- package/dist/plugins/supabase/src/index.js +121 -0
- package/dist/plugins/syncromsp/src/index.js +255 -0
- package/dist/plugins/tapfiliate/src/index.js +125 -0
- package/dist/plugins/telegram/src/index.js +233 -0
- package/dist/plugins/thehive/src/index.js +142 -0
- package/dist/plugins/thehiveProject/src/index.js +194 -0
- package/dist/plugins/todoist/src/index.js +244 -0
- package/dist/plugins/travisci/src/index.js +71 -0
- package/dist/plugins/trello/src/index.js +341 -0
- package/dist/plugins/twake/src/index.js +40 -0
- package/dist/plugins/twilio/src/index.js +75 -0
- package/dist/plugins/twist/src/index.js +90 -0
- package/dist/plugins/twitter/src/index.js +123 -0
- package/dist/plugins/unleashedSoftware/src/index.js +84 -0
- package/dist/plugins/uplead/src/index.js +59 -0
- package/dist/plugins/uproc/src/index.js +34 -0
- package/dist/plugins/uptimerobot/src/index.js +264 -0
- package/dist/plugins/urlscanio/src/index.js +64 -0
- package/dist/plugins/vero/src/index.js +80 -0
- package/dist/plugins/vonage/src/index.js +42 -0
- package/dist/plugins/wekan/src/index.js +91 -0
- package/dist/plugins/woocommerce/src/index.js +92 -0
- package/dist/plugins/wordpress/src/index.js +121 -0
- package/dist/plugins/xero/src/index.js +136 -0
- package/dist/plugins/yourls/src/index.js +56 -0
- package/dist/plugins/zammad/src/index.js +91 -0
- package/dist/plugins/zendesk/src/index.js +137 -0
- package/dist/plugins/zoho/src/index.js +85 -0
- package/dist/plugins/zoom/src/index.js +122 -0
- package/dist/plugins/zulip/src/index.js +170 -0
- package/dist/sdk.d.ts +38 -0
- package/dist/sdk.js +105 -0
- package/dist/utils/cli.d.ts +13 -0
- package/dist/utils/cli.js +32 -0
- package/dist/utils/output.d.ts +4 -0
- package/dist/utils/output.js +13 -0
- package/package.json +57 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
const API_URL = "https://api.dropboxapi.com/2";
|
|
2
|
+
async function apiRequest(token, endpoint, body) {
|
|
3
|
+
const res = await fetch(`${API_URL}${endpoint}`, {
|
|
4
|
+
method: "POST",
|
|
5
|
+
headers: {
|
|
6
|
+
Authorization: `Bearer ${token}`,
|
|
7
|
+
"Content-Type": "application/json",
|
|
8
|
+
},
|
|
9
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
10
|
+
});
|
|
11
|
+
if (!res.ok)
|
|
12
|
+
throw new Error(`Dropbox API error ${res.status}: ${await res.text()}`);
|
|
13
|
+
const ct = res.headers.get("content-type") ?? "";
|
|
14
|
+
if (ct.includes("application/json"))
|
|
15
|
+
return res.json();
|
|
16
|
+
return { success: true };
|
|
17
|
+
}
|
|
18
|
+
async function paginateFolder(token, path, opts, limit) {
|
|
19
|
+
const results = [];
|
|
20
|
+
const body = { path, limit: 1000, ...opts };
|
|
21
|
+
let data = (await apiRequest(token, "/files/list_folder", body));
|
|
22
|
+
results.push(...data.entries);
|
|
23
|
+
while (data.has_more && (!limit || results.length < limit)) {
|
|
24
|
+
data = (await apiRequest(token, "/files/list_folder/continue", { cursor: data.cursor }));
|
|
25
|
+
results.push(...data.entries);
|
|
26
|
+
}
|
|
27
|
+
return limit ? results.slice(0, limit) : results;
|
|
28
|
+
}
|
|
29
|
+
async function paginateSearch(token, query, opts, limit) {
|
|
30
|
+
const results = [];
|
|
31
|
+
const body = { query, options: { filename_only: true, ...opts } };
|
|
32
|
+
if (limit)
|
|
33
|
+
body.options.max_results = Math.min(limit, 1000);
|
|
34
|
+
let data = (await apiRequest(token, "/files/search_v2", body));
|
|
35
|
+
results.push(...data.matches);
|
|
36
|
+
while (data.has_more && (!limit || results.length < limit)) {
|
|
37
|
+
data = (await apiRequest(token, "/files/search/continue_v2", { cursor: data.cursor }));
|
|
38
|
+
results.push(...data.matches);
|
|
39
|
+
}
|
|
40
|
+
return limit ? results.slice(0, limit) : results;
|
|
41
|
+
}
|
|
42
|
+
export default function dropbox(rl) {
|
|
43
|
+
rl.setName("dropbox");
|
|
44
|
+
rl.setVersion("0.1.0");
|
|
45
|
+
rl.setConnectionSchema({
|
|
46
|
+
accessToken: { type: "string", required: true, description: "Dropbox access token", env: "DROPBOX_ACCESS_TOKEN" },
|
|
47
|
+
});
|
|
48
|
+
const tok = (ctx) => ctx.connection.config.accessToken;
|
|
49
|
+
// ── File ────────────────────────────────────────────
|
|
50
|
+
rl.registerAction("file.copy", {
|
|
51
|
+
description: "Copy a file",
|
|
52
|
+
inputSchema: {
|
|
53
|
+
fromPath: { type: "string", required: true, description: "Source file path" },
|
|
54
|
+
toPath: { type: "string", required: true, description: "Destination file path" },
|
|
55
|
+
},
|
|
56
|
+
async execute(input, ctx) {
|
|
57
|
+
const { fromPath, toPath } = input;
|
|
58
|
+
return apiRequest(tok(ctx), "/files/copy_v2", { from_path: fromPath, to_path: toPath });
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
rl.registerAction("file.move", {
|
|
62
|
+
description: "Move a file",
|
|
63
|
+
inputSchema: {
|
|
64
|
+
fromPath: { type: "string", required: true, description: "Source file path" },
|
|
65
|
+
toPath: { type: "string", required: true, description: "Destination file path" },
|
|
66
|
+
},
|
|
67
|
+
async execute(input, ctx) {
|
|
68
|
+
const { fromPath, toPath } = input;
|
|
69
|
+
return apiRequest(tok(ctx), "/files/move_v2", { from_path: fromPath, to_path: toPath });
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
rl.registerAction("file.delete", {
|
|
73
|
+
description: "Delete a file",
|
|
74
|
+
inputSchema: { path: { type: "string", required: true, description: "File path to delete" } },
|
|
75
|
+
async execute(input, ctx) {
|
|
76
|
+
return apiRequest(tok(ctx), "/files/delete_v2", { path: input.path });
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
// ── Folder ──────────────────────────────────────────
|
|
80
|
+
rl.registerAction("folder.create", {
|
|
81
|
+
description: "Create a folder",
|
|
82
|
+
inputSchema: { path: { type: "string", required: true, description: "Folder path to create" } },
|
|
83
|
+
async execute(input, ctx) {
|
|
84
|
+
return apiRequest(tok(ctx), "/files/create_folder_v2", { path: input.path });
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
rl.registerAction("folder.list", {
|
|
88
|
+
description: "List contents of a folder",
|
|
89
|
+
inputSchema: {
|
|
90
|
+
path: { type: "string", required: true, description: "Folder path (empty string for root)" },
|
|
91
|
+
limit: { type: "number", required: false, description: "Max results" },
|
|
92
|
+
recursive: { type: "boolean", required: false, description: "Include subfolders recursively" },
|
|
93
|
+
includeDeleted: { type: "boolean", required: false, description: "Include deleted entries" },
|
|
94
|
+
},
|
|
95
|
+
async execute(input, ctx) {
|
|
96
|
+
const { path, limit, recursive, includeDeleted } = (input ?? {});
|
|
97
|
+
const opts = {};
|
|
98
|
+
if (recursive)
|
|
99
|
+
opts.recursive = true;
|
|
100
|
+
if (includeDeleted)
|
|
101
|
+
opts.include_deleted = true;
|
|
102
|
+
return paginateFolder(tok(ctx), path, opts, limit);
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
rl.registerAction("folder.copy", {
|
|
106
|
+
description: "Copy a folder",
|
|
107
|
+
inputSchema: {
|
|
108
|
+
fromPath: { type: "string", required: true, description: "Source folder path" },
|
|
109
|
+
toPath: { type: "string", required: true, description: "Destination folder path" },
|
|
110
|
+
},
|
|
111
|
+
async execute(input, ctx) {
|
|
112
|
+
const { fromPath, toPath } = input;
|
|
113
|
+
return apiRequest(tok(ctx), "/files/copy_v2", { from_path: fromPath, to_path: toPath });
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
rl.registerAction("folder.move", {
|
|
117
|
+
description: "Move a folder",
|
|
118
|
+
inputSchema: {
|
|
119
|
+
fromPath: { type: "string", required: true, description: "Source folder path" },
|
|
120
|
+
toPath: { type: "string", required: true, description: "Destination folder path" },
|
|
121
|
+
},
|
|
122
|
+
async execute(input, ctx) {
|
|
123
|
+
const { fromPath, toPath } = input;
|
|
124
|
+
return apiRequest(tok(ctx), "/files/move_v2", { from_path: fromPath, to_path: toPath });
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
rl.registerAction("folder.delete", {
|
|
128
|
+
description: "Delete a folder",
|
|
129
|
+
inputSchema: { path: { type: "string", required: true, description: "Folder path to delete" } },
|
|
130
|
+
async execute(input, ctx) {
|
|
131
|
+
return apiRequest(tok(ctx), "/files/delete_v2", { path: input.path });
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
// ── Search ──────────────────────────────────────────
|
|
135
|
+
rl.registerAction("search.query", {
|
|
136
|
+
description: "Search for files and folders",
|
|
137
|
+
inputSchema: {
|
|
138
|
+
query: { type: "string", required: true, description: "Search query" },
|
|
139
|
+
limit: { type: "number", required: false, description: "Max results" },
|
|
140
|
+
path: { type: "string", required: false, description: "Limit search to this folder path" },
|
|
141
|
+
fileCategories: { type: "array", required: false, description: "Filter by categories: image, document, pdf, spreadsheet, presentation, audio, video, folder, paper, other" },
|
|
142
|
+
fileExtensions: { type: "array", required: false, description: "Filter by file extensions (e.g. ['jpg', 'pdf'])" },
|
|
143
|
+
fileStatus: { type: "string", required: false, description: "active (default) or deleted" },
|
|
144
|
+
},
|
|
145
|
+
async execute(input, ctx) {
|
|
146
|
+
const { query, limit, path, fileCategories, fileExtensions, fileStatus } = (input ?? {});
|
|
147
|
+
const opts = {};
|
|
148
|
+
if (path)
|
|
149
|
+
opts.path = path;
|
|
150
|
+
if (fileCategories)
|
|
151
|
+
opts.file_categories = fileCategories;
|
|
152
|
+
if (fileExtensions)
|
|
153
|
+
opts.file_extensions = fileExtensions;
|
|
154
|
+
if (fileStatus)
|
|
155
|
+
opts.file_status = { ".tag": fileStatus };
|
|
156
|
+
return paginateSearch(tok(ctx), query, opts, limit);
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const BASE_URL = "https://api.dropcontact.io";
|
|
2
|
+
async function apiRequest(apiKey, method, endpoint, body) {
|
|
3
|
+
const opts = {
|
|
4
|
+
method,
|
|
5
|
+
headers: {
|
|
6
|
+
"Content-Type": "application/json",
|
|
7
|
+
"X-Access-Token": apiKey,
|
|
8
|
+
},
|
|
9
|
+
};
|
|
10
|
+
if (body && Object.keys(body).length > 0 && method !== "GET") {
|
|
11
|
+
opts.body = JSON.stringify(body);
|
|
12
|
+
}
|
|
13
|
+
const res = await fetch(`${BASE_URL}${endpoint}`, opts);
|
|
14
|
+
if (!res.ok)
|
|
15
|
+
throw new Error(`Dropcontact API error ${res.status}: ${await res.text()}`);
|
|
16
|
+
return res.json();
|
|
17
|
+
}
|
|
18
|
+
export default function dropcontact(rl) {
|
|
19
|
+
rl.setName("dropcontact");
|
|
20
|
+
rl.setVersion("0.1.0");
|
|
21
|
+
rl.setConnectionSchema({
|
|
22
|
+
apiKey: { type: "string", required: true, description: "Dropcontact API key", env: "DROPCONTACT_API_KEY" },
|
|
23
|
+
});
|
|
24
|
+
const key = (ctx) => ctx.connection.config.apiKey;
|
|
25
|
+
rl.registerAction("contact.enrich", {
|
|
26
|
+
description: "Enrich contacts — find B2B emails from name and website",
|
|
27
|
+
inputSchema: {
|
|
28
|
+
contacts: {
|
|
29
|
+
type: "array",
|
|
30
|
+
required: true,
|
|
31
|
+
description: "Array of contact objects with fields: email, first_name, last_name, full_name, company, website, phone, linkedin, country, num_siren, siret",
|
|
32
|
+
},
|
|
33
|
+
siren: { type: "boolean", required: false, description: "Include French company SIREN data" },
|
|
34
|
+
language: { type: "string", required: false, description: "Response language: en (default) or fr" },
|
|
35
|
+
},
|
|
36
|
+
async execute(input, ctx) {
|
|
37
|
+
const { contacts, siren, language } = input;
|
|
38
|
+
const body = { data: contacts };
|
|
39
|
+
if (siren)
|
|
40
|
+
body.siren = true;
|
|
41
|
+
if (language)
|
|
42
|
+
body.language = language;
|
|
43
|
+
return apiRequest(key(ctx), "POST", "/batch", body);
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
rl.registerAction("contact.fetchRequest", {
|
|
47
|
+
description: "Fetch results of a previous enrich request by ID",
|
|
48
|
+
inputSchema: {
|
|
49
|
+
requestId: { type: "string", required: true, description: "Request ID from a previous enrich call" },
|
|
50
|
+
},
|
|
51
|
+
async execute(input, ctx) {
|
|
52
|
+
const { requestId } = input;
|
|
53
|
+
const data = (await apiRequest(key(ctx), "GET", `/batch/${requestId}`));
|
|
54
|
+
if (!data.success)
|
|
55
|
+
throw new Error(`Request not ready or failed: ${data.reason ?? "unknown"}`);
|
|
56
|
+
return data.data;
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
const BASE_URL = "https://api.egoiapp.com";
|
|
2
|
+
async function apiRequest(apiKey, method, endpoint, body, qs) {
|
|
3
|
+
const url = new URL(`${BASE_URL}${endpoint}`);
|
|
4
|
+
if (qs) {
|
|
5
|
+
for (const [k, v] of Object.entries(qs)) {
|
|
6
|
+
if (v !== undefined && v !== null)
|
|
7
|
+
url.searchParams.set(k, String(v));
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
const opts = {
|
|
11
|
+
method,
|
|
12
|
+
headers: { Apikey: apiKey, "Content-Type": "application/json", Accept: "application/json" },
|
|
13
|
+
};
|
|
14
|
+
if (body && Object.keys(body).length > 0 && method !== "GET" && method !== "DELETE") {
|
|
15
|
+
opts.body = JSON.stringify(body);
|
|
16
|
+
}
|
|
17
|
+
const res = await fetch(url.toString(), opts);
|
|
18
|
+
if (!res.ok)
|
|
19
|
+
throw new Error(`E-goi API error ${res.status}: ${await res.text()}`);
|
|
20
|
+
return res.json();
|
|
21
|
+
}
|
|
22
|
+
async function paginate(apiKey, endpoint, qs = {}, limit) {
|
|
23
|
+
const results = [];
|
|
24
|
+
qs.offset = 0;
|
|
25
|
+
qs.count = 500;
|
|
26
|
+
let data;
|
|
27
|
+
do {
|
|
28
|
+
const res = (await apiRequest(apiKey, "GET", endpoint, undefined, qs));
|
|
29
|
+
data = res.items ?? [];
|
|
30
|
+
results.push(...data);
|
|
31
|
+
qs.offset += qs.count;
|
|
32
|
+
if (limit && results.length >= limit)
|
|
33
|
+
break;
|
|
34
|
+
} while (data.length > 0);
|
|
35
|
+
return limit ? results.slice(0, limit) : results;
|
|
36
|
+
}
|
|
37
|
+
export default function egoi(rl) {
|
|
38
|
+
rl.setName("egoi");
|
|
39
|
+
rl.setVersion("0.1.0");
|
|
40
|
+
rl.setConnectionSchema({
|
|
41
|
+
apiKey: { type: "string", required: true, description: "E-goi API key", env: "EGOI_API_KEY" },
|
|
42
|
+
});
|
|
43
|
+
const key = (ctx) => ctx.connection.config.apiKey;
|
|
44
|
+
rl.registerAction("contact.create", {
|
|
45
|
+
description: "Create a contact in a list",
|
|
46
|
+
inputSchema: {
|
|
47
|
+
listId: { type: "string", required: true, description: "List ID" },
|
|
48
|
+
email: { type: "string", required: true, description: "Email address" },
|
|
49
|
+
firstName: { type: "string", required: false, description: "First name" },
|
|
50
|
+
lastName: { type: "string", required: false, description: "Last name" },
|
|
51
|
+
cellphone: { type: "string", required: false, description: "Cellphone" },
|
|
52
|
+
birthDate: { type: "string", required: false, description: "Birth date (YYYY-MM-DD)" },
|
|
53
|
+
status: { type: "string", required: false, description: "Status: active, inactive, unconfirmed, removed" },
|
|
54
|
+
tagIds: { type: "array", required: false, description: "Tag IDs to attach" },
|
|
55
|
+
extraFields: { type: "array", required: false, description: "Extra fields as [{field_id, value}]" },
|
|
56
|
+
},
|
|
57
|
+
async execute(input, ctx) {
|
|
58
|
+
const { listId, email, firstName, lastName, cellphone, birthDate, status, tagIds, extraFields } = input;
|
|
59
|
+
const base = { email };
|
|
60
|
+
if (firstName)
|
|
61
|
+
base.first_name = firstName;
|
|
62
|
+
if (lastName)
|
|
63
|
+
base.last_name = lastName;
|
|
64
|
+
if (cellphone)
|
|
65
|
+
base.cellphone = cellphone;
|
|
66
|
+
if (birthDate)
|
|
67
|
+
base.birth_date = birthDate;
|
|
68
|
+
if (status)
|
|
69
|
+
base.status = status;
|
|
70
|
+
const body = { base, extra: extraFields ?? [] };
|
|
71
|
+
const data = (await apiRequest(key(ctx), "POST", `/lists/${listId}/contacts`, body));
|
|
72
|
+
const contactId = data.contact_id;
|
|
73
|
+
if (tagIds && Array.isArray(tagIds)) {
|
|
74
|
+
for (const tag of tagIds) {
|
|
75
|
+
await apiRequest(key(ctx), "POST", `/lists/${listId}/contacts/actions/attach-tag`, {
|
|
76
|
+
tag_id: tag, contacts: [contactId],
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return apiRequest(key(ctx), "GET", `/lists/${listId}/contacts/${contactId}`);
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
rl.registerAction("contact.get", {
|
|
84
|
+
description: "Get a contact by ID or email",
|
|
85
|
+
inputSchema: {
|
|
86
|
+
listId: { type: "string", required: true, description: "List ID" },
|
|
87
|
+
contactId: { type: "string", required: false, description: "Contact ID" },
|
|
88
|
+
email: { type: "string", required: false, description: "Email (alternative to contactId)" },
|
|
89
|
+
},
|
|
90
|
+
async execute(input, ctx) {
|
|
91
|
+
const { listId, contactId, email } = (input ?? {});
|
|
92
|
+
if (contactId)
|
|
93
|
+
return apiRequest(key(ctx), "GET", `/lists/${listId}/contacts/${contactId}`);
|
|
94
|
+
if (email)
|
|
95
|
+
return apiRequest(key(ctx), "GET", `/lists/${listId}/contacts`, undefined, { email: email });
|
|
96
|
+
throw new Error("Provide either contactId or email");
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
rl.registerAction("contact.list", {
|
|
100
|
+
description: "List contacts in a list",
|
|
101
|
+
inputSchema: {
|
|
102
|
+
listId: { type: "string", required: true, description: "List ID" },
|
|
103
|
+
limit: { type: "number", required: false, description: "Max results" },
|
|
104
|
+
},
|
|
105
|
+
async execute(input, ctx) {
|
|
106
|
+
const { listId, limit } = (input ?? {});
|
|
107
|
+
return paginate(key(ctx), `/lists/${listId}/contacts`, {}, limit);
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
rl.registerAction("contact.update", {
|
|
111
|
+
description: "Update a contact",
|
|
112
|
+
inputSchema: {
|
|
113
|
+
listId: { type: "string", required: true, description: "List ID" },
|
|
114
|
+
contactId: { type: "string", required: true, description: "Contact ID" },
|
|
115
|
+
email: { type: "string", required: false, description: "New email" },
|
|
116
|
+
firstName: { type: "string", required: false, description: "First name" },
|
|
117
|
+
lastName: { type: "string", required: false, description: "Last name" },
|
|
118
|
+
cellphone: { type: "string", required: false, description: "Cellphone" },
|
|
119
|
+
birthDate: { type: "string", required: false, description: "Birth date (YYYY-MM-DD)" },
|
|
120
|
+
status: { type: "string", required: false, description: "Status" },
|
|
121
|
+
tagIds: { type: "array", required: false, description: "Tag IDs to attach" },
|
|
122
|
+
extraFields: { type: "array", required: false, description: "Extra fields as [{field_id, value}]" },
|
|
123
|
+
},
|
|
124
|
+
async execute(input, ctx) {
|
|
125
|
+
const { listId, contactId, email, firstName, lastName, cellphone, birthDate, status, tagIds, extraFields } = input;
|
|
126
|
+
const base = {};
|
|
127
|
+
if (email)
|
|
128
|
+
base.email = email;
|
|
129
|
+
if (firstName)
|
|
130
|
+
base.first_name = firstName;
|
|
131
|
+
if (lastName)
|
|
132
|
+
base.last_name = lastName;
|
|
133
|
+
if (cellphone)
|
|
134
|
+
base.cellphone = cellphone;
|
|
135
|
+
if (birthDate)
|
|
136
|
+
base.birth_date = birthDate;
|
|
137
|
+
if (status)
|
|
138
|
+
base.status = status;
|
|
139
|
+
const body = { base, extra: extraFields ?? [] };
|
|
140
|
+
await apiRequest(key(ctx), "PATCH", `/lists/${listId}/contacts/${contactId}`, body);
|
|
141
|
+
if (tagIds && Array.isArray(tagIds)) {
|
|
142
|
+
for (const tag of tagIds) {
|
|
143
|
+
await apiRequest(key(ctx), "POST", `/lists/${listId}/contacts/actions/attach-tag`, {
|
|
144
|
+
tag_id: tag, contacts: [contactId],
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return apiRequest(key(ctx), "GET", `/lists/${listId}/contacts/${contactId}`);
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
async function apiRequest(baseUrl, username, password, method, endpoint, body, qs) {
|
|
2
|
+
const url = new URL(`${baseUrl}${endpoint}`);
|
|
3
|
+
if (qs) {
|
|
4
|
+
for (const [k, v] of Object.entries(qs)) {
|
|
5
|
+
if (v !== undefined && v !== null)
|
|
6
|
+
url.searchParams.set(k, String(v));
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
const opts = {
|
|
10
|
+
method,
|
|
11
|
+
headers: {
|
|
12
|
+
Authorization: `Basic ${btoa(`${username}:${password}`)}`,
|
|
13
|
+
"Content-Type": "application/json",
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
if (body && Object.keys(body).length > 0 && method !== "GET" && method !== "DELETE") {
|
|
17
|
+
opts.body = JSON.stringify(body);
|
|
18
|
+
}
|
|
19
|
+
const res = await fetch(url.toString(), opts);
|
|
20
|
+
if (!res.ok)
|
|
21
|
+
throw new Error(`Elasticsearch error ${res.status}: ${await res.text()}`);
|
|
22
|
+
const ct = res.headers.get("content-type") ?? "";
|
|
23
|
+
if (ct.includes("application/json"))
|
|
24
|
+
return res.json();
|
|
25
|
+
return { success: true };
|
|
26
|
+
}
|
|
27
|
+
function getConn(ctx) {
|
|
28
|
+
const cfg = ctx.connection.config;
|
|
29
|
+
return {
|
|
30
|
+
baseUrl: cfg.baseUrl.replace(/\/$/, ""),
|
|
31
|
+
username: cfg.username ?? "",
|
|
32
|
+
password: cfg.password ?? "",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function req(ctx, method, endpoint, body, qs) {
|
|
36
|
+
const { baseUrl, username, password } = getConn(ctx);
|
|
37
|
+
return apiRequest(baseUrl, username, password, method, endpoint, body, qs);
|
|
38
|
+
}
|
|
39
|
+
export default function elasticsearch(rl) {
|
|
40
|
+
rl.setName("elasticsearch");
|
|
41
|
+
rl.setVersion("0.1.0");
|
|
42
|
+
rl.setConnectionSchema({
|
|
43
|
+
baseUrl: { type: "string", required: true, description: "Elasticsearch base URL (e.g. https://localhost:9200)", env: "ELASTICSEARCH_URL" },
|
|
44
|
+
username: { type: "string", required: false, description: "Username for basic auth", env: "ELASTICSEARCH_USERNAME" },
|
|
45
|
+
password: { type: "string", required: false, description: "Password for basic auth", env: "ELASTICSEARCH_PASSWORD" },
|
|
46
|
+
});
|
|
47
|
+
// ── Document ────────────────────────────────────────
|
|
48
|
+
rl.registerAction("document.create", {
|
|
49
|
+
description: "Index (create) a document",
|
|
50
|
+
inputSchema: {
|
|
51
|
+
index: { type: "string", required: true, description: "Index name" },
|
|
52
|
+
id: { type: "string", required: false, description: "Document ID (auto-generated if omitted)" },
|
|
53
|
+
body: { type: "object", required: true, description: "Document body" },
|
|
54
|
+
},
|
|
55
|
+
async execute(input, ctx) {
|
|
56
|
+
const { index, id, body } = input;
|
|
57
|
+
const endpoint = id ? `/${index}/_doc/${id}` : `/${index}/_doc`;
|
|
58
|
+
return req(ctx, id ? "PUT" : "POST", endpoint, body);
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
rl.registerAction("document.get", {
|
|
62
|
+
description: "Get a document by ID",
|
|
63
|
+
inputSchema: {
|
|
64
|
+
index: { type: "string", required: true, description: "Index name" },
|
|
65
|
+
id: { type: "string", required: true, description: "Document ID" },
|
|
66
|
+
},
|
|
67
|
+
async execute(input, ctx) {
|
|
68
|
+
const { index, id } = input;
|
|
69
|
+
return req(ctx, "GET", `/${index}/_doc/${id}`);
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
rl.registerAction("document.update", {
|
|
73
|
+
description: "Update a document",
|
|
74
|
+
inputSchema: {
|
|
75
|
+
index: { type: "string", required: true, description: "Index name" },
|
|
76
|
+
id: { type: "string", required: true, description: "Document ID" },
|
|
77
|
+
body: { type: "object", required: true, description: "Partial document to merge" },
|
|
78
|
+
},
|
|
79
|
+
async execute(input, ctx) {
|
|
80
|
+
const { index, id, body } = input;
|
|
81
|
+
return req(ctx, "POST", `/${index}/_update/${id}`, { doc: body });
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
rl.registerAction("document.delete", {
|
|
85
|
+
description: "Delete a document",
|
|
86
|
+
inputSchema: {
|
|
87
|
+
index: { type: "string", required: true, description: "Index name" },
|
|
88
|
+
id: { type: "string", required: true, description: "Document ID" },
|
|
89
|
+
},
|
|
90
|
+
async execute(input, ctx) {
|
|
91
|
+
const { index, id } = input;
|
|
92
|
+
return req(ctx, "DELETE", `/${index}/_doc/${id}`);
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
rl.registerAction("document.search", {
|
|
96
|
+
description: "Search documents in an index",
|
|
97
|
+
inputSchema: {
|
|
98
|
+
index: { type: "string", required: true, description: "Index name" },
|
|
99
|
+
query: { type: "object", required: false, description: "Elasticsearch query DSL" },
|
|
100
|
+
size: { type: "number", required: false, description: "Max results (default: 10)" },
|
|
101
|
+
from: { type: "number", required: false, description: "Offset" },
|
|
102
|
+
sort: { type: "array", required: false, description: "Sort criteria" },
|
|
103
|
+
},
|
|
104
|
+
async execute(input, ctx) {
|
|
105
|
+
const { index, query, size, from: offset, sort } = (input ?? {});
|
|
106
|
+
const body = {};
|
|
107
|
+
if (query)
|
|
108
|
+
body.query = query;
|
|
109
|
+
if (size !== undefined)
|
|
110
|
+
body.size = size;
|
|
111
|
+
if (offset !== undefined)
|
|
112
|
+
body.from = offset;
|
|
113
|
+
if (sort)
|
|
114
|
+
body.sort = sort;
|
|
115
|
+
const data = (await req(ctx, "POST", `/${index}/_search`, body));
|
|
116
|
+
return data.hits?.hits;
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
// ── Index ───────────────────────────────────────────
|
|
120
|
+
rl.registerAction("index.create", {
|
|
121
|
+
description: "Create an index",
|
|
122
|
+
inputSchema: {
|
|
123
|
+
index: { type: "string", required: true, description: "Index name" },
|
|
124
|
+
settings: { type: "object", required: false, description: "Index settings" },
|
|
125
|
+
mappings: { type: "object", required: false, description: "Index mappings" },
|
|
126
|
+
},
|
|
127
|
+
async execute(input, ctx) {
|
|
128
|
+
const { index, settings, mappings } = (input ?? {});
|
|
129
|
+
const body = {};
|
|
130
|
+
if (settings)
|
|
131
|
+
body.settings = settings;
|
|
132
|
+
if (mappings)
|
|
133
|
+
body.mappings = mappings;
|
|
134
|
+
return req(ctx, "PUT", `/${index}`, Object.keys(body).length > 0 ? body : undefined);
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
rl.registerAction("index.get", {
|
|
138
|
+
description: "Get index details",
|
|
139
|
+
inputSchema: { index: { type: "string", required: true, description: "Index name" } },
|
|
140
|
+
async execute(input, ctx) {
|
|
141
|
+
return req(ctx, "GET", `/${input.index}`);
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
rl.registerAction("index.list", {
|
|
145
|
+
description: "List all indices",
|
|
146
|
+
async execute(_input, ctx) {
|
|
147
|
+
return req(ctx, "GET", "/_cat/indices", undefined, { format: "json" });
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
rl.registerAction("index.delete", {
|
|
151
|
+
description: "Delete an index",
|
|
152
|
+
inputSchema: { index: { type: "string", required: true, description: "Index name" } },
|
|
153
|
+
async execute(input, ctx) {
|
|
154
|
+
return req(ctx, "DELETE", `/${input.index}`);
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
}
|