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,80 @@
1
+ const BASE = "https://api.getvero.com/api/v2";
2
+ async function apiRequest(token, method, endpoint, body) {
3
+ const form = new URLSearchParams();
4
+ form.set("auth_token", token);
5
+ for (const [k, v] of Object.entries(body)) {
6
+ if (v !== undefined && v !== null)
7
+ form.set(k, typeof v === "object" ? JSON.stringify(v) : String(v));
8
+ }
9
+ const res = await fetch(`${BASE}${endpoint}`, { method, headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: form });
10
+ if (!res.ok)
11
+ throw new Error(`Vero error ${res.status}: ${await res.text()}`);
12
+ return res.json();
13
+ }
14
+ export default function vero(rl) {
15
+ rl.setName("vero");
16
+ rl.setVersion("0.1.0");
17
+ rl.setConnectionSchema({ authToken: { type: "string", required: true, description: "Vero auth token", env: "VERO_AUTH_TOKEN" } });
18
+ const key = (ctx) => ctx.connection.config.authToken;
19
+ rl.registerAction("user.create", {
20
+ description: "Create/identify a user",
21
+ inputSchema: { id: { type: "string", required: true }, email: { type: "string", required: false }, data: { type: "object", required: false, description: "Custom attributes" } },
22
+ async execute(input, ctx) {
23
+ const p = input;
24
+ const body = { id: p.id };
25
+ if (p.email)
26
+ body.email = p.email;
27
+ if (p.data)
28
+ body.data = p.data;
29
+ return apiRequest(key(ctx), "POST", "/users/track", body);
30
+ },
31
+ });
32
+ rl.registerAction("user.alias", {
33
+ description: "Alias (re-identify) a user",
34
+ inputSchema: { id: { type: "string", required: true }, newId: { type: "string", required: true } },
35
+ async execute(input, ctx) {
36
+ const p = input;
37
+ return apiRequest(key(ctx), "PUT", "/users/reidentify", { id: p.id, new_id: p.newId });
38
+ },
39
+ });
40
+ for (const op of ["unsubscribe", "resubscribe", "delete"]) {
41
+ rl.registerAction(`user.${op}`, {
42
+ description: `${op.charAt(0).toUpperCase() + op.slice(1)} a user`,
43
+ inputSchema: { id: { type: "string", required: true } },
44
+ async execute(input, ctx) { return apiRequest(key(ctx), "POST", `/users/${op}`, { id: input.id }); },
45
+ });
46
+ }
47
+ rl.registerAction("user.addTags", {
48
+ description: "Add tags to a user",
49
+ inputSchema: { id: { type: "string", required: true }, tags: { type: "string", required: true, description: "Comma-separated tags" } },
50
+ async execute(input, ctx) {
51
+ const p = input;
52
+ return apiRequest(key(ctx), "PUT", "/users/tags/edit", { id: p.id, add: JSON.stringify(p.tags.split(",").map(t => t.trim())) });
53
+ },
54
+ });
55
+ rl.registerAction("user.removeTags", {
56
+ description: "Remove tags from a user",
57
+ inputSchema: { id: { type: "string", required: true }, tags: { type: "string", required: true, description: "Comma-separated tags" } },
58
+ async execute(input, ctx) {
59
+ const p = input;
60
+ return apiRequest(key(ctx), "PUT", "/users/tags/edit", { id: p.id, remove: JSON.stringify(p.tags.split(",").map(t => t.trim())) });
61
+ },
62
+ });
63
+ rl.registerAction("event.track", {
64
+ description: "Track an event",
65
+ inputSchema: {
66
+ id: { type: "string", required: true }, email: { type: "string", required: true },
67
+ eventName: { type: "string", required: true }, data: { type: "object", required: false },
68
+ extras: { type: "object", required: false },
69
+ },
70
+ async execute(input, ctx) {
71
+ const p = input;
72
+ const body = { identity: { id: p.id, email: p.email }, event_name: p.eventName, email: p.email };
73
+ if (p.data)
74
+ body.data = JSON.stringify(p.data);
75
+ if (p.extras)
76
+ body.extras = JSON.stringify(p.extras);
77
+ return apiRequest(key(ctx), "POST", "/events/track", body);
78
+ },
79
+ });
80
+ }
@@ -0,0 +1,42 @@
1
+ export default function vonage(rl) {
2
+ rl.setName("vonage");
3
+ rl.setVersion("0.1.0");
4
+ rl.setConnectionSchema({
5
+ apiKey: { type: "string", required: true, description: "Vonage API key", env: "VONAGE_API_KEY" },
6
+ apiSecret: { type: "string", required: true, description: "Vonage API secret", env: "VONAGE_API_SECRET" },
7
+ });
8
+ rl.registerAction("sms.send", {
9
+ description: "Send an SMS",
10
+ inputSchema: {
11
+ from: { type: "string", required: true, description: "Sender name or number" },
12
+ to: { type: "string", required: true, description: "Recipient number in E.164 format" },
13
+ text: { type: "string", required: true, description: "Message text" },
14
+ ttl: { type: "number", required: false, description: "Time-to-live in minutes (default 4320 = 72h)" },
15
+ callback: { type: "string", required: false, description: "Webhook URL for delivery receipt" },
16
+ },
17
+ async execute(input, ctx) {
18
+ const c = ctx.connection.config;
19
+ const p = input;
20
+ const form = new URLSearchParams();
21
+ form.set("api_key", c.apiKey);
22
+ form.set("api_secret", c.apiSecret);
23
+ form.set("from", p.from);
24
+ form.set("to", p.to);
25
+ form.set("text", p.text);
26
+ form.set("type", "text");
27
+ if (p.ttl)
28
+ form.set("ttl", String(p.ttl * 60000));
29
+ if (p.callback)
30
+ form.set("callback", p.callback);
31
+ const res = await fetch("https://rest.nexmo.com/sms/json", {
32
+ method: "POST",
33
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
34
+ body: form,
35
+ });
36
+ if (!res.ok)
37
+ throw new Error(`Vonage error ${res.status}: ${await res.text()}`);
38
+ const data = (await res.json());
39
+ return data.messages;
40
+ },
41
+ });
42
+ }
@@ -0,0 +1,91 @@
1
+ function getConn(ctx) {
2
+ const c = ctx.connection.config;
3
+ return { url: c.url.replace(/\/$/, ""), token: c.token };
4
+ }
5
+ async function api(conn, method, endpoint, body) {
6
+ const init = { method, headers: { Authorization: `Bearer ${conn.token}`, "Content-Type": "application/json", Accept: "application/json" } };
7
+ if (body && Object.keys(body).length > 0)
8
+ init.body = JSON.stringify(body);
9
+ const res = await fetch(`${conn.url}/api/${endpoint}`, init);
10
+ if (!res.ok)
11
+ throw new Error(`Wekan error ${res.status}: ${await res.text()}`);
12
+ const text = await res.text();
13
+ return text ? JSON.parse(text) : {};
14
+ }
15
+ export default function wekan(rl) {
16
+ rl.setName("wekan");
17
+ rl.setVersion("0.1.0");
18
+ rl.setConnectionSchema({
19
+ url: { type: "string", required: true, description: "Wekan server URL", env: "WEKAN_URL" },
20
+ token: { type: "string", required: true, description: "Wekan API token", env: "WEKAN_TOKEN" },
21
+ });
22
+ // ── Board ───────────────────────────────────────────
23
+ rl.registerAction("board.create", { description: "Create a board", inputSchema: { title: { type: "string", required: true }, owner: { type: "string", required: true } },
24
+ async execute(input, ctx) { return api(getConn(ctx), "POST", "boards", input); } });
25
+ rl.registerAction("board.get", { description: "Get a board", inputSchema: { boardId: { type: "string", required: true } },
26
+ async execute(input, ctx) { return api(getConn(ctx), "GET", `boards/${input.boardId}`); } });
27
+ rl.registerAction("board.list", { description: "List boards for a user", inputSchema: { userId: { type: "string", required: true }, limit: { type: "number", required: false } },
28
+ async execute(input, ctx) {
29
+ const p = input;
30
+ const data = (await api(getConn(ctx), "GET", `users/${p.userId}/boards`));
31
+ return p.limit ? data.slice(0, p.limit) : data;
32
+ } });
33
+ rl.registerAction("board.delete", { description: "Delete a board", inputSchema: { boardId: { type: "string", required: true } },
34
+ async execute(input, ctx) { return api(getConn(ctx), "DELETE", `boards/${input.boardId}`); } });
35
+ // ── List ────────────────────────────────────────────
36
+ rl.registerAction("list.create", { description: "Create a list on a board", inputSchema: { boardId: { type: "string", required: true }, title: { type: "string", required: true } },
37
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "POST", `boards/${p.boardId}/lists`, { title: p.title }); } });
38
+ rl.registerAction("list.get", { description: "Get a list", inputSchema: { boardId: { type: "string", required: true }, listId: { type: "string", required: true } },
39
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "GET", `boards/${p.boardId}/lists/${p.listId}`); } });
40
+ rl.registerAction("list.listAll", { description: "List all lists on a board", inputSchema: { boardId: { type: "string", required: true }, limit: { type: "number", required: false } },
41
+ async execute(input, ctx) {
42
+ const p = input;
43
+ const data = (await api(getConn(ctx), "GET", `boards/${p.boardId}/lists`));
44
+ return p.limit ? data.slice(0, p.limit) : data;
45
+ } });
46
+ rl.registerAction("list.delete", { description: "Delete a list", inputSchema: { boardId: { type: "string", required: true }, listId: { type: "string", required: true } },
47
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "DELETE", `boards/${p.boardId}/lists/${p.listId}`); } });
48
+ // ── Card ────────────────────────────────────────────
49
+ rl.registerAction("card.create", { description: "Create a card", inputSchema: { boardId: { type: "string", required: true }, listId: { type: "string", required: true }, title: { type: "string", required: true }, swimlaneId: { type: "string", required: true }, authorId: { type: "string", required: true }, description: { type: "string", required: false } },
50
+ async execute(input, ctx) {
51
+ const { boardId, listId, ...body } = input;
52
+ return api(getConn(ctx), "POST", `boards/${boardId}/lists/${listId}/cards`, body);
53
+ } });
54
+ rl.registerAction("card.get", { description: "Get a card", inputSchema: { boardId: { type: "string", required: true }, listId: { type: "string", required: true }, cardId: { type: "string", required: true } },
55
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "GET", `boards/${p.boardId}/lists/${p.listId}/cards/${p.cardId}`); } });
56
+ rl.registerAction("card.list", { description: "List cards in a list", inputSchema: { boardId: { type: "string", required: true }, listId: { type: "string", required: true }, limit: { type: "number", required: false } },
57
+ async execute(input, ctx) {
58
+ const p = input;
59
+ const data = (await api(getConn(ctx), "GET", `boards/${p.boardId}/lists/${p.listId}/cards`));
60
+ return p.limit ? data.slice(0, p.limit) : data;
61
+ } });
62
+ rl.registerAction("card.update", { description: "Update a card", inputSchema: { boardId: { type: "string", required: true }, listId: { type: "string", required: true }, cardId: { type: "string", required: true }, data: { type: "object", required: true } },
63
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "PUT", `boards/${p.boardId}/lists/${p.listId}/cards/${p.cardId}`, p.data); } });
64
+ rl.registerAction("card.delete", { description: "Delete a card", inputSchema: { boardId: { type: "string", required: true }, listId: { type: "string", required: true }, cardId: { type: "string", required: true } },
65
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "DELETE", `boards/${p.boardId}/lists/${p.listId}/cards/${p.cardId}`); } });
66
+ // ── Card Comment ────────────────────────────────────
67
+ rl.registerAction("cardComment.create", { description: "Add a comment to a card", inputSchema: { boardId: { type: "string", required: true }, cardId: { type: "string", required: true }, authorId: { type: "string", required: true }, comment: { type: "string", required: true } },
68
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "POST", `boards/${p.boardId}/cards/${p.cardId}/comments`, { authorId: p.authorId, comment: p.comment }); } });
69
+ rl.registerAction("cardComment.get", { description: "Get a comment", inputSchema: { boardId: { type: "string", required: true }, cardId: { type: "string", required: true }, commentId: { type: "string", required: true } },
70
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "GET", `boards/${p.boardId}/cards/${p.cardId}/comments/${p.commentId}`); } });
71
+ rl.registerAction("cardComment.list", { description: "List comments on a card", inputSchema: { boardId: { type: "string", required: true }, cardId: { type: "string", required: true } },
72
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "GET", `boards/${p.boardId}/cards/${p.cardId}/comments`); } });
73
+ rl.registerAction("cardComment.delete", { description: "Delete a comment", inputSchema: { boardId: { type: "string", required: true }, cardId: { type: "string", required: true }, commentId: { type: "string", required: true } },
74
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "DELETE", `boards/${p.boardId}/cards/${p.cardId}/comments/${p.commentId}`); } });
75
+ // ── Checklist ───────────────────────────────────────
76
+ rl.registerAction("checklist.create", { description: "Create a checklist on a card", inputSchema: { boardId: { type: "string", required: true }, cardId: { type: "string", required: true }, title: { type: "string", required: true }, items: { type: "object", required: false, description: "Array of item titles" } },
77
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "POST", `boards/${p.boardId}/cards/${p.cardId}/checklists`, { title: p.title, items: p.items }); } });
78
+ rl.registerAction("checklist.get", { description: "Get a checklist", inputSchema: { boardId: { type: "string", required: true }, cardId: { type: "string", required: true }, checklistId: { type: "string", required: true } },
79
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "GET", `boards/${p.boardId}/cards/${p.cardId}/checklists/${p.checklistId}`); } });
80
+ rl.registerAction("checklist.list", { description: "List checklists on a card", inputSchema: { boardId: { type: "string", required: true }, cardId: { type: "string", required: true } },
81
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "GET", `boards/${p.boardId}/cards/${p.cardId}/checklists`); } });
82
+ rl.registerAction("checklist.delete", { description: "Delete a checklist", inputSchema: { boardId: { type: "string", required: true }, cardId: { type: "string", required: true }, checklistId: { type: "string", required: true } },
83
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "DELETE", `boards/${p.boardId}/cards/${p.cardId}/checklists/${p.checklistId}`); } });
84
+ // ── Checklist Item ──────────────────────────────────
85
+ rl.registerAction("checklistItem.get", { description: "Get a checklist item", inputSchema: { boardId: { type: "string", required: true }, cardId: { type: "string", required: true }, checklistId: { type: "string", required: true }, itemId: { type: "string", required: true } },
86
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "GET", `boards/${p.boardId}/cards/${p.cardId}/checklists/${p.checklistId}/items/${p.itemId}`); } });
87
+ rl.registerAction("checklistItem.update", { description: "Update a checklist item", inputSchema: { boardId: { type: "string", required: true }, cardId: { type: "string", required: true }, checklistId: { type: "string", required: true }, itemId: { type: "string", required: true }, data: { type: "object", required: true } },
88
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "PUT", `boards/${p.boardId}/cards/${p.cardId}/checklists/${p.checklistId}/items/${p.itemId}`, p.data); } });
89
+ rl.registerAction("checklistItem.delete", { description: "Delete a checklist item", inputSchema: { boardId: { type: "string", required: true }, cardId: { type: "string", required: true }, checklistId: { type: "string", required: true }, itemId: { type: "string", required: true } },
90
+ async execute(input, ctx) { const p = input; return api(getConn(ctx), "DELETE", `boards/${p.boardId}/cards/${p.cardId}/checklists/${p.checklistId}/items/${p.itemId}`); } });
91
+ }
@@ -0,0 +1,92 @@
1
+ function getConn(ctx) {
2
+ const c = ctx.connection.config;
3
+ return { url: c.url.replace(/\/$/, ""), consumerKey: c.consumerKey, consumerSecret: c.consumerSecret };
4
+ }
5
+ async function apiRequest(conn, method, endpoint, body, qs) {
6
+ const url = new URL(`${conn.url}/wp-json/wc/v3${endpoint}`);
7
+ if (qs) {
8
+ for (const [k, v] of Object.entries(qs)) {
9
+ if (v !== undefined && v !== null)
10
+ url.searchParams.set(k, String(v));
11
+ }
12
+ }
13
+ const init = {
14
+ method,
15
+ headers: { Authorization: `Basic ${btoa(`${conn.consumerKey}:${conn.consumerSecret}`)}`, "Content-Type": "application/json" },
16
+ };
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(`WooCommerce error ${res.status}: ${await res.text()}`);
22
+ return res.json();
23
+ }
24
+ function registerCrud(rl, resource, plural, conn, createSchema) {
25
+ rl.registerAction(`${resource}.create`, {
26
+ description: `Create a ${resource}`,
27
+ inputSchema: createSchema,
28
+ async execute(input, ctx) { return apiRequest(conn(ctx), "POST", `/${plural}`, input); },
29
+ });
30
+ rl.registerAction(`${resource}.get`, {
31
+ description: `Get a ${resource} by ID`,
32
+ inputSchema: { id: { type: "string", required: true } },
33
+ async execute(input, ctx) { return apiRequest(conn(ctx), "GET", `/${plural}/${input.id}`); },
34
+ });
35
+ rl.registerAction(`${resource}.list`, {
36
+ description: `List ${plural}`,
37
+ inputSchema: { limit: { type: "number", required: false }, search: { type: "string", required: false }, status: { type: "string", required: false } },
38
+ async execute(input, ctx) {
39
+ const p = (input ?? {});
40
+ const qs = {};
41
+ if (p.limit)
42
+ qs.per_page = p.limit;
43
+ if (p.search)
44
+ qs.search = p.search;
45
+ if (p.status)
46
+ qs.status = p.status;
47
+ return apiRequest(conn(ctx), "GET", `/${plural}`, undefined, qs);
48
+ },
49
+ });
50
+ rl.registerAction(`${resource}.update`, {
51
+ description: `Update a ${resource}`,
52
+ inputSchema: { id: { type: "string", required: true }, data: { type: "object", required: true } },
53
+ async execute(input, ctx) {
54
+ const p = input;
55
+ return apiRequest(conn(ctx), "PUT", `/${plural}/${p.id}`, p.data);
56
+ },
57
+ });
58
+ rl.registerAction(`${resource}.delete`, {
59
+ description: `Delete a ${resource}`,
60
+ inputSchema: { id: { type: "string", required: true } },
61
+ async execute(input, ctx) {
62
+ return apiRequest(conn(ctx), "DELETE", `/${plural}/${input.id}`, undefined, { force: "true" });
63
+ },
64
+ });
65
+ }
66
+ export default function woocommerce(rl) {
67
+ rl.setName("woocommerce");
68
+ rl.setVersion("0.1.0");
69
+ rl.setConnectionSchema({
70
+ url: { type: "string", required: true, description: "WooCommerce store URL", env: "WOOCOMMERCE_URL" },
71
+ consumerKey: { type: "string", required: true, description: "WooCommerce consumer key", env: "WOOCOMMERCE_CONSUMER_KEY" },
72
+ consumerSecret: { type: "string", required: true, description: "WooCommerce consumer secret", env: "WOOCOMMERCE_CONSUMER_SECRET" },
73
+ });
74
+ registerCrud(rl, "product", "products", getConn, {
75
+ name: { type: "string", required: true },
76
+ type: { type: "string", required: false, description: "simple, grouped, external, variable" },
77
+ regular_price: { type: "string", required: false },
78
+ description: { type: "string", required: false },
79
+ sku: { type: "string", required: false },
80
+ });
81
+ registerCrud(rl, "order", "orders", getConn, {
82
+ status: { type: "string", required: false, description: "pending, processing, on-hold, completed, cancelled, refunded, failed" },
83
+ customer_id: { type: "number", required: false },
84
+ line_items: { type: "object", required: false, description: "Array of { product_id, quantity }" },
85
+ payment_method: { type: "string", required: false },
86
+ });
87
+ registerCrud(rl, "customer", "customers", getConn, {
88
+ email: { type: "string", required: true },
89
+ first_name: { type: "string", required: false },
90
+ last_name: { type: "string", required: false },
91
+ });
92
+ }
@@ -0,0 +1,121 @@
1
+ function getConn(ctx) {
2
+ const c = ctx.connection.config;
3
+ return { url: c.url.replace(/\/$/, ""), username: c.username, password: c.password };
4
+ }
5
+ async function apiRequest(conn, method, endpoint, body, qs) {
6
+ const url = new URL(`${conn.url}/wp-json/wp/v2${endpoint}`);
7
+ if (qs) {
8
+ for (const [k, v] of Object.entries(qs)) {
9
+ if (v !== undefined && v !== null)
10
+ url.searchParams.set(k, String(v));
11
+ }
12
+ }
13
+ const init = {
14
+ method,
15
+ headers: { Authorization: `Basic ${btoa(`${conn.username}:${conn.password}`)}`, "Content-Type": "application/json", Accept: "application/json" },
16
+ };
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(`WordPress error ${res.status}: ${await res.text()}`);
22
+ return res.json();
23
+ }
24
+ function registerContentCrud(rl, resource, plural, conn) {
25
+ rl.registerAction(`${resource}.create`, {
26
+ description: `Create a ${resource}`,
27
+ inputSchema: { title: { type: "string", required: true }, content: { type: "string", required: false }, status: { type: "string", required: false, description: "publish, draft, pending, private" }, slug: { type: "string", required: false } },
28
+ async execute(input, ctx) { return apiRequest(conn(ctx), "POST", `/${plural}`, input); },
29
+ });
30
+ rl.registerAction(`${resource}.get`, {
31
+ description: `Get a ${resource} by ID`,
32
+ inputSchema: { id: { type: "string", required: true } },
33
+ async execute(input, ctx) { return apiRequest(conn(ctx), "GET", `/${plural}/${input.id}`); },
34
+ });
35
+ rl.registerAction(`${resource}.list`, {
36
+ description: `List ${plural}`,
37
+ inputSchema: { limit: { type: "number", required: false }, search: { type: "string", required: false }, status: { type: "string", required: false }, orderby: { type: "string", required: false } },
38
+ async execute(input, ctx) {
39
+ const p = (input ?? {});
40
+ const qs = {};
41
+ if (p.limit)
42
+ qs.per_page = p.limit;
43
+ if (p.search)
44
+ qs.search = p.search;
45
+ if (p.status)
46
+ qs.status = p.status;
47
+ if (p.orderby)
48
+ qs.orderby = p.orderby;
49
+ return apiRequest(conn(ctx), "GET", `/${plural}`, undefined, qs);
50
+ },
51
+ });
52
+ rl.registerAction(`${resource}.update`, {
53
+ description: `Update a ${resource}`,
54
+ inputSchema: { id: { type: "string", required: true }, title: { type: "string", required: false }, content: { type: "string", required: false }, status: { type: "string", required: false }, slug: { type: "string", required: false } },
55
+ async execute(input, ctx) {
56
+ const { id, ...fields } = input;
57
+ return apiRequest(conn(ctx), "POST", `/${plural}/${id}`, fields);
58
+ },
59
+ });
60
+ rl.registerAction(`${resource}.delete`, {
61
+ description: `Delete a ${resource}`,
62
+ inputSchema: { id: { type: "string", required: true }, force: { type: "boolean", required: false } },
63
+ async execute(input, ctx) {
64
+ const p = input;
65
+ const qs = {};
66
+ if (p.force)
67
+ qs.force = "true";
68
+ return apiRequest(conn(ctx), "DELETE", `/${plural}/${p.id}`, undefined, qs);
69
+ },
70
+ });
71
+ }
72
+ export default function wordpress(rl) {
73
+ rl.setName("wordpress");
74
+ rl.setVersion("0.1.0");
75
+ rl.setConnectionSchema({
76
+ url: { type: "string", required: true, description: "WordPress site URL", env: "WORDPRESS_URL" },
77
+ username: { type: "string", required: true, description: "WordPress username", env: "WORDPRESS_USERNAME" },
78
+ password: { type: "string", required: true, description: "WordPress application password", env: "WORDPRESS_PASSWORD" },
79
+ });
80
+ registerContentCrud(rl, "post", "posts", getConn);
81
+ registerContentCrud(rl, "page", "pages", getConn);
82
+ // ── User ────────────────────────────────────────────
83
+ rl.registerAction("user.create", {
84
+ description: "Create a user",
85
+ inputSchema: { username: { type: "string", required: true }, email: { type: "string", required: true }, password: { type: "string", required: true }, name: { type: "string", required: false } },
86
+ async execute(input, ctx) { return apiRequest(getConn(ctx), "POST", "/users", input); },
87
+ });
88
+ rl.registerAction("user.get", {
89
+ description: "Get a user by ID",
90
+ inputSchema: { id: { type: "string", required: true } },
91
+ async execute(input, ctx) { return apiRequest(getConn(ctx), "GET", `/users/${input.id}`); },
92
+ });
93
+ rl.registerAction("user.list", {
94
+ description: "List users",
95
+ inputSchema: { limit: { type: "number", required: false }, search: { type: "string", required: false } },
96
+ async execute(input, ctx) {
97
+ const p = (input ?? {});
98
+ const qs = {};
99
+ if (p.limit)
100
+ qs.per_page = p.limit;
101
+ if (p.search)
102
+ qs.search = p.search;
103
+ return apiRequest(getConn(ctx), "GET", "/users", undefined, qs);
104
+ },
105
+ });
106
+ rl.registerAction("user.update", {
107
+ description: "Update a user",
108
+ inputSchema: { id: { type: "string", required: true }, name: { type: "string", required: false }, email: { type: "string", required: false }, description: { type: "string", required: false } },
109
+ async execute(input, ctx) {
110
+ const { id, ...fields } = input;
111
+ return apiRequest(getConn(ctx), "POST", `/users/${id}`, fields);
112
+ },
113
+ });
114
+ rl.registerAction("user.delete", {
115
+ description: "Delete the current user",
116
+ inputSchema: { reassign: { type: "string", required: true, description: "User ID to reassign content to" } },
117
+ async execute(input, ctx) {
118
+ return apiRequest(getConn(ctx), "DELETE", "/users/me", undefined, { reassign: input.reassign, force: "true" });
119
+ },
120
+ });
121
+ }
@@ -0,0 +1,136 @@
1
+ const BASE = "https://api.xero.com/api.xro/2.0";
2
+ function getConn(ctx) {
3
+ return { accessToken: ctx.connection.config.accessToken, tenantId: ctx.connection.config.tenantId };
4
+ }
5
+ async function api(conn, method, endpoint, body, qs) {
6
+ const url = new URL(`${BASE}${endpoint}`);
7
+ if (qs) {
8
+ for (const [k, v] of Object.entries(qs)) {
9
+ if (v !== undefined && v !== null)
10
+ url.searchParams.set(k, String(v));
11
+ }
12
+ }
13
+ const init = { method, headers: { Authorization: `Bearer ${conn.accessToken}`, "Xero-tenant-id": conn.tenantId, "Content-Type": "application/json" } };
14
+ if (body && Object.keys(body).length > 0)
15
+ init.body = JSON.stringify(body);
16
+ const res = await fetch(url.toString(), init);
17
+ if (!res.ok)
18
+ throw new Error(`Xero error ${res.status}: ${await res.text()}`);
19
+ return res.json();
20
+ }
21
+ export default function xero(rl) {
22
+ rl.setName("xero");
23
+ rl.setVersion("0.1.0");
24
+ rl.setConnectionSchema({
25
+ accessToken: { type: "string", required: true, description: "Xero OAuth2 access token", env: "XERO_ACCESS_TOKEN" },
26
+ tenantId: { type: "string", required: true, description: "Xero tenant/organization ID", env: "XERO_TENANT_ID" },
27
+ });
28
+ // ── Invoice ─────────────────────────────────────────
29
+ rl.registerAction("invoice.create", {
30
+ description: "Create an invoice",
31
+ inputSchema: {
32
+ Type: { type: "string", required: true, description: "ACCREC (sales) or ACCPAY (bills)" },
33
+ ContactID: { type: "string", required: true },
34
+ LineItems: { type: "object", required: false, description: "Array of line items" },
35
+ Status: { type: "string", required: false, description: "DRAFT, SUBMITTED, AUTHORISED" },
36
+ Date: { type: "string", required: false },
37
+ DueDate: { type: "string", required: false },
38
+ Reference: { type: "string", required: false },
39
+ CurrencyCode: { type: "string", required: false },
40
+ },
41
+ async execute(input, ctx) {
42
+ const p = input;
43
+ const body = { Type: p.Type, Contact: { ContactID: p.ContactID } };
44
+ if (p.LineItems)
45
+ body.LineItems = p.LineItems;
46
+ if (p.Status)
47
+ body.Status = p.Status;
48
+ if (p.Date)
49
+ body.Date = p.Date;
50
+ if (p.DueDate)
51
+ body.DueDate = p.DueDate;
52
+ if (p.Reference)
53
+ body.Reference = p.Reference;
54
+ if (p.CurrencyCode)
55
+ body.CurrencyCode = p.CurrencyCode;
56
+ const data = (await api(getConn(ctx), "POST", "/Invoices", body));
57
+ return data.Invoices;
58
+ },
59
+ });
60
+ rl.registerAction("invoice.get", {
61
+ description: "Get an invoice by ID",
62
+ inputSchema: { invoiceId: { type: "string", required: true } },
63
+ async execute(input, ctx) {
64
+ const data = (await api(getConn(ctx), "GET", `/Invoices/${input.invoiceId}`));
65
+ return data.Invoices;
66
+ },
67
+ });
68
+ rl.registerAction("invoice.list", {
69
+ description: "List invoices",
70
+ inputSchema: { limit: { type: "number", required: false }, statuses: { type: "string", required: false, description: "Comma-separated statuses" }, where: { type: "string", required: false } },
71
+ async execute(input, ctx) {
72
+ const p = (input ?? {});
73
+ const qs = {};
74
+ if (p.statuses)
75
+ qs.statuses = p.statuses;
76
+ if (p.where)
77
+ qs.where = p.where;
78
+ const data = (await api(getConn(ctx), "GET", "/Invoices", undefined, qs));
79
+ const invoices = data.Invoices;
80
+ return p.limit ? invoices.slice(0, p.limit) : invoices;
81
+ },
82
+ });
83
+ rl.registerAction("invoice.update", {
84
+ description: "Update an invoice",
85
+ inputSchema: { invoiceId: { type: "string", required: true }, data: { type: "object", required: true, description: "Fields to update (Xero API format)" } },
86
+ async execute(input, ctx) {
87
+ const p = input;
88
+ const result = (await api(getConn(ctx), "POST", `/Invoices/${p.invoiceId}`, p.data));
89
+ return result.Invoices;
90
+ },
91
+ });
92
+ // ── Contact ─────────────────────────────────────────
93
+ rl.registerAction("contact.create", {
94
+ description: "Create a contact",
95
+ inputSchema: { Name: { type: "string", required: true }, EmailAddress: { type: "string", required: false }, FirstName: { type: "string", required: false }, LastName: { type: "string", required: false } },
96
+ async execute(input, ctx) {
97
+ const p = input;
98
+ const body = { Contacts: [p] };
99
+ const data = (await api(getConn(ctx), "POST", "/Contacts", body));
100
+ return data.Contacts;
101
+ },
102
+ });
103
+ rl.registerAction("contact.get", {
104
+ description: "Get a contact by ID",
105
+ inputSchema: { contactId: { type: "string", required: true } },
106
+ async execute(input, ctx) {
107
+ const data = (await api(getConn(ctx), "GET", `/Contacts/${input.contactId}`));
108
+ return data.Contacts;
109
+ },
110
+ });
111
+ rl.registerAction("contact.list", {
112
+ description: "List contacts",
113
+ inputSchema: { limit: { type: "number", required: false }, where: { type: "string", required: false }, includeArchived: { type: "boolean", required: false } },
114
+ async execute(input, ctx) {
115
+ const p = (input ?? {});
116
+ const qs = {};
117
+ if (p.where)
118
+ qs.where = p.where;
119
+ if (p.includeArchived)
120
+ qs.includeArchived = "true";
121
+ const data = (await api(getConn(ctx), "GET", "/Contacts", undefined, qs));
122
+ const contacts = data.Contacts;
123
+ return p.limit ? contacts.slice(0, p.limit) : contacts;
124
+ },
125
+ });
126
+ rl.registerAction("contact.update", {
127
+ description: "Update a contact",
128
+ inputSchema: { contactId: { type: "string", required: true }, data: { type: "object", required: true, description: "Fields to update (Xero API format)" } },
129
+ async execute(input, ctx) {
130
+ const p = input;
131
+ const body = { Contacts: [p.data] };
132
+ const result = (await api(getConn(ctx), "POST", `/Contacts/${p.contactId}`, body));
133
+ return result.Contacts;
134
+ },
135
+ });
136
+ }
@@ -0,0 +1,56 @@
1
+ function getConn(ctx) {
2
+ const c = ctx.connection.config;
3
+ return { url: c.url.replace(/\/$/, ""), signature: c.signature };
4
+ }
5
+ async function apiRequest(conn, qs) {
6
+ const url = new URL(`${conn.url}/yourls-api.php`);
7
+ qs.signature = conn.signature;
8
+ qs.format = "json";
9
+ for (const [k, v] of Object.entries(qs)) {
10
+ if (v !== undefined && v !== null)
11
+ url.searchParams.set(k, String(v));
12
+ }
13
+ const res = await fetch(url.toString());
14
+ if (!res.ok)
15
+ throw new Error(`Yourls error ${res.status}: ${await res.text()}`);
16
+ const data = (await res.json());
17
+ if (data.status === "fail")
18
+ throw new Error(`Yourls error: ${data.message}`);
19
+ return data;
20
+ }
21
+ export default function yourls(rl) {
22
+ rl.setName("yourls");
23
+ rl.setVersion("0.1.0");
24
+ rl.setConnectionSchema({
25
+ url: { type: "string", required: true, description: "Yourls installation URL", env: "YOURLS_URL" },
26
+ signature: { type: "string", required: true, description: "Yourls signature token", env: "YOURLS_SIGNATURE" },
27
+ });
28
+ rl.registerAction("url.shorten", {
29
+ description: "Shorten a URL",
30
+ inputSchema: { url: { type: "string", required: true }, keyword: { type: "string", required: false, description: "Custom short URL keyword" }, title: { type: "string", required: false } },
31
+ async execute(input, ctx) {
32
+ const p = input;
33
+ const qs = { action: "shorturl", url: p.url };
34
+ if (p.keyword)
35
+ qs.keyword = p.keyword;
36
+ if (p.title)
37
+ qs.title = p.title;
38
+ return apiRequest(getConn(ctx), qs);
39
+ },
40
+ });
41
+ rl.registerAction("url.expand", {
42
+ description: "Expand a short URL to its original",
43
+ inputSchema: { shortUrl: { type: "string", required: true } },
44
+ async execute(input, ctx) {
45
+ return apiRequest(getConn(ctx), { action: "expand", shorturl: input.shortUrl });
46
+ },
47
+ });
48
+ rl.registerAction("url.stats", {
49
+ description: "Get stats for a short URL",
50
+ inputSchema: { shortUrl: { type: "string", required: true } },
51
+ async execute(input, ctx) {
52
+ const data = (await apiRequest(getConn(ctx), { action: "url-stats", shorturl: input.shortUrl }));
53
+ return data.link;
54
+ },
55
+ });
56
+ }