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.
Files changed (230) hide show
  1. package/.pi/extensions/runline-context/index.ts +135 -0
  2. package/.pi/extensions/runline-context/package.json +17 -0
  3. package/README.md +273 -0
  4. package/dist/commands/actions.d.ts +3 -0
  5. package/dist/commands/actions.js +43 -0
  6. package/dist/commands/connection.d.ts +11 -0
  7. package/dist/commands/connection.js +56 -0
  8. package/dist/commands/exec.d.ts +5 -0
  9. package/dist/commands/exec.js +46 -0
  10. package/dist/commands/init.d.ts +4 -0
  11. package/dist/commands/init.js +26 -0
  12. package/dist/commands/plugin.d.ts +10 -0
  13. package/dist/commands/plugin.js +57 -0
  14. package/dist/config/index.d.ts +3 -0
  15. package/dist/config/index.js +2 -0
  16. package/dist/config/loader.d.ts +11 -0
  17. package/dist/config/loader.js +82 -0
  18. package/dist/config/types.d.ts +9 -0
  19. package/dist/config/types.js +5 -0
  20. package/dist/core/engine.d.ts +21 -0
  21. package/dist/core/engine.js +280 -0
  22. package/dist/index.d.ts +16 -0
  23. package/dist/index.js +9 -0
  24. package/dist/main.d.ts +2 -0
  25. package/dist/main.js +127 -0
  26. package/dist/plugin/api.d.ts +32 -0
  27. package/dist/plugin/api.js +68 -0
  28. package/dist/plugin/installer.d.ts +27 -0
  29. package/dist/plugin/installer.js +181 -0
  30. package/dist/plugin/loader.d.ts +13 -0
  31. package/dist/plugin/loader.js +164 -0
  32. package/dist/plugin/registry.d.ts +18 -0
  33. package/dist/plugin/registry.js +43 -0
  34. package/dist/plugin/types.d.ts +40 -0
  35. package/dist/plugin/types.js +1 -0
  36. package/dist/plugins/actionNetwork/src/index.js +353 -0
  37. package/dist/plugins/activeCampaign/src/index.js +711 -0
  38. package/dist/plugins/adalo/src/index.js +131 -0
  39. package/dist/plugins/affinity/src/index.js +279 -0
  40. package/dist/plugins/agileCrm/src/index.js +415 -0
  41. package/dist/plugins/airtable/src/index.js +280 -0
  42. package/dist/plugins/airtop/src/index.js +527 -0
  43. package/dist/plugins/apiTemplateIo/src/index.js +86 -0
  44. package/dist/plugins/asana/src/index.js +413 -0
  45. package/dist/plugins/autopilot/src/index.js +203 -0
  46. package/dist/plugins/bambooHr/src/index.js +252 -0
  47. package/dist/plugins/bannerbear/src/index.js +100 -0
  48. package/dist/plugins/baserow/src/index.js +180 -0
  49. package/dist/plugins/beeminder/src/index.js +298 -0
  50. package/dist/plugins/bitly/src/index.js +107 -0
  51. package/dist/plugins/bitwarden/src/index.js +383 -0
  52. package/dist/plugins/box/src/index.js +300 -0
  53. package/dist/plugins/brandfetch/src/index.js +80 -0
  54. package/dist/plugins/brevo/src/index.js +305 -0
  55. package/dist/plugins/bubble/src/index.js +181 -0
  56. package/dist/plugins/chargebee/src/index.js +126 -0
  57. package/dist/plugins/circleci/src/index.js +111 -0
  58. package/dist/plugins/ciscoWebex/src/index.js +245 -0
  59. package/dist/plugins/clearbit/src/index.js +103 -0
  60. package/dist/plugins/clickup/src/index.js +1043 -0
  61. package/dist/plugins/clockify/src/index.js +443 -0
  62. package/dist/plugins/cloudflare/src/index.js +93 -0
  63. package/dist/plugins/cockpit/src/index.js +131 -0
  64. package/dist/plugins/coda/src/index.js +327 -0
  65. package/dist/plugins/coingecko/src/index.js +244 -0
  66. package/dist/plugins/contentful/src/index.js +146 -0
  67. package/dist/plugins/convertkit/src/index.js +270 -0
  68. package/dist/plugins/copper/src/index.js +140 -0
  69. package/dist/plugins/cortex/src/index.js +147 -0
  70. package/dist/plugins/currents/src/index.js +405 -0
  71. package/dist/plugins/customerIo/src/index.js +184 -0
  72. package/dist/plugins/databricks/src/index.js +342 -0
  73. package/dist/plugins/deepl/src/index.js +87 -0
  74. package/dist/plugins/demio/src/index.js +111 -0
  75. package/dist/plugins/dhl/src/index.js +40 -0
  76. package/dist/plugins/discord/src/index.js +275 -0
  77. package/dist/plugins/discourse/src/index.js +273 -0
  78. package/dist/plugins/disqus/src/index.js +145 -0
  79. package/dist/plugins/docker/src/index.js +76 -0
  80. package/dist/plugins/drift/src/index.js +89 -0
  81. package/dist/plugins/dropbox/src/index.js +159 -0
  82. package/dist/plugins/dropcontact/src/index.js +59 -0
  83. package/dist/plugins/egoi/src/index.js +151 -0
  84. package/dist/plugins/elasticsearch/src/index.js +157 -0
  85. package/dist/plugins/emelia/src/index.js +174 -0
  86. package/dist/plugins/erpnext/src/index.js +121 -0
  87. package/dist/plugins/facebookGraph/src/index.js +57 -0
  88. package/dist/plugins/freshdesk/src/index.js +320 -0
  89. package/dist/plugins/freshservice/src/index.js +146 -0
  90. package/dist/plugins/freshworksCrm/src/index.js +149 -0
  91. package/dist/plugins/getresponse/src/index.js +140 -0
  92. package/dist/plugins/ghost/src/index.js +192 -0
  93. package/dist/plugins/github/src/index.js +630 -0
  94. package/dist/plugins/gitlab/src/index.js +358 -0
  95. package/dist/plugins/gong/src/index.js +126 -0
  96. package/dist/plugins/gotify/src/index.js +77 -0
  97. package/dist/plugins/gotowebinar/src/index.js +316 -0
  98. package/dist/plugins/grafana/src/index.js +250 -0
  99. package/dist/plugins/graphql/src/index.js +78 -0
  100. package/dist/plugins/grist/src/index.js +106 -0
  101. package/dist/plugins/hackernews/src/index.js +89 -0
  102. package/dist/plugins/halopsa/src/index.js +79 -0
  103. package/dist/plugins/harvest/src/index.js +163 -0
  104. package/dist/plugins/helpscout/src/index.js +176 -0
  105. package/dist/plugins/highlevel/src/index.js +172 -0
  106. package/dist/plugins/homeAssistant/src/index.js +148 -0
  107. package/dist/plugins/hubspot/src/index.js +176 -0
  108. package/dist/plugins/humanticAi/src/index.js +60 -0
  109. package/dist/plugins/hunter/src/index.js +59 -0
  110. package/dist/plugins/intercom/src/index.js +156 -0
  111. package/dist/plugins/iterable/src/index.js +139 -0
  112. package/dist/plugins/jenkins/src/index.js +132 -0
  113. package/dist/plugins/jira/src/index.js +229 -0
  114. package/dist/plugins/keap/src/index.js +502 -0
  115. package/dist/plugins/kobotoolbox/src/index.js +281 -0
  116. package/dist/plugins/lemlist/src/index.js +231 -0
  117. package/dist/plugins/linear/src/index.js +133 -0
  118. package/dist/plugins/lingvanex/src/index.js +31 -0
  119. package/dist/plugins/linkedin/src/index.js +80 -0
  120. package/dist/plugins/lonescale/src/index.js +119 -0
  121. package/dist/plugins/magento/src/index.js +300 -0
  122. package/dist/plugins/mailcheck/src/index.js +27 -0
  123. package/dist/plugins/mailchimp/src/index.js +321 -0
  124. package/dist/plugins/mailerlite/src/index.js +123 -0
  125. package/dist/plugins/mailgun/src/index.js +48 -0
  126. package/dist/plugins/mailjet/src/index.js +155 -0
  127. package/dist/plugins/mandrill/src/index.js +145 -0
  128. package/dist/plugins/marketstack/src/index.js +97 -0
  129. package/dist/plugins/matrix/src/index.js +194 -0
  130. package/dist/plugins/mattermost/src/index.js +331 -0
  131. package/dist/plugins/mautic/src/index.js +311 -0
  132. package/dist/plugins/medium/src/index.js +77 -0
  133. package/dist/plugins/messagebird/src/index.js +57 -0
  134. package/dist/plugins/metabase/src/index.js +130 -0
  135. package/dist/plugins/misp/src/index.js +476 -0
  136. package/dist/plugins/mocean/src/index.js +67 -0
  137. package/dist/plugins/monday/src/index.js +231 -0
  138. package/dist/plugins/monicaCrm/src/index.js +52 -0
  139. package/dist/plugins/msg91/src/index.js +31 -0
  140. package/dist/plugins/nasa/src/index.js +146 -0
  141. package/dist/plugins/netlify/src/index.js +151 -0
  142. package/dist/plugins/netscalerAdc/src/index.js +131 -0
  143. package/dist/plugins/nextcloud/src/index.js +263 -0
  144. package/dist/plugins/nocodb/src/index.js +130 -0
  145. package/dist/plugins/notion/src/index.js +112 -0
  146. package/dist/plugins/npm/src/index.js +104 -0
  147. package/dist/plugins/odoo/src/index.js +157 -0
  148. package/dist/plugins/okta/src/index.js +141 -0
  149. package/dist/plugins/oneSimpleApi/src/index.js +155 -0
  150. package/dist/plugins/onfleet/src/index.js +254 -0
  151. package/dist/plugins/openThesaurus/src/index.js +32 -0
  152. package/dist/plugins/openweathermap/src/index.js +60 -0
  153. package/dist/plugins/oura/src/index.js +62 -0
  154. package/dist/plugins/paddle/src/index.js +247 -0
  155. package/dist/plugins/pagerduty/src/index.js +201 -0
  156. package/dist/plugins/paypal/src/index.js +106 -0
  157. package/dist/plugins/peekalink/src/index.js +35 -0
  158. package/dist/plugins/phantombuster/src/index.js +94 -0
  159. package/dist/plugins/philipsHue/src/index.js +98 -0
  160. package/dist/plugins/pipedrive/src/index.js +169 -0
  161. package/dist/plugins/plivo/src/index.js +66 -0
  162. package/dist/plugins/postbin/src/index.js +93 -0
  163. package/dist/plugins/posthog/src/index.js +113 -0
  164. package/dist/plugins/profitwell/src/index.js +50 -0
  165. package/dist/plugins/pushbullet/src/index.js +102 -0
  166. package/dist/plugins/pushcut/src/index.js +39 -0
  167. package/dist/plugins/pushover/src/index.js +65 -0
  168. package/dist/plugins/quickbase/src/index.js +153 -0
  169. package/dist/plugins/quickbooks/src/index.js +73 -0
  170. package/dist/plugins/quickchart/src/index.js +36 -0
  171. package/dist/plugins/raindrop/src/index.js +209 -0
  172. package/dist/plugins/reddit/src/index.js +185 -0
  173. package/dist/plugins/rocketchat/src/index.js +53 -0
  174. package/dist/plugins/rundeck/src/index.js +62 -0
  175. package/dist/plugins/salesforce/src/index.js +94 -0
  176. package/dist/plugins/salesmate/src/index.js +83 -0
  177. package/dist/plugins/securityScorecard/src/index.js +200 -0
  178. package/dist/plugins/segment/src/index.js +125 -0
  179. package/dist/plugins/sendgrid/src/index.js +187 -0
  180. package/dist/plugins/sendy/src/index.js +138 -0
  181. package/dist/plugins/sentry/src/index.js +233 -0
  182. package/dist/plugins/servicenow/src/index.js +108 -0
  183. package/dist/plugins/shopify/src/index.js +222 -0
  184. package/dist/plugins/signl4/src/index.js +61 -0
  185. package/dist/plugins/slack/src/index.js +236 -0
  186. package/dist/plugins/sms77/src/index.js +63 -0
  187. package/dist/plugins/splunk/src/index.js +207 -0
  188. package/dist/plugins/spotify/src/index.js +188 -0
  189. package/dist/plugins/stackby/src/index.js +82 -0
  190. package/dist/plugins/storyblok/src/index.js +141 -0
  191. package/dist/plugins/strapi/src/index.js +152 -0
  192. package/dist/plugins/strava/src/index.js +137 -0
  193. package/dist/plugins/stripe/src/index.js +222 -0
  194. package/dist/plugins/supabase/src/index.js +121 -0
  195. package/dist/plugins/syncromsp/src/index.js +255 -0
  196. package/dist/plugins/tapfiliate/src/index.js +125 -0
  197. package/dist/plugins/telegram/src/index.js +233 -0
  198. package/dist/plugins/thehive/src/index.js +142 -0
  199. package/dist/plugins/thehiveProject/src/index.js +194 -0
  200. package/dist/plugins/todoist/src/index.js +244 -0
  201. package/dist/plugins/travisci/src/index.js +71 -0
  202. package/dist/plugins/trello/src/index.js +341 -0
  203. package/dist/plugins/twake/src/index.js +40 -0
  204. package/dist/plugins/twilio/src/index.js +75 -0
  205. package/dist/plugins/twist/src/index.js +90 -0
  206. package/dist/plugins/twitter/src/index.js +123 -0
  207. package/dist/plugins/unleashedSoftware/src/index.js +84 -0
  208. package/dist/plugins/uplead/src/index.js +59 -0
  209. package/dist/plugins/uproc/src/index.js +34 -0
  210. package/dist/plugins/uptimerobot/src/index.js +264 -0
  211. package/dist/plugins/urlscanio/src/index.js +64 -0
  212. package/dist/plugins/vero/src/index.js +80 -0
  213. package/dist/plugins/vonage/src/index.js +42 -0
  214. package/dist/plugins/wekan/src/index.js +91 -0
  215. package/dist/plugins/woocommerce/src/index.js +92 -0
  216. package/dist/plugins/wordpress/src/index.js +121 -0
  217. package/dist/plugins/xero/src/index.js +136 -0
  218. package/dist/plugins/yourls/src/index.js +56 -0
  219. package/dist/plugins/zammad/src/index.js +91 -0
  220. package/dist/plugins/zendesk/src/index.js +137 -0
  221. package/dist/plugins/zoho/src/index.js +85 -0
  222. package/dist/plugins/zoom/src/index.js +122 -0
  223. package/dist/plugins/zulip/src/index.js +170 -0
  224. package/dist/sdk.d.ts +38 -0
  225. package/dist/sdk.js +105 -0
  226. package/dist/utils/cli.d.ts +13 -0
  227. package/dist/utils/cli.js +32 -0
  228. package/dist/utils/output.d.ts +4 -0
  229. package/dist/utils/output.js +13 -0
  230. package/package.json +57 -0
@@ -0,0 +1,174 @@
1
+ const GQL_URL = "https://graphql.emelia.io/graphql";
2
+ async function gql(apiKey, query, variables) {
3
+ const body = { query };
4
+ if (variables)
5
+ body.variables = variables;
6
+ const res = await fetch(GQL_URL, {
7
+ method: "POST",
8
+ headers: {
9
+ Authorization: apiKey,
10
+ "Content-Type": "application/json",
11
+ },
12
+ body: JSON.stringify(body),
13
+ });
14
+ if (!res.ok)
15
+ throw new Error(`Emelia API error ${res.status}: ${await res.text()}`);
16
+ const data = (await res.json());
17
+ if (data.errors)
18
+ throw new Error(`Emelia GraphQL error: ${JSON.stringify(data.errors)}`);
19
+ return data.data;
20
+ }
21
+ export default function emelia(rl) {
22
+ rl.setName("emelia");
23
+ rl.setVersion("0.1.0");
24
+ rl.setConnectionSchema({
25
+ apiKey: { type: "string", required: true, description: "Emelia API key", env: "EMELIA_API_KEY" },
26
+ });
27
+ const key = (ctx) => ctx.connection.config.apiKey;
28
+ // ── Campaign ────────────────────────────────────────
29
+ rl.registerAction("campaign.create", {
30
+ description: "Create a new campaign",
31
+ inputSchema: { name: { type: "string", required: true, description: "Campaign name" } },
32
+ async execute(input, ctx) {
33
+ const data = await gql(key(ctx), `
34
+ mutation createCampaign($name: String!) {
35
+ createCampaign(name: $name) { _id name status createdAt provider startAt estimatedEnd }
36
+ }`, { name: input.name });
37
+ return data.createCampaign;
38
+ },
39
+ });
40
+ rl.registerAction("campaign.get", {
41
+ description: "Get a campaign by ID",
42
+ inputSchema: { campaignId: { type: "string", required: true, description: "Campaign ID" } },
43
+ async execute(input, ctx) {
44
+ const data = await gql(key(ctx), `
45
+ query campaign($id: ID!) {
46
+ campaign(id: $id) {
47
+ _id name status createdAt provider startAt estimatedEnd
48
+ schedule { dailyContact dailyLimit minInterval maxInterval trackLinks trackOpens timeZone days start end }
49
+ recipients { total_count }
50
+ }
51
+ }`, { id: input.campaignId });
52
+ return data.campaign;
53
+ },
54
+ });
55
+ rl.registerAction("campaign.list", {
56
+ description: "List all campaigns",
57
+ inputSchema: { limit: { type: "number", required: false, description: "Max results" } },
58
+ async execute(input, ctx) {
59
+ const { limit } = (input ?? {});
60
+ const data = await gql(key(ctx), `
61
+ query all_campaigns {
62
+ all_campaigns {
63
+ _id name status createdAt
64
+ stats { mailsSent uniqueOpensPercent opens linkClickedPercent repliedPercent bouncedPercent unsubscribePercent progressPercent }
65
+ }
66
+ }`);
67
+ const campaigns = data.all_campaigns;
68
+ if (limit)
69
+ return campaigns.slice(0, limit);
70
+ return campaigns;
71
+ },
72
+ });
73
+ rl.registerAction("campaign.addContact", {
74
+ description: "Add a contact to a campaign",
75
+ inputSchema: {
76
+ campaignId: { type: "string", required: true, description: "Campaign ID" },
77
+ email: { type: "string", required: true, description: "Contact email" },
78
+ firstName: { type: "string", required: false, description: "First name" },
79
+ lastName: { type: "string", required: false, description: "Last name" },
80
+ customFields: { type: "object", required: false, description: "Custom fields as key-value pairs" },
81
+ },
82
+ async execute(input, ctx) {
83
+ const { campaignId, email, firstName, lastName, customFields } = input;
84
+ const contact = { email };
85
+ if (firstName)
86
+ contact.firstName = firstName;
87
+ if (lastName)
88
+ contact.lastName = lastName;
89
+ if (customFields)
90
+ Object.assign(contact, customFields);
91
+ const data = await gql(key(ctx), `
92
+ mutation AddContactToCampaignHook($id: ID!, $contact: JSON!) {
93
+ addContactToCampaignHook(id: $id, contact: $contact)
94
+ }`, { id: campaignId, contact });
95
+ return { contactId: data.addContactToCampaignHook };
96
+ },
97
+ });
98
+ rl.registerAction("campaign.start", {
99
+ description: "Start a campaign",
100
+ inputSchema: { campaignId: { type: "string", required: true, description: "Campaign ID" } },
101
+ async execute(input, ctx) {
102
+ await gql(key(ctx), `mutation startCampaign($id: ID!) { startCampaign(id: $id) }`, { id: input.campaignId });
103
+ return { success: true };
104
+ },
105
+ });
106
+ rl.registerAction("campaign.pause", {
107
+ description: "Pause a campaign",
108
+ inputSchema: { campaignId: { type: "string", required: true, description: "Campaign ID" } },
109
+ async execute(input, ctx) {
110
+ await gql(key(ctx), `mutation pauseCampaign($id: ID!) { pauseCampaign(id: $id) }`, { id: input.campaignId });
111
+ return { success: true };
112
+ },
113
+ });
114
+ rl.registerAction("campaign.duplicate", {
115
+ description: "Duplicate a campaign",
116
+ inputSchema: {
117
+ campaignId: { type: "string", required: true, description: "Source campaign ID" },
118
+ name: { type: "string", required: true, description: "New campaign name" },
119
+ copySettings: { type: "boolean", required: false, description: "Copy settings (default: true)" },
120
+ copyMails: { type: "boolean", required: false, description: "Copy mail templates (default: true)" },
121
+ copyContacts: { type: "boolean", required: false, description: "Copy contacts (default: false)" },
122
+ copyProvider: { type: "boolean", required: false, description: "Copy provider (default: true)" },
123
+ },
124
+ async execute(input, ctx) {
125
+ const { campaignId, name, copySettings = true, copyMails = true, copyContacts = false, copyProvider = true } = input;
126
+ const data = await gql(key(ctx), `
127
+ mutation duplicateCampaign($fromId: ID!, $name: String!, $copySettings: Boolean!, $copyMails: Boolean!, $copyContacts: Boolean!, $copyProvider: Boolean!) {
128
+ duplicateCampaign(fromId: $fromId, name: $name, copySettings: $copySettings, copyMails: $copyMails, copyContacts: $copyContacts, copyProvider: $copyProvider)
129
+ }`, { fromId: campaignId, name, copySettings, copyMails, copyContacts, copyProvider });
130
+ return { _id: data.duplicateCampaign };
131
+ },
132
+ });
133
+ // ── Contact List ────────────────────────────────────
134
+ rl.registerAction("contactList.list", {
135
+ description: "List all contact lists",
136
+ inputSchema: { limit: { type: "number", required: false, description: "Max results" } },
137
+ async execute(input, ctx) {
138
+ const { limit } = (input ?? {});
139
+ const data = await gql(key(ctx), `
140
+ query contact_lists {
141
+ contact_lists { _id name contactCount fields usedInCampaign }
142
+ }`);
143
+ const lists = data.contact_lists;
144
+ if (limit)
145
+ return lists.slice(0, limit);
146
+ return lists;
147
+ },
148
+ });
149
+ rl.registerAction("contactList.addContact", {
150
+ description: "Add a contact to a contact list",
151
+ inputSchema: {
152
+ contactListId: { type: "string", required: true, description: "Contact list ID" },
153
+ email: { type: "string", required: true, description: "Contact email" },
154
+ firstName: { type: "string", required: false, description: "First name" },
155
+ lastName: { type: "string", required: false, description: "Last name" },
156
+ customFields: { type: "object", required: false, description: "Custom fields as key-value pairs" },
157
+ },
158
+ async execute(input, ctx) {
159
+ const { contactListId, email, firstName, lastName, customFields } = input;
160
+ const contact = { email };
161
+ if (firstName)
162
+ contact.firstName = firstName;
163
+ if (lastName)
164
+ contact.lastName = lastName;
165
+ if (customFields)
166
+ Object.assign(contact, customFields);
167
+ const data = await gql(key(ctx), `
168
+ mutation AddContactsToListHook($id: ID!, $contact: JSON!) {
169
+ addContactsToListHook(id: $id, contact: $contact)
170
+ }`, { id: contactListId, contact });
171
+ return { contactId: data.addContactsToListHook };
172
+ },
173
+ });
174
+ }
@@ -0,0 +1,121 @@
1
+ async function apiRequest(host, apiKey, apiSecret, method, endpoint, body, qs) {
2
+ const url = new URL(`${host}${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: `token ${apiKey}:${apiSecret}`,
13
+ "Content-Type": "application/json",
14
+ Accept: "application/json",
15
+ },
16
+ };
17
+ if (body && Object.keys(body).length > 0 && method !== "GET" && method !== "DELETE") {
18
+ opts.body = JSON.stringify(body);
19
+ }
20
+ const res = await fetch(url.toString(), opts);
21
+ if (!res.ok)
22
+ throw new Error(`ERPNext API error ${res.status}: ${await res.text()}`);
23
+ return res.json();
24
+ }
25
+ function getConn(ctx) {
26
+ const cfg = ctx.connection.config;
27
+ return {
28
+ host: cfg.host.replace(/\/$/, ""),
29
+ apiKey: cfg.apiKey,
30
+ apiSecret: cfg.apiSecret,
31
+ };
32
+ }
33
+ function req(ctx, method, endpoint, body, qs) {
34
+ const { host, apiKey, apiSecret } = getConn(ctx);
35
+ return apiRequest(host, apiKey, apiSecret, method, endpoint, body, qs);
36
+ }
37
+ export default function erpnext(rl) {
38
+ rl.setName("erpnext");
39
+ rl.setVersion("0.1.0");
40
+ rl.setConnectionSchema({
41
+ host: { type: "string", required: true, description: "ERPNext instance URL (e.g. https://mysite.erpnext.com)", env: "ERPNEXT_HOST" },
42
+ apiKey: { type: "string", required: true, description: "API key", env: "ERPNEXT_API_KEY" },
43
+ apiSecret: { type: "string", required: true, description: "API secret", env: "ERPNEXT_API_SECRET" },
44
+ });
45
+ rl.registerAction("document.get", {
46
+ description: "Get a document by DocType and name",
47
+ inputSchema: {
48
+ docType: { type: "string", required: true, description: "Document type (e.g. Customer, Sales Order)" },
49
+ documentName: { type: "string", required: true, description: "Document name/ID" },
50
+ },
51
+ async execute(input, ctx) {
52
+ const { docType, documentName } = input;
53
+ const data = (await req(ctx, "GET", `/api/resource/${encodeURIComponent(docType)}/${encodeURIComponent(documentName)}`));
54
+ return data.data;
55
+ },
56
+ });
57
+ rl.registerAction("document.list", {
58
+ description: "List documents of a DocType",
59
+ inputSchema: {
60
+ docType: { type: "string", required: true, description: "Document type" },
61
+ fields: { type: "array", required: false, description: "Fields to return (default: ['name']). Use ['*'] for all." },
62
+ filters: { type: "array", required: false, description: 'Filters as [[doctype, field, operator, value], ...]' },
63
+ limit: { type: "number", required: false, description: "Max results (default: 20)" },
64
+ offset: { type: "number", required: false, description: "Start offset" },
65
+ orderBy: { type: "string", required: false, description: "Order by (e.g. 'creation desc')" },
66
+ },
67
+ async execute(input, ctx) {
68
+ const { docType, fields, filters, limit, offset, orderBy } = (input ?? {});
69
+ const qs = {};
70
+ if (fields)
71
+ qs.fields = JSON.stringify(fields);
72
+ if (filters)
73
+ qs.filters = JSON.stringify(filters);
74
+ if (limit)
75
+ qs.limit_page_length = limit;
76
+ if (offset)
77
+ qs.limit_start = offset;
78
+ if (orderBy)
79
+ qs.order_by = orderBy;
80
+ const data = (await req(ctx, "GET", `/api/resource/${encodeURIComponent(docType)}`, undefined, qs));
81
+ return data.data;
82
+ },
83
+ });
84
+ rl.registerAction("document.create", {
85
+ description: "Create a document",
86
+ inputSchema: {
87
+ docType: { type: "string", required: true, description: "Document type" },
88
+ properties: { type: "object", required: true, description: "Document field values as key-value pairs" },
89
+ },
90
+ async execute(input, ctx) {
91
+ const { docType, properties } = input;
92
+ const data = (await req(ctx, "POST", `/api/resource/${encodeURIComponent(docType)}`, properties));
93
+ return data.data;
94
+ },
95
+ });
96
+ rl.registerAction("document.update", {
97
+ description: "Update a document",
98
+ inputSchema: {
99
+ docType: { type: "string", required: true, description: "Document type" },
100
+ documentName: { type: "string", required: true, description: "Document name/ID" },
101
+ properties: { type: "object", required: true, description: "Fields to update as key-value pairs" },
102
+ },
103
+ async execute(input, ctx) {
104
+ const { docType, documentName, properties } = input;
105
+ const data = (await req(ctx, "PUT", `/api/resource/${encodeURIComponent(docType)}/${encodeURIComponent(documentName)}`, properties));
106
+ return data.data;
107
+ },
108
+ });
109
+ rl.registerAction("document.delete", {
110
+ description: "Delete a document",
111
+ inputSchema: {
112
+ docType: { type: "string", required: true, description: "Document type" },
113
+ documentName: { type: "string", required: true, description: "Document name/ID" },
114
+ },
115
+ async execute(input, ctx) {
116
+ const { docType, documentName } = input;
117
+ await req(ctx, "DELETE", `/api/resource/${encodeURIComponent(docType)}/${encodeURIComponent(documentName)}`);
118
+ return { success: true };
119
+ },
120
+ });
121
+ }
@@ -0,0 +1,57 @@
1
+ export default function facebookGraph(rl) {
2
+ rl.setName("facebookGraph");
3
+ rl.setVersion("0.1.0");
4
+ rl.setConnectionSchema({
5
+ accessToken: { type: "string", required: true, description: "Facebook/Meta access token", env: "FACEBOOK_ACCESS_TOKEN" },
6
+ });
7
+ rl.registerAction("request", {
8
+ description: "Make a request to the Facebook Graph API. Supports GET, POST, DELETE against any node/edge combination.",
9
+ inputSchema: {
10
+ hostUrl: { type: "string", required: false, description: "Host URL: 'graph.facebook.com' (default) or 'graph-video.facebook.com' for video uploads" },
11
+ method: { type: "string", required: false, description: "HTTP method: GET (default), POST, DELETE" },
12
+ graphApiVersion: { type: "string", required: false, description: "API version (e.g. 'v19.0'). Omit for default." },
13
+ node: { type: "string", required: true, description: "Node ID (e.g. 'me', a page/user/object ID)" },
14
+ edge: { type: "string", required: false, description: "Edge name (e.g. 'posts', 'feed', 'videos')" },
15
+ fields: { type: "array", required: false, description: "Fields to request (GET only), sent as comma-separated 'fields' param" },
16
+ queryParameters: { type: "object", required: false, description: "Additional query parameters as key-value pairs" },
17
+ body: { type: "object", required: false, description: "Request body for POST requests (sent as JSON)" },
18
+ },
19
+ async execute(input, ctx) {
20
+ const { hostUrl = "graph.facebook.com", method = "GET", graphApiVersion = "", node, edge, fields, queryParameters, body, } = input;
21
+ const versionPrefix = graphApiVersion ? `${graphApiVersion}/` : "";
22
+ let uri = `https://${hostUrl}/${versionPrefix}${node}`;
23
+ if (edge)
24
+ uri = `${uri}/${edge}`;
25
+ const url = new URL(uri);
26
+ url.searchParams.set("access_token", ctx.connection.config.accessToken);
27
+ if (fields && Array.isArray(fields) && fields.length > 0) {
28
+ url.searchParams.set("fields", fields.join(","));
29
+ }
30
+ if (queryParameters && typeof queryParameters === "object") {
31
+ for (const [k, v] of Object.entries(queryParameters)) {
32
+ if (v !== undefined && v !== null)
33
+ url.searchParams.set(k, String(v));
34
+ }
35
+ }
36
+ const httpMethod = method.toUpperCase();
37
+ const opts = {
38
+ method: httpMethod,
39
+ headers: { Accept: "application/json,text/*;q=0.99" },
40
+ };
41
+ if (body && typeof body === "object" && Object.keys(body).length > 0 && httpMethod === "POST") {
42
+ opts.headers["Content-Type"] = "application/json";
43
+ opts.body = JSON.stringify(body);
44
+ }
45
+ const res = await fetch(url.toString(), opts);
46
+ if (!res.ok)
47
+ throw new Error(`Facebook Graph API error ${res.status}: ${await res.text()}`);
48
+ const text = await res.text();
49
+ try {
50
+ return JSON.parse(text);
51
+ }
52
+ catch {
53
+ return { message: text };
54
+ }
55
+ },
56
+ });
57
+ }
@@ -0,0 +1,320 @@
1
+ const STATUS = { open: 2, pending: 3, resolved: 4, closed: 5 };
2
+ const PRIORITY = { low: 1, medium: 2, high: 3, urgent: 4 };
3
+ const SOURCE = { email: 1, portal: 2, phone: 3, chat: 7, mobihelp: 8, feedbackWidget: 9, outboundEmail: 10 };
4
+ async function apiRequest(domain, apiKey, method, endpoint, body, qs) {
5
+ const url = new URL(`https://${domain}.freshdesk.com/api/v2${endpoint}`);
6
+ if (qs) {
7
+ for (const [k, v] of Object.entries(qs)) {
8
+ if (v !== undefined && v !== null)
9
+ url.searchParams.set(k, String(v));
10
+ }
11
+ }
12
+ const opts = {
13
+ method,
14
+ headers: {
15
+ Authorization: `Basic ${btoa(`${apiKey}:X`)}`,
16
+ "Content-Type": "application/json",
17
+ },
18
+ };
19
+ if (body && Object.keys(body).length > 0 && method !== "GET" && method !== "DELETE") {
20
+ opts.body = JSON.stringify(body);
21
+ }
22
+ const res = await fetch(url.toString(), opts);
23
+ if (!res.ok)
24
+ throw new Error(`Freshdesk API error ${res.status}: ${await res.text()}`);
25
+ if (res.status === 204)
26
+ return { success: true };
27
+ return res.json();
28
+ }
29
+ function getConn(ctx) {
30
+ return {
31
+ domain: ctx.connection.config.domain,
32
+ apiKey: ctx.connection.config.apiKey,
33
+ };
34
+ }
35
+ function req(ctx, method, endpoint, body, qs) {
36
+ const { domain, apiKey } = getConn(ctx);
37
+ return apiRequest(domain, apiKey, method, endpoint, body, qs);
38
+ }
39
+ export default function freshdesk(rl) {
40
+ rl.setName("freshdesk");
41
+ rl.setVersion("0.1.0");
42
+ rl.setConnectionSchema({
43
+ domain: { type: "string", required: true, description: "Freshdesk subdomain (e.g. 'mycompany' for mycompany.freshdesk.com)", env: "FRESHDESK_DOMAIN" },
44
+ apiKey: { type: "string", required: true, description: "Freshdesk API key", env: "FRESHDESK_API_KEY" },
45
+ });
46
+ // ── Ticket ──────────────────────────────────────────
47
+ rl.registerAction("ticket.create", {
48
+ description: "Create a ticket",
49
+ inputSchema: {
50
+ email: { type: "string", required: false, description: "Requester email" },
51
+ requesterId: { type: "number", required: false, description: "Requester user ID" },
52
+ phone: { type: "string", required: false, description: "Requester phone" },
53
+ subject: { type: "string", required: false, description: "Ticket subject" },
54
+ description: { type: "string", required: false, description: "Ticket description (HTML)" },
55
+ status: { type: "string", required: true, description: "open, pending, resolved, closed" },
56
+ priority: { type: "string", required: true, description: "low, medium, high, urgent" },
57
+ source: { type: "string", required: false, description: "email, portal, phone, chat, feedbackWidget, mobihelp, outboundEmail" },
58
+ type: { type: "string", required: false, description: "Question, Incident, Problem, Feature Request, Refund" },
59
+ responderId: { type: "number", required: false, description: "Agent ID" },
60
+ groupId: { type: "number", required: false, description: "Group ID" },
61
+ productId: { type: "number", required: false, description: "Product ID" },
62
+ companyId: { type: "number", required: false, description: "Company ID" },
63
+ tags: { type: "array", required: false, description: "Tags" },
64
+ ccEmails: { type: "array", required: false, description: "CC email addresses" },
65
+ dueBy: { type: "string", required: false, description: "Due date (ISO 8601)" },
66
+ frDueBy: { type: "string", required: false, description: "First response due date" },
67
+ customFields: { type: "object", required: false, description: "Custom fields as key-value pairs" },
68
+ },
69
+ async execute(input, ctx) {
70
+ const i = input;
71
+ const body = {
72
+ status: STATUS[i.status] ?? 3,
73
+ priority: PRIORITY[i.priority] ?? 1,
74
+ };
75
+ if (i.email)
76
+ body.email = i.email;
77
+ if (i.requesterId)
78
+ body.requester_id = i.requesterId;
79
+ if (i.phone)
80
+ body.phone = i.phone;
81
+ if (i.subject)
82
+ body.subject = i.subject;
83
+ if (i.description)
84
+ body.description = i.description;
85
+ if (i.source)
86
+ body.source = SOURCE[i.source] ?? 2;
87
+ if (i.type)
88
+ body.type = i.type;
89
+ if (i.responderId)
90
+ body.responder_id = i.responderId;
91
+ if (i.groupId)
92
+ body.group_id = i.groupId;
93
+ if (i.productId)
94
+ body.product_id = i.productId;
95
+ if (i.companyId)
96
+ body.company_id = i.companyId;
97
+ if (i.tags)
98
+ body.tags = i.tags;
99
+ if (i.ccEmails)
100
+ body.cc_emails = i.ccEmails;
101
+ if (i.dueBy)
102
+ body.due_by = i.dueBy;
103
+ if (i.frDueBy)
104
+ body.fr_due_by = i.frDueBy;
105
+ if (i.customFields)
106
+ body.custom_fields = i.customFields;
107
+ return req(ctx, "POST", "/tickets", body);
108
+ },
109
+ });
110
+ rl.registerAction("ticket.get", {
111
+ description: "Get a ticket by ID",
112
+ inputSchema: { ticketId: { type: "string", required: true, description: "Ticket ID" } },
113
+ async execute(input, ctx) {
114
+ return req(ctx, "GET", `/tickets/${input.ticketId}`);
115
+ },
116
+ });
117
+ rl.registerAction("ticket.list", {
118
+ description: "List tickets",
119
+ inputSchema: {
120
+ limit: { type: "number", required: false, description: "Max results (default: 30)" },
121
+ requesterId: { type: "string", required: false, description: "Filter by requester ID" },
122
+ requesterEmail: { type: "string", required: false, description: "Filter by requester email" },
123
+ companyId: { type: "string", required: false, description: "Filter by company ID" },
124
+ updatedSince: { type: "string", required: false, description: "Filter by updated since (ISO 8601)" },
125
+ orderBy: { type: "string", required: false, description: "created_at, due_by, updated_at" },
126
+ orderType: { type: "string", required: false, description: "asc or desc" },
127
+ include: { type: "string", required: false, description: "Comma-separated: requester, company, stats, description" },
128
+ },
129
+ async execute(input, ctx) {
130
+ const { limit, requesterId, requesterEmail, companyId, updatedSince, orderBy, orderType, include } = (input ?? {});
131
+ const qs = {};
132
+ if (limit)
133
+ qs.per_page = limit;
134
+ if (requesterId)
135
+ qs.requester_id = requesterId;
136
+ if (requesterEmail)
137
+ qs.email = requesterEmail;
138
+ if (companyId)
139
+ qs.company_id = companyId;
140
+ if (updatedSince)
141
+ qs.updated_since = updatedSince;
142
+ if (orderBy)
143
+ qs.order_by = orderBy;
144
+ if (orderType)
145
+ qs.order_type = orderType;
146
+ if (include)
147
+ qs.include = include;
148
+ return req(ctx, "GET", "/tickets", undefined, qs);
149
+ },
150
+ });
151
+ rl.registerAction("ticket.update", {
152
+ description: "Update a ticket",
153
+ inputSchema: {
154
+ ticketId: { type: "string", required: true, description: "Ticket ID" },
155
+ status: { type: "string", required: false, description: "open, pending, resolved, closed" },
156
+ priority: { type: "string", required: false, description: "low, medium, high, urgent" },
157
+ source: { type: "string", required: false, description: "Source" },
158
+ type: { type: "string", required: false, description: "Ticket type" },
159
+ responderId: { type: "number", required: false, description: "Agent ID" },
160
+ groupId: { type: "number", required: false, description: "Group ID" },
161
+ productId: { type: "number", required: false, description: "Product ID" },
162
+ companyId: { type: "number", required: false, description: "Company ID" },
163
+ tags: { type: "array", required: false, description: "Tags" },
164
+ dueBy: { type: "string", required: false, description: "Due date" },
165
+ frDueBy: { type: "string", required: false, description: "First response due" },
166
+ customFields: { type: "object", required: false, description: "Custom fields" },
167
+ },
168
+ async execute(input, ctx) {
169
+ const { ticketId, status, priority, source, type, responderId, groupId, productId, companyId, tags, dueBy, frDueBy, customFields } = input;
170
+ const body = {};
171
+ if (status)
172
+ body.status = STATUS[status];
173
+ if (priority)
174
+ body.priority = PRIORITY[priority];
175
+ if (source)
176
+ body.source = SOURCE[source];
177
+ if (type)
178
+ body.type = type;
179
+ if (responderId)
180
+ body.responder_id = responderId;
181
+ if (groupId)
182
+ body.group_id = groupId;
183
+ if (productId)
184
+ body.product_id = productId;
185
+ if (companyId)
186
+ body.company_id = companyId;
187
+ if (tags)
188
+ body.tags = tags;
189
+ if (dueBy)
190
+ body.due_by = dueBy;
191
+ if (frDueBy)
192
+ body.fr_due_by = frDueBy;
193
+ if (customFields)
194
+ body.custom_fields = customFields;
195
+ return req(ctx, "PUT", `/tickets/${ticketId}`, body);
196
+ },
197
+ });
198
+ rl.registerAction("ticket.delete", {
199
+ description: "Delete a ticket",
200
+ inputSchema: { ticketId: { type: "string", required: true, description: "Ticket ID" } },
201
+ async execute(input, ctx) {
202
+ await req(ctx, "DELETE", `/tickets/${input.ticketId}`);
203
+ return { success: true };
204
+ },
205
+ });
206
+ // ── Contact ─────────────────────────────────────────
207
+ rl.registerAction("contact.create", {
208
+ description: "Create a contact",
209
+ inputSchema: {
210
+ name: { type: "string", required: true, description: "Full name" },
211
+ email: { type: "string", required: false, description: "Email address" },
212
+ phone: { type: "string", required: false, description: "Phone number" },
213
+ mobile: { type: "string", required: false, description: "Mobile number" },
214
+ address: { type: "string", required: false, description: "Address" },
215
+ description: { type: "string", required: false, description: "Description" },
216
+ jobTitle: { type: "string", required: false, description: "Job title" },
217
+ tags: { type: "array", required: false, description: "Tags" },
218
+ companyId: { type: "number", required: false, description: "Company ID" },
219
+ customFields: { type: "object", required: false, description: "Custom fields" },
220
+ },
221
+ async execute(input, ctx) {
222
+ const { name, email, phone, mobile, address, description: desc, jobTitle, tags, companyId, customFields } = input;
223
+ const body = { name };
224
+ if (email)
225
+ body.email = email;
226
+ if (phone)
227
+ body.phone = phone;
228
+ if (mobile)
229
+ body.mobile = mobile;
230
+ if (address)
231
+ body.address = address;
232
+ if (desc)
233
+ body.description = desc;
234
+ if (jobTitle)
235
+ body.job_title = jobTitle;
236
+ if (tags)
237
+ body.tags = tags;
238
+ if (companyId)
239
+ body.company_id = companyId;
240
+ if (customFields)
241
+ body.custom_fields = customFields;
242
+ return req(ctx, "POST", "/contacts", body);
243
+ },
244
+ });
245
+ rl.registerAction("contact.get", {
246
+ description: "Get a contact by ID",
247
+ inputSchema: { contactId: { type: "string", required: true, description: "Contact ID" } },
248
+ async execute(input, ctx) {
249
+ return req(ctx, "GET", `/contacts/${input.contactId}`);
250
+ },
251
+ });
252
+ rl.registerAction("contact.list", {
253
+ description: "List contacts",
254
+ inputSchema: {
255
+ email: { type: "string", required: false, description: "Filter by email" },
256
+ phone: { type: "string", required: false, description: "Filter by phone" },
257
+ mobile: { type: "string", required: false, description: "Filter by mobile" },
258
+ companyId: { type: "string", required: false, description: "Filter by company ID" },
259
+ state: { type: "string", required: false, description: "verified, unverified, blocked, deleted" },
260
+ },
261
+ async execute(input, ctx) {
262
+ const { email, phone, mobile, companyId, state } = (input ?? {});
263
+ const qs = {};
264
+ if (email)
265
+ qs.email = email;
266
+ if (phone)
267
+ qs.phone = phone;
268
+ if (mobile)
269
+ qs.mobile = mobile;
270
+ if (companyId)
271
+ qs.company_id = companyId;
272
+ if (state)
273
+ qs.state = state;
274
+ return req(ctx, "GET", "/contacts", undefined, qs);
275
+ },
276
+ });
277
+ rl.registerAction("contact.update", {
278
+ description: "Update a contact",
279
+ inputSchema: {
280
+ contactId: { type: "string", required: true, description: "Contact ID" },
281
+ name: { type: "string", required: false, description: "Name" },
282
+ email: { type: "string", required: false, description: "Email" },
283
+ phone: { type: "string", required: false, description: "Phone" },
284
+ mobile: { type: "string", required: false, description: "Mobile" },
285
+ address: { type: "string", required: false, description: "Address" },
286
+ jobTitle: { type: "string", required: false, description: "Job title" },
287
+ tags: { type: "array", required: false, description: "Tags" },
288
+ customFields: { type: "object", required: false, description: "Custom fields" },
289
+ },
290
+ async execute(input, ctx) {
291
+ const { contactId, name, email, phone, mobile, address, jobTitle, tags, customFields } = input;
292
+ const body = {};
293
+ if (name)
294
+ body.name = name;
295
+ if (email)
296
+ body.email = email;
297
+ if (phone)
298
+ body.phone = phone;
299
+ if (mobile)
300
+ body.mobile = mobile;
301
+ if (address)
302
+ body.address = address;
303
+ if (jobTitle)
304
+ body.job_title = jobTitle;
305
+ if (tags)
306
+ body.tags = tags;
307
+ if (customFields)
308
+ body.custom_fields = customFields;
309
+ return req(ctx, "PUT", `/contacts/${contactId}`, body);
310
+ },
311
+ });
312
+ rl.registerAction("contact.delete", {
313
+ description: "Delete a contact",
314
+ inputSchema: { contactId: { type: "string", required: true, description: "Contact ID" } },
315
+ async execute(input, ctx) {
316
+ await req(ctx, "DELETE", `/contacts/${input.contactId}`);
317
+ return { success: true };
318
+ },
319
+ });
320
+ }