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,169 @@
1
+ const V2 = "https://api.pipedrive.com/api/v2";
2
+ const V1 = "https://api.pipedrive.com/v1";
3
+ function getConn(ctx) {
4
+ return ctx.connection.config.apiToken;
5
+ }
6
+ async function api(token, method, endpoint, body, qs, version = "v2") {
7
+ const base = version === "v1" ? V1 : V2;
8
+ const url = new URL(`${base}${endpoint}`);
9
+ url.searchParams.set("api_token", token);
10
+ if (qs) {
11
+ for (const [k, v] of Object.entries(qs)) {
12
+ if (v !== undefined && v !== null)
13
+ url.searchParams.set(k, String(v));
14
+ }
15
+ }
16
+ const init = { method, headers: { Accept: "application/json", "Content-Type": "application/json" } };
17
+ if (body && Object.keys(body).length > 0)
18
+ init.body = JSON.stringify(body);
19
+ const res = await fetch(url.toString(), init);
20
+ if (!res.ok)
21
+ throw new Error(`Pipedrive error ${res.status}: ${await res.text()}`);
22
+ const json = await res.json();
23
+ if (json.success === false)
24
+ throw new Error(`Pipedrive: ${JSON.stringify(json)}`);
25
+ return json.data ?? json;
26
+ }
27
+ async function paginate(token, endpoint, qs = {}) {
28
+ const results = [];
29
+ qs.limit = 500;
30
+ let cursor;
31
+ do {
32
+ if (cursor)
33
+ qs.cursor = cursor;
34
+ const url = new URL(`${V2}${endpoint}`);
35
+ url.searchParams.set("api_token", token);
36
+ for (const [k, v] of Object.entries(qs)) {
37
+ if (v !== undefined && v !== null)
38
+ url.searchParams.set(k, String(v));
39
+ }
40
+ const res = await fetch(url.toString(), { headers: { Accept: "application/json" } });
41
+ if (!res.ok)
42
+ throw new Error(`Pipedrive error ${res.status}: ${await res.text()}`);
43
+ const json = await res.json();
44
+ const data = json.data;
45
+ if (Array.isArray(data))
46
+ results.push(...data);
47
+ cursor = json.additional_data?.next_cursor;
48
+ if (!cursor)
49
+ break;
50
+ } while (true);
51
+ return results;
52
+ }
53
+ function registerCrud(rl, resource, endpoint, opts) {
54
+ const cap = resource.charAt(0).toUpperCase() + resource.slice(1);
55
+ const updateMethod = opts?.updateMethod ?? "PATCH";
56
+ rl.registerAction(`${resource}.create`, { description: `Create a ${resource}`,
57
+ inputSchema: { data: { type: "object", required: true, description: `Fields for the new ${resource}` }, ...(opts?.extraCreate ?? {}) },
58
+ async execute(input, ctx) { const t = getConn(ctx); return api(t, "POST", endpoint, input.data); } });
59
+ rl.registerAction(`${resource}.get`, { description: `Get a ${resource}`, inputSchema: { id: { type: "number", required: true } },
60
+ async execute(input, ctx) { const t = getConn(ctx); return api(t, "GET", `${endpoint}/${input.id}`); } });
61
+ rl.registerAction(`${resource}.list`, { description: `List ${resource}s`,
62
+ inputSchema: { limit: { type: "number", required: false }, filterId: { type: "number", required: false } },
63
+ async execute(input, ctx) {
64
+ const t = getConn(ctx);
65
+ const p = (input ?? {});
66
+ const qs = {};
67
+ if (p.filterId)
68
+ qs.filter_id = p.filterId;
69
+ if (p.limit) {
70
+ qs.limit = p.limit;
71
+ return api(t, "GET", endpoint, undefined, qs);
72
+ }
73
+ return paginate(t, endpoint, qs);
74
+ } });
75
+ rl.registerAction(`${resource}.update`, { description: `Update a ${resource}`,
76
+ inputSchema: { id: { type: "number", required: true }, data: { type: "object", required: true, description: `Fields to update` }, ...(opts?.extraUpdate ?? {}) },
77
+ async execute(input, ctx) { const t = getConn(ctx); const p = input; return api(t, updateMethod, `${endpoint}/${p.id}`, p.data); } });
78
+ rl.registerAction(`${resource}.delete`, { description: `Delete a ${resource}`, inputSchema: { id: { type: "number", required: true } },
79
+ async execute(input, ctx) { const t = getConn(ctx); await api(t, "DELETE", `${endpoint}/${input.id}`); return { success: true }; } });
80
+ if (opts?.hasSearch) {
81
+ rl.registerAction(`${resource}.search`, { description: `Search ${resource}s`,
82
+ inputSchema: { term: { type: "string", required: true }, exactMatch: { type: "boolean", required: false }, limit: { type: "number", required: false }, fields: { type: "string", required: false, description: "Comma-separated fields to search" } },
83
+ async execute(input, ctx) {
84
+ const t = getConn(ctx);
85
+ const p = input;
86
+ const qs = { term: p.term };
87
+ if (p.exactMatch)
88
+ qs.exact_match = true;
89
+ if (p.limit)
90
+ qs.limit = p.limit;
91
+ if (p.fields)
92
+ qs.fields = p.fields;
93
+ // Search uses v1 API
94
+ const res = await api(t, "GET", `${endpoint}/search`, undefined, qs, "v1");
95
+ if (Array.isArray(res))
96
+ return res.map((r) => r.item ?? r);
97
+ return res;
98
+ } });
99
+ }
100
+ if (opts?.hasDuplicate) {
101
+ rl.registerAction(`${resource}.duplicate`, { description: `Duplicate a ${resource}`, inputSchema: { id: { type: "number", required: true } },
102
+ async execute(input, ctx) { const t = getConn(ctx); return api(t, "POST", `${endpoint}/${input.id}/duplicate`); } });
103
+ }
104
+ }
105
+ export default function pipedrive(rl) {
106
+ rl.setName("pipedrive");
107
+ rl.setVersion("0.1.0");
108
+ rl.setConnectionSchema({
109
+ apiToken: { type: "string", required: true, description: "Pipedrive API token", env: "PIPEDRIVE_API_TOKEN" },
110
+ });
111
+ // ── Activity ────────────────────────────────────────
112
+ registerCrud(rl, "activity", "/activities");
113
+ // ── Deal ────────────────────────────────────────────
114
+ registerCrud(rl, "deal", "/deals", { hasSearch: true, hasDuplicate: true });
115
+ // ── Deal Product ────────────────────────────────────
116
+ rl.registerAction("dealProduct.add", { description: "Add a product to a deal",
117
+ inputSchema: { dealId: { type: "number", required: true }, productId: { type: "number", required: true }, itemPrice: { type: "number", required: true }, quantity: { type: "number", required: true }, discount: { type: "number", required: false }, discountType: { type: "string", required: false, description: "percentage or amount" }, comments: { type: "string", required: false } },
118
+ async execute(input, ctx) {
119
+ const t = getConn(ctx);
120
+ const { dealId, ...body } = input;
121
+ return api(t, "POST", `/deals/${dealId}/products`, { product_id: body.productId, item_price: body.itemPrice, quantity: body.quantity, ...(body.discount !== undefined ? { discount: body.discount } : {}), ...(body.discountType ? { discount_type: body.discountType } : {}), ...(body.comments ? { comments: body.comments } : {}) });
122
+ } });
123
+ rl.registerAction("dealProduct.list", { description: "List products of a deal",
124
+ inputSchema: { dealId: { type: "number", required: true }, limit: { type: "number", required: false } },
125
+ async execute(input, ctx) {
126
+ const t = getConn(ctx);
127
+ const p = input;
128
+ const qs = {};
129
+ if (p.limit)
130
+ qs.limit = p.limit;
131
+ return api(t, "GET", `/deals/${p.dealId}/products`, undefined, qs);
132
+ } });
133
+ rl.registerAction("dealProduct.update", { description: "Update a product in a deal",
134
+ inputSchema: { dealId: { type: "number", required: true }, productAttachmentId: { type: "number", required: true }, data: { type: "object", required: true } },
135
+ async execute(input, ctx) {
136
+ const t = getConn(ctx);
137
+ const p = input;
138
+ return api(t, "PATCH", `/deals/${p.dealId}/products/${p.productAttachmentId}`, p.data);
139
+ } });
140
+ rl.registerAction("dealProduct.remove", { description: "Remove a product from a deal",
141
+ inputSchema: { dealId: { type: "number", required: true }, productAttachmentId: { type: "number", required: true } },
142
+ async execute(input, ctx) {
143
+ const t = getConn(ctx);
144
+ const p = input;
145
+ await api(t, "DELETE", `/deals/${p.dealId}/products/${p.productAttachmentId}`);
146
+ return { success: true };
147
+ } });
148
+ // ── File (skip create/download — binary) ────────────
149
+ rl.registerAction("file.get", { description: "Get file metadata", inputSchema: { id: { type: "number", required: true } },
150
+ async execute(input, ctx) { return api(getConn(ctx), "GET", `/files/${input.id}`, undefined, undefined, "v1"); } });
151
+ rl.registerAction("file.delete", { description: "Delete a file", inputSchema: { id: { type: "number", required: true } },
152
+ async execute(input, ctx) { await api(getConn(ctx), "DELETE", `/files/${input.id}`, undefined, undefined, "v1"); return { success: true }; } });
153
+ rl.registerAction("file.update", { description: "Update file metadata",
154
+ inputSchema: { id: { type: "number", required: true }, name: { type: "string", required: false }, description: { type: "string", required: false } },
155
+ async execute(input, ctx) {
156
+ const { id, ...body } = input;
157
+ return api(getConn(ctx), "PUT", `/files/${id}`, body, undefined, "v1");
158
+ } });
159
+ // ── Lead ────────────────────────────────────────────
160
+ registerCrud(rl, "lead", "/leads");
161
+ // ── Note ────────────────────────────────────────────
162
+ registerCrud(rl, "note", "/notes");
163
+ // ── Organization ────────────────────────────────────
164
+ registerCrud(rl, "organization", "/organizations", { hasSearch: true });
165
+ // ── Person ──────────────────────────────────────────
166
+ registerCrud(rl, "person", "/persons", { hasSearch: true });
167
+ // ── Product ─────────────────────────────────────────
168
+ registerCrud(rl, "product", "/products", { hasSearch: true });
169
+ }
@@ -0,0 +1,66 @@
1
+ function getConn(ctx) {
2
+ const c = ctx.connection.config;
3
+ return { authId: c.authId, authToken: c.authToken };
4
+ }
5
+ async function apiRequest(conn, method, endpoint, body) {
6
+ const url = `https://api.plivo.com/v1/Account/${conn.authId}${endpoint}/`;
7
+ const res = await fetch(url, {
8
+ method,
9
+ headers: {
10
+ Authorization: "Basic " + btoa(`${conn.authId}:${conn.authToken}`),
11
+ "Content-Type": "application/json",
12
+ },
13
+ body: JSON.stringify(body),
14
+ });
15
+ if (!res.ok)
16
+ throw new Error(`Plivo error ${res.status}: ${await res.text()}`);
17
+ return res.json();
18
+ }
19
+ export default function plivo(rl) {
20
+ rl.setName("plivo");
21
+ rl.setVersion("0.1.0");
22
+ rl.setConnectionSchema({
23
+ authId: { type: "string", required: true, description: "Plivo Auth ID", env: "PLIVO_AUTH_ID" },
24
+ authToken: { type: "string", required: true, description: "Plivo Auth Token", env: "PLIVO_AUTH_TOKEN" },
25
+ });
26
+ rl.registerAction("sms.send", {
27
+ description: "Send an SMS message via Plivo",
28
+ inputSchema: {
29
+ from: { type: "string", required: true, description: "Sender number" },
30
+ to: { type: "string", required: true, description: "Recipient number" },
31
+ message: { type: "string", required: true },
32
+ },
33
+ async execute(input, ctx) {
34
+ const { from, to, message } = input;
35
+ return apiRequest(getConn(ctx), "POST", "/Message", { src: from, dst: to, text: message });
36
+ },
37
+ });
38
+ rl.registerAction("mms.send", {
39
+ description: "Send an MMS message via Plivo",
40
+ inputSchema: {
41
+ from: { type: "string", required: true, description: "Sender number" },
42
+ to: { type: "string", required: true, description: "Recipient number" },
43
+ message: { type: "string", required: true },
44
+ mediaUrls: { type: "string", required: true, description: "Comma-separated media URLs" },
45
+ },
46
+ async execute(input, ctx) {
47
+ const { from, to, message, mediaUrls } = input;
48
+ return apiRequest(getConn(ctx), "POST", "/Message", { src: from, dst: to, text: message, type: "mms", media_urls: mediaUrls });
49
+ },
50
+ });
51
+ rl.registerAction("call.make", {
52
+ description: "Make a phone call via Plivo",
53
+ inputSchema: {
54
+ from: { type: "string", required: true, description: "Caller number" },
55
+ to: { type: "string", required: true, description: "Destination number" },
56
+ answerUrl: { type: "string", required: true, description: "URL for call answer XML" },
57
+ answerMethod: { type: "string", required: false, description: "HTTP method for answer URL (GET or POST, default POST)" },
58
+ },
59
+ async execute(input, ctx) {
60
+ const { from, to, answerUrl, answerMethod } = input;
61
+ return apiRequest(getConn(ctx), "POST", "/Call", {
62
+ from, to, answer_url: answerUrl, answer_method: answerMethod ?? "POST",
63
+ });
64
+ },
65
+ });
66
+ }
@@ -0,0 +1,93 @@
1
+ const BASE = "https://www.postb.in";
2
+ async function apiRequest(method, path, body) {
3
+ const init = { method, headers: { "Content-Type": "application/json" } };
4
+ if (body !== undefined)
5
+ init.body = body;
6
+ const res = await fetch(`${BASE}${path}`, init);
7
+ if (!res.ok)
8
+ throw new Error(`PostBin error ${res.status}: ${await res.text()}`);
9
+ const text = await res.text();
10
+ return text ? JSON.parse(text) : {};
11
+ }
12
+ function parseBinId(binId) {
13
+ const match = /\b\d{13}-\d{13}\b/.exec(binId);
14
+ if (!match)
15
+ throw new Error(`Invalid Bin ID format: ${binId}`);
16
+ return match[0];
17
+ }
18
+ function transformBin(data) {
19
+ const binId = data.binId;
20
+ return {
21
+ binId,
22
+ nowTimestamp: data.now,
23
+ nowIso: new Date(data.now).toISOString(),
24
+ expiresTimestamp: data.expires,
25
+ expiresIso: new Date(data.expires).toISOString(),
26
+ requestUrl: `${BASE}/${binId}`,
27
+ viewUrl: `${BASE}/b/${binId}`,
28
+ };
29
+ }
30
+ export default function postbin(rl) {
31
+ rl.setName("postbin");
32
+ rl.setVersion("0.1.0");
33
+ rl.setConnectionSchema({});
34
+ rl.registerAction("bin.create", {
35
+ description: "Create a new PostBin bin (no auth required)",
36
+ inputSchema: {},
37
+ async execute() {
38
+ const data = (await apiRequest("POST", "/api/bin"));
39
+ return transformBin(data);
40
+ },
41
+ });
42
+ rl.registerAction("bin.get", {
43
+ description: "Get a bin's info",
44
+ inputSchema: { binId: { type: "string", required: true } },
45
+ async execute(input) {
46
+ const id = parseBinId(input.binId);
47
+ const data = (await apiRequest("GET", `/api/bin/${id}`));
48
+ return transformBin(data);
49
+ },
50
+ });
51
+ rl.registerAction("bin.delete", {
52
+ description: "Delete a bin",
53
+ inputSchema: { binId: { type: "string", required: true } },
54
+ async execute(input) {
55
+ const id = parseBinId(input.binId);
56
+ await apiRequest("DELETE", `/api/bin/${id}`);
57
+ return { success: true };
58
+ },
59
+ });
60
+ rl.registerAction("request.get", {
61
+ description: "Get a specific request from a bin",
62
+ inputSchema: {
63
+ binId: { type: "string", required: true },
64
+ requestId: { type: "string", required: true },
65
+ },
66
+ async execute(input) {
67
+ const p = input;
68
+ const id = parseBinId(p.binId);
69
+ return apiRequest("GET", `/api/bin/${id}/req/${p.requestId}`);
70
+ },
71
+ });
72
+ rl.registerAction("request.removeFirst", {
73
+ description: "Remove and return the first request from a bin",
74
+ inputSchema: { binId: { type: "string", required: true } },
75
+ async execute(input) {
76
+ const id = parseBinId(input.binId);
77
+ return apiRequest("GET", `/api/bin/${id}/req/shift`);
78
+ },
79
+ });
80
+ rl.registerAction("request.send", {
81
+ description: "Send a test request to a bin",
82
+ inputSchema: {
83
+ binId: { type: "string", required: true },
84
+ content: { type: "string", required: false, description: "Request body content" },
85
+ },
86
+ async execute(input) {
87
+ const p = input;
88
+ const id = parseBinId(p.binId);
89
+ const data = await apiRequest("POST", `/${id}`, p.content ? JSON.stringify({ content: p.content }) : undefined);
90
+ return { requestId: data };
91
+ },
92
+ });
93
+ }
@@ -0,0 +1,113 @@
1
+ function getConn(ctx) {
2
+ const c = ctx.connection.config;
3
+ return { url: c.url.replace(/\/$/, ""), apiKey: c.apiKey };
4
+ }
5
+ async function apiRequest(conn, endpoint, body) {
6
+ body.api_key = conn.apiKey;
7
+ const res = await fetch(`${conn.url}${endpoint}`, {
8
+ method: "POST",
9
+ headers: { "Content-Type": "application/json" },
10
+ body: JSON.stringify(body),
11
+ });
12
+ if (!res.ok)
13
+ throw new Error(`PostHog error ${res.status}: ${await res.text()}`);
14
+ return res.json();
15
+ }
16
+ export default function posthog(rl) {
17
+ rl.setName("posthog");
18
+ rl.setVersion("0.1.0");
19
+ rl.setConnectionSchema({
20
+ url: { type: "string", required: true, description: "PostHog instance URL (e.g. https://app.posthog.com)", env: "POSTHOG_URL" },
21
+ apiKey: { type: "string", required: true, description: "PostHog project API key", env: "POSTHOG_API_KEY" },
22
+ });
23
+ rl.registerAction("alias.create", {
24
+ description: "Create an alias for a distinct ID",
25
+ inputSchema: {
26
+ distinctId: { type: "string", required: true },
27
+ alias: { type: "string", required: true },
28
+ context: { type: "object", required: false, description: "Context key-value pairs" },
29
+ timestamp: { type: "string", required: false, description: "ISO 8601 timestamp" },
30
+ },
31
+ async execute(input, ctx) {
32
+ const p = input;
33
+ const body = {
34
+ type: "alias", event: "$create_alias",
35
+ context: p.context ?? {},
36
+ properties: { distinct_id: p.distinctId, alias: p.alias },
37
+ };
38
+ if (p.timestamp)
39
+ body.timestamp = p.timestamp;
40
+ return apiRequest(getConn(ctx), "/batch", body);
41
+ },
42
+ });
43
+ rl.registerAction("event.create", {
44
+ description: "Capture one or more events",
45
+ inputSchema: {
46
+ events: { type: "object", required: true, description: "Array of event objects: [{event, distinct_id, properties?, timestamp?}]" },
47
+ },
48
+ async execute(input, ctx) {
49
+ const { events } = input;
50
+ return apiRequest(getConn(ctx), "/capture", { batch: events });
51
+ },
52
+ });
53
+ rl.registerAction("identity.create", {
54
+ description: "Identify a user (set person properties)",
55
+ inputSchema: {
56
+ distinctId: { type: "string", required: true },
57
+ properties: { type: "object", required: false, description: "Person properties to set" },
58
+ timestamp: { type: "string", required: false },
59
+ },
60
+ async execute(input, ctx) {
61
+ const p = input;
62
+ const body = {
63
+ event: "$identify", distinct_id: p.distinctId,
64
+ properties: p.properties ?? {},
65
+ };
66
+ if (p.timestamp)
67
+ body.timestamp = p.timestamp;
68
+ return apiRequest(getConn(ctx), "/batch", body);
69
+ },
70
+ });
71
+ rl.registerAction("track.page", {
72
+ description: "Track a page view",
73
+ inputSchema: {
74
+ distinctId: { type: "string", required: true },
75
+ name: { type: "string", required: true, description: "Page name" },
76
+ properties: { type: "object", required: false },
77
+ context: { type: "object", required: false },
78
+ timestamp: { type: "string", required: false },
79
+ },
80
+ async execute(input, ctx) {
81
+ const p = input;
82
+ const body = {
83
+ type: "page", event: "$page", name: p.name,
84
+ distinct_id: p.distinctId,
85
+ properties: p.properties ?? {}, context: p.context ?? {},
86
+ };
87
+ if (p.timestamp)
88
+ body.timestamp = p.timestamp;
89
+ return apiRequest(getConn(ctx), "/batch", body);
90
+ },
91
+ });
92
+ rl.registerAction("track.screen", {
93
+ description: "Track a screen view",
94
+ inputSchema: {
95
+ distinctId: { type: "string", required: true },
96
+ name: { type: "string", required: true, description: "Screen name" },
97
+ properties: { type: "object", required: false },
98
+ context: { type: "object", required: false },
99
+ timestamp: { type: "string", required: false },
100
+ },
101
+ async execute(input, ctx) {
102
+ const p = input;
103
+ const body = {
104
+ type: "screen", event: "$screen", name: p.name,
105
+ distinct_id: p.distinctId,
106
+ properties: p.properties ?? {}, context: p.context ?? {},
107
+ };
108
+ if (p.timestamp)
109
+ body.timestamp = p.timestamp;
110
+ return apiRequest(getConn(ctx), "/batch", body);
111
+ },
112
+ });
113
+ }
@@ -0,0 +1,50 @@
1
+ const BASE = "https://api.profitwell.com/v2";
2
+ async function apiRequest(token, endpoint, qs) {
3
+ const url = new URL(`${BASE}${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 res = await fetch(url.toString(), { headers: { Authorization: token } });
11
+ if (!res.ok)
12
+ throw new Error(`ProfitWell error ${res.status}: ${await res.text()}`);
13
+ return res.json();
14
+ }
15
+ export default function profitwell(rl) {
16
+ rl.setName("profitwell");
17
+ rl.setVersion("0.1.0");
18
+ rl.setConnectionSchema({
19
+ accessToken: { type: "string", required: true, description: "ProfitWell API access token", env: "PROFITWELL_ACCESS_TOKEN" },
20
+ });
21
+ const key = (ctx) => ctx.connection.config.accessToken;
22
+ rl.registerAction("company.getSettings", {
23
+ description: "Get company settings",
24
+ inputSchema: {},
25
+ async execute(_input, ctx) {
26
+ return apiRequest(key(ctx), "/company/settings/");
27
+ },
28
+ });
29
+ rl.registerAction("metric.get", {
30
+ description: "Get financial metrics (daily or monthly)",
31
+ inputSchema: {
32
+ type: { type: "string", required: true, description: "daily or monthly" },
33
+ month: { type: "string", required: false, description: "Month (YYYY-MM) — required for daily metrics" },
34
+ metrics: { type: "string", required: false, description: "Comma-separated metric names to retrieve" },
35
+ planId: { type: "string", required: false, description: "Filter by plan ID" },
36
+ },
37
+ async execute(input, ctx) {
38
+ const p = (input ?? {});
39
+ const qs = {};
40
+ if (p.month)
41
+ qs.month = p.month;
42
+ if (p.metrics)
43
+ qs.metrics = p.metrics;
44
+ if (p.planId)
45
+ qs.plan_id = p.planId;
46
+ const data = (await apiRequest(key(ctx), `/metrics/${p.type}`, qs));
47
+ return data.data;
48
+ },
49
+ });
50
+ }
@@ -0,0 +1,102 @@
1
+ const BASE = "https://api.pushbullet.com/v2";
2
+ async function apiRequest(token, method, path, body, qs) {
3
+ const url = new URL(`${BASE}${path}`);
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 init = { method, headers: { "Access-Token": token, "Content-Type": "application/json" } };
11
+ if (body && Object.keys(body).length > 0)
12
+ init.body = JSON.stringify(body);
13
+ const res = await fetch(url.toString(), init);
14
+ if (!res.ok)
15
+ throw new Error(`Pushbullet error ${res.status}: ${await res.text()}`);
16
+ const text = await res.text();
17
+ return text ? JSON.parse(text) : {};
18
+ }
19
+ async function paginate(token, path, qs = {}) {
20
+ const all = [];
21
+ let cursor;
22
+ do {
23
+ if (cursor)
24
+ qs.cursor = cursor;
25
+ const data = (await apiRequest(token, "GET", path, undefined, qs));
26
+ const items = (data.pushes ?? []);
27
+ all.push(...items);
28
+ cursor = data.cursor;
29
+ } while (cursor);
30
+ return all;
31
+ }
32
+ export default function pushbullet(rl) {
33
+ rl.setName("pushbullet");
34
+ rl.setVersion("0.1.0");
35
+ rl.setConnectionSchema({
36
+ accessToken: { type: "string", required: true, description: "Pushbullet Access Token", env: "PUSHBULLET_ACCESS_TOKEN" },
37
+ });
38
+ const key = (ctx) => ctx.connection.config.accessToken;
39
+ rl.registerAction("push.create", {
40
+ description: "Create a push (note or link)",
41
+ inputSchema: {
42
+ type: { type: "string", required: true, description: "note or link" },
43
+ title: { type: "string", required: true },
44
+ body: { type: "string", required: true },
45
+ url: { type: "string", required: false, description: "URL (required for link type)" },
46
+ target: { type: "string", required: false, description: "Target: default, device_iden, email, channel_tag" },
47
+ targetValue: { type: "string", required: false, description: "Value for target (device ID, email, or channel tag)" },
48
+ },
49
+ async execute(input, ctx) {
50
+ const p = input;
51
+ const reqBody = { type: p.type, title: p.title, body: p.body };
52
+ if (p.type === "link" && p.url)
53
+ reqBody.url = p.url;
54
+ const target = p.target ?? "default";
55
+ if (target !== "default" && p.targetValue)
56
+ reqBody[target] = p.targetValue;
57
+ return apiRequest(key(ctx), "POST", "/pushes", reqBody);
58
+ },
59
+ });
60
+ rl.registerAction("push.list", {
61
+ description: "List pushes",
62
+ inputSchema: {
63
+ limit: { type: "number", required: false },
64
+ active: { type: "boolean", required: false, description: "Only return non-deleted pushes" },
65
+ modifiedAfter: { type: "string", required: false, description: "ISO timestamp — only return pushes modified after this" },
66
+ },
67
+ async execute(input, ctx) {
68
+ const p = (input ?? {});
69
+ const qs = {};
70
+ if (p.active)
71
+ qs.active = "true";
72
+ if (p.modifiedAfter)
73
+ qs.modified_after = String(Math.floor(new Date(p.modifiedAfter).getTime() / 1000));
74
+ if (p.limit) {
75
+ qs.limit = p.limit;
76
+ const d = (await apiRequest(key(ctx), "GET", "/pushes", undefined, qs));
77
+ return d.pushes;
78
+ }
79
+ return paginate(key(ctx), "/pushes", qs);
80
+ },
81
+ });
82
+ rl.registerAction("push.delete", {
83
+ description: "Delete a push",
84
+ inputSchema: { pushId: { type: "string", required: true } },
85
+ async execute(input, ctx) {
86
+ const { pushId } = input;
87
+ await apiRequest(key(ctx), "DELETE", `/pushes/${pushId}`);
88
+ return { success: true };
89
+ },
90
+ });
91
+ rl.registerAction("push.update", {
92
+ description: "Update a push (dismiss it)",
93
+ inputSchema: {
94
+ pushId: { type: "string", required: true },
95
+ dismissed: { type: "boolean", required: true, description: "Mark push as dismissed" },
96
+ },
97
+ async execute(input, ctx) {
98
+ const { pushId, dismissed } = input;
99
+ return apiRequest(key(ctx), "POST", `/pushes/${pushId}`, { dismissed });
100
+ },
101
+ });
102
+ }
@@ -0,0 +1,39 @@
1
+ const BASE = "https://api.pushcut.io/v1";
2
+ export default function pushcut(rl) {
3
+ rl.setName("pushcut");
4
+ rl.setVersion("0.1.0");
5
+ rl.setConnectionSchema({
6
+ apiKey: { type: "string", required: true, description: "Pushcut API key", env: "PUSHCUT_API_KEY" },
7
+ });
8
+ const key = (ctx) => ctx.connection.config.apiKey;
9
+ rl.registerAction("notification.send", {
10
+ description: "Send a Pushcut notification",
11
+ inputSchema: {
12
+ notificationName: { type: "string", required: true, description: "Notification name or ID" },
13
+ text: { type: "string", required: false, description: "Override notification text" },
14
+ title: { type: "string", required: false, description: "Override notification title" },
15
+ input: { type: "string", required: false, description: "Value passed as input to the action" },
16
+ devices: { type: "object", required: false, description: "Array of device IDs (default: all)" },
17
+ },
18
+ async execute(input, ctx) {
19
+ const p = (input ?? {});
20
+ const body = {};
21
+ if (p.text)
22
+ body.text = p.text;
23
+ if (p.title)
24
+ body.title = p.title;
25
+ if (p.input)
26
+ body.input = p.input;
27
+ if (p.devices)
28
+ body.devices = p.devices;
29
+ const res = await fetch(`${BASE}/notifications/${encodeURIComponent(p.notificationName)}`, {
30
+ method: "POST",
31
+ headers: { "API-Key": key(ctx), "Content-Type": "application/json" },
32
+ body: JSON.stringify(body),
33
+ });
34
+ if (!res.ok)
35
+ throw new Error(`Pushcut error ${res.status}: ${await res.text()}`);
36
+ return res.json();
37
+ },
38
+ });
39
+ }