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,65 @@
1
+ const BASE = "https://api.pushover.net/1";
2
+ export default function pushover(rl) {
3
+ rl.setName("pushover");
4
+ rl.setVersion("0.1.0");
5
+ rl.setConnectionSchema({
6
+ apiToken: { type: "string", required: true, description: "Pushover application API token", env: "PUSHOVER_API_TOKEN" },
7
+ });
8
+ const token = (ctx) => ctx.connection.config.apiToken;
9
+ rl.registerAction("message.push", {
10
+ description: "Send a push notification via Pushover",
11
+ inputSchema: {
12
+ userKey: { type: "string", required: true, description: "User or group key" },
13
+ message: { type: "string", required: true },
14
+ priority: { type: "number", required: false, description: "-2 (lowest) to 2 (emergency), default 0" },
15
+ title: { type: "string", required: false },
16
+ url: { type: "string", required: false, description: "Supplementary URL" },
17
+ urlTitle: { type: "string", required: false },
18
+ sound: { type: "string", required: false, description: "Sound name (e.g. pushover, bike, bugle)" },
19
+ device: { type: "string", required: false, description: "Target device name(s), comma-separated" },
20
+ html: { type: "boolean", required: false, description: "Enable HTML formatting" },
21
+ retry: { type: "number", required: false, description: "Retry interval in seconds (for priority 2, min 30)" },
22
+ expire: { type: "number", required: false, description: "Expiry in seconds (for priority 2, max 10800)" },
23
+ ttl: { type: "number", required: false, description: "Time to live in seconds" },
24
+ },
25
+ async execute(input, ctx) {
26
+ const p = input;
27
+ const body = {
28
+ token: token(ctx),
29
+ user: p.userKey,
30
+ message: p.message,
31
+ };
32
+ if (p.priority !== undefined)
33
+ body.priority = p.priority;
34
+ if (p.title)
35
+ body.title = p.title;
36
+ if (p.url)
37
+ body.url = p.url;
38
+ if (p.urlTitle)
39
+ body.url_title = p.urlTitle;
40
+ if (p.sound)
41
+ body.sound = p.sound;
42
+ if (p.device)
43
+ body.device = p.device;
44
+ if (p.html)
45
+ body.html = 1;
46
+ if (p.retry)
47
+ body.retry = p.retry;
48
+ if (p.expire)
49
+ body.expire = p.expire;
50
+ if (p.ttl)
51
+ body.ttl = p.ttl;
52
+ const formBody = Object.entries(body)
53
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)
54
+ .join("&");
55
+ const res = await fetch(`${BASE}/messages.json`, {
56
+ method: "POST",
57
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
58
+ body: formBody,
59
+ });
60
+ if (!res.ok)
61
+ throw new Error(`Pushover error ${res.status}: ${await res.text()}`);
62
+ return res.json();
63
+ },
64
+ });
65
+ }
@@ -0,0 +1,153 @@
1
+ const BASE = "https://api.quickbase.com/v1";
2
+ function getConn(ctx) {
3
+ const c = ctx.connection.config;
4
+ return { hostname: c.hostname, userToken: c.userToken };
5
+ }
6
+ async function apiRequest(conn, method, endpoint, body, qs) {
7
+ const url = new URL(`${BASE}${endpoint}`);
8
+ if (qs) {
9
+ for (const [k, v] of Object.entries(qs)) {
10
+ if (v !== undefined && v !== null)
11
+ url.searchParams.set(k, String(v));
12
+ }
13
+ }
14
+ const init = {
15
+ method,
16
+ headers: {
17
+ "QB-Realm-Hostname": conn.hostname,
18
+ Authorization: `QB-USER-TOKEN ${conn.userToken}`,
19
+ "Content-Type": "application/json",
20
+ },
21
+ };
22
+ if (body !== undefined)
23
+ init.body = JSON.stringify(body);
24
+ const res = await fetch(url.toString(), init);
25
+ if (!res.ok)
26
+ throw new Error(`QuickBase error ${res.status}: ${await res.text()}`);
27
+ const text = await res.text();
28
+ return text ? JSON.parse(text) : {};
29
+ }
30
+ export default function quickbase(rl) {
31
+ rl.setName("quickbase");
32
+ rl.setVersion("0.1.0");
33
+ rl.setConnectionSchema({
34
+ hostname: { type: "string", required: true, description: "QuickBase realm hostname (e.g. mycompany.quickbase.com)", env: "QUICKBASE_HOSTNAME" },
35
+ userToken: { type: "string", required: true, description: "QuickBase user token", env: "QUICKBASE_USER_TOKEN" },
36
+ });
37
+ rl.registerAction("field.list", {
38
+ description: "List all fields for a table",
39
+ inputSchema: {
40
+ tableId: { type: "string", required: true },
41
+ limit: { type: "number", required: false },
42
+ },
43
+ async execute(input, ctx) {
44
+ const p = input;
45
+ const data = (await apiRequest(getConn(ctx), "GET", "/fields", undefined, { tableId: p.tableId }));
46
+ if (p.limit)
47
+ return data.slice(0, p.limit);
48
+ return data;
49
+ },
50
+ });
51
+ rl.registerAction("file.delete", {
52
+ description: "Delete a file attachment",
53
+ inputSchema: {
54
+ tableId: { type: "string", required: true },
55
+ recordId: { type: "string", required: true },
56
+ fieldId: { type: "string", required: true },
57
+ versionNumber: { type: "string", required: true },
58
+ },
59
+ async execute(input, ctx) {
60
+ const { tableId, recordId, fieldId, versionNumber } = input;
61
+ return apiRequest(getConn(ctx), "DELETE", `/files/${tableId}/${recordId}/${fieldId}/${versionNumber}`);
62
+ },
63
+ });
64
+ rl.registerAction("record.create", {
65
+ description: "Create records in a QuickBase table",
66
+ inputSchema: {
67
+ tableId: { type: "string", required: true },
68
+ data: { type: "object", required: true, description: "Array of record objects with field IDs as keys, e.g. [{\"6\": {\"value\": \"test\"}}]" },
69
+ fieldsToReturn: { type: "object", required: false, description: "Array of field IDs to return (default: [3])" },
70
+ },
71
+ async execute(input, ctx) {
72
+ const p = input;
73
+ const body = { to: p.tableId, data: p.data };
74
+ body.fieldsToReturn = p.fieldsToReturn ?? [3];
75
+ return apiRequest(getConn(ctx), "POST", "/records", body);
76
+ },
77
+ });
78
+ rl.registerAction("record.delete", {
79
+ description: "Delete records matching a query",
80
+ inputSchema: {
81
+ tableId: { type: "string", required: true },
82
+ where: { type: "string", required: true, description: "Query string, e.g. {3.EX.123}" },
83
+ },
84
+ async execute(input, ctx) {
85
+ const { tableId, where } = input;
86
+ return apiRequest(getConn(ctx), "DELETE", "/records", { from: tableId, where });
87
+ },
88
+ });
89
+ rl.registerAction("record.query", {
90
+ description: "Query records from a table",
91
+ inputSchema: {
92
+ tableId: { type: "string", required: true },
93
+ where: { type: "string", required: false, description: "Query string filter" },
94
+ select: { type: "object", required: false, description: "Array of field IDs to return" },
95
+ sortBy: { type: "object", required: false, description: "Array of sort objects [{fieldId, order: 'ASC'|'DESC'}]" },
96
+ limit: { type: "number", required: false },
97
+ },
98
+ async execute(input, ctx) {
99
+ const p = (input ?? {});
100
+ const body = { from: p.tableId };
101
+ if (p.where)
102
+ body.where = p.where;
103
+ if (p.select)
104
+ body.select = p.select;
105
+ if (p.sortBy)
106
+ body.sortBy = p.sortBy;
107
+ if (p.limit)
108
+ body.options = { top: p.limit };
109
+ return apiRequest(getConn(ctx), "POST", "/records/query", body);
110
+ },
111
+ });
112
+ rl.registerAction("record.upsert", {
113
+ description: "Create or update records (upsert) using a merge field",
114
+ inputSchema: {
115
+ tableId: { type: "string", required: true },
116
+ mergeFieldId: { type: "number", required: true, description: "Field ID used as the merge key" },
117
+ data: { type: "object", required: true, description: "Array of record objects" },
118
+ fieldsToReturn: { type: "object", required: false, description: "Array of field IDs to return" },
119
+ },
120
+ async execute(input, ctx) {
121
+ const p = input;
122
+ const body = { to: p.tableId, data: p.data, mergeFieldId: p.mergeFieldId };
123
+ body.fieldsToReturn = p.fieldsToReturn ?? [3];
124
+ return apiRequest(getConn(ctx), "POST", "/records", body);
125
+ },
126
+ });
127
+ rl.registerAction("report.get", {
128
+ description: "Get report metadata",
129
+ inputSchema: {
130
+ tableId: { type: "string", required: true },
131
+ reportId: { type: "string", required: true },
132
+ },
133
+ async execute(input, ctx) {
134
+ const { tableId, reportId } = input;
135
+ return apiRequest(getConn(ctx), "GET", `/reports/${reportId}`, undefined, { tableId });
136
+ },
137
+ });
138
+ rl.registerAction("report.run", {
139
+ description: "Run a report and get results",
140
+ inputSchema: {
141
+ tableId: { type: "string", required: true },
142
+ reportId: { type: "string", required: true },
143
+ limit: { type: "number", required: false },
144
+ },
145
+ async execute(input, ctx) {
146
+ const p = input;
147
+ const qs = { tableId: p.tableId };
148
+ if (p.limit)
149
+ qs.top = p.limit;
150
+ return apiRequest(getConn(ctx), "POST", `/reports/${p.reportId}/run`, {}, qs);
151
+ },
152
+ });
153
+ }
@@ -0,0 +1,73 @@
1
+ function getConn(ctx) {
2
+ const c = ctx.connection.config;
3
+ const sandbox = c.sandbox === true;
4
+ const base = sandbox ? "https://sandbox-quickbooks.api.intuit.com" : "https://quickbooks.api.intuit.com";
5
+ return { base, accessToken: c.accessToken, companyId: c.companyId };
6
+ }
7
+ async function api(conn, method, endpoint, body, qs) {
8
+ const url = new URL(`${conn.base}${endpoint}`);
9
+ if (qs) {
10
+ for (const [k, v] of Object.entries(qs)) {
11
+ if (v !== undefined && v !== null)
12
+ url.searchParams.set(k, String(v));
13
+ }
14
+ }
15
+ const init = { method, headers: { Authorization: `Bearer ${conn.accessToken}`, Accept: "application/json", "Content-Type": "application/json" } };
16
+ if (body && Object.keys(body).length > 0)
17
+ init.body = JSON.stringify(body);
18
+ const res = await fetch(url.toString(), init);
19
+ if (!res.ok)
20
+ throw new Error(`QuickBooks error ${res.status}: ${await res.text()}`);
21
+ return res.json();
22
+ }
23
+ function capitalCase(s) { return s.charAt(0).toUpperCase() + s.slice(1); }
24
+ function registerQbResource(rl, resource, conn) {
25
+ const cap = capitalCase(resource);
26
+ const prefix = (c) => `/v3/company/${c.companyId}`;
27
+ rl.registerAction(`${resource}.create`, { description: `Create a ${resource}`, inputSchema: { data: { type: "object", required: true } },
28
+ async execute(input, ctx) {
29
+ const c = conn(ctx);
30
+ return api(c, "POST", `${prefix(c)}/${resource}`, input.data);
31
+ } });
32
+ rl.registerAction(`${resource}.get`, { description: `Get a ${resource} by ID`, inputSchema: { id: { type: "string", required: true } },
33
+ async execute(input, ctx) {
34
+ const c = conn(ctx);
35
+ const data = (await api(c, "GET", `${prefix(c)}/${resource}/${input.id}`));
36
+ return data[cap];
37
+ } });
38
+ rl.registerAction(`${resource}.query`, { description: `Query ${resource}s (SQL-like)`, inputSchema: { query: { type: "string", required: false, description: `WHERE clause (default: SELECT * FROM ${cap})` }, limit: { type: "number", required: false } },
39
+ async execute(input, ctx) {
40
+ const c = conn(ctx);
41
+ const p = (input ?? {});
42
+ let q = `SELECT * FROM ${cap}`;
43
+ if (p.query)
44
+ q += ` ${p.query}`;
45
+ if (p.limit)
46
+ q += ` MAXRESULTS ${p.limit}`;
47
+ const data = (await api(c, "GET", `${prefix(c)}/query`, undefined, { query: q }));
48
+ return data.QueryResponse?.[cap] ?? [];
49
+ } });
50
+ rl.registerAction(`${resource}.update`, { description: `Update a ${resource} (must include Id and SyncToken)`, inputSchema: { data: { type: "object", required: true } },
51
+ async execute(input, ctx) {
52
+ const c = conn(ctx);
53
+ return api(c, "POST", `${prefix(c)}/${resource}`, input.data);
54
+ } });
55
+ rl.registerAction(`${resource}.delete`, { description: `Delete a ${resource}`, inputSchema: { id: { type: "string", required: true }, syncToken: { type: "string", required: true } },
56
+ async execute(input, ctx) {
57
+ const c = conn(ctx);
58
+ const p = input;
59
+ return api(c, "POST", `${prefix(c)}/${resource}`, { Id: p.id, SyncToken: p.syncToken }, { operation: "delete" });
60
+ } });
61
+ }
62
+ export default function quickbooks(rl) {
63
+ rl.setName("quickbooks");
64
+ rl.setVersion("0.1.0");
65
+ rl.setConnectionSchema({
66
+ accessToken: { type: "string", required: true, description: "QuickBooks OAuth2 access token", env: "QUICKBOOKS_ACCESS_TOKEN" },
67
+ companyId: { type: "string", required: true, description: "QuickBooks Company/Realm ID", env: "QUICKBOOKS_COMPANY_ID" },
68
+ sandbox: { type: "boolean", required: false, description: "Use sandbox environment", env: "QUICKBOOKS_SANDBOX" },
69
+ });
70
+ for (const resource of ["bill", "customer", "employee", "estimate", "invoice", "item", "payment", "purchase", "vendor"]) {
71
+ registerQbResource(rl, resource, getConn);
72
+ }
73
+ }
@@ -0,0 +1,36 @@
1
+ export default function quickchart(rl) {
2
+ rl.setName("quickchart");
3
+ rl.setVersion("0.1.0");
4
+ rl.setConnectionSchema({});
5
+ rl.registerAction("chart.create", {
6
+ description: "Generate a chart image URL via QuickChart.io (no auth required)",
7
+ inputSchema: {
8
+ type: { type: "string", required: true, description: "Chart type: bar, line, pie, doughnut, radar, scatter, etc." },
9
+ labels: { type: "object", required: true, description: "Array of label strings" },
10
+ datasets: { type: "object", required: true, description: "Array of dataset objects [{label, data: [...], backgroundColor?, borderColor?}]" },
11
+ width: { type: "number", required: false, description: "Chart width in pixels (default 500)" },
12
+ height: { type: "number", required: false, description: "Chart height in pixels (default 300)" },
13
+ backgroundColor: { type: "string", required: false, description: "Chart background color" },
14
+ format: { type: "string", required: false, description: "Output format: png (default), svg, webp, pdf" },
15
+ },
16
+ async execute(input) {
17
+ const p = (input ?? {});
18
+ const chart = {
19
+ type: p.type,
20
+ data: { labels: p.labels, datasets: p.datasets },
21
+ };
22
+ const qs = new URLSearchParams();
23
+ qs.set("chart", JSON.stringify(chart));
24
+ if (p.width)
25
+ qs.set("width", String(p.width));
26
+ if (p.height)
27
+ qs.set("height", String(p.height));
28
+ if (p.backgroundColor)
29
+ qs.set("backgroundColor", p.backgroundColor);
30
+ if (p.format)
31
+ qs.set("format", p.format);
32
+ const url = `https://quickchart.io/chart?${qs.toString()}`;
33
+ return { url, chart };
34
+ },
35
+ });
36
+ }
@@ -0,0 +1,209 @@
1
+ const BASE = "https://api.raindrop.io/rest/v1";
2
+ async function apiRequest(token, method, endpoint, body) {
3
+ const init = {
4
+ method,
5
+ headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
6
+ };
7
+ if (body && Object.keys(body).length > 0)
8
+ init.body = JSON.stringify(body);
9
+ const res = await fetch(`${BASE}${endpoint}`, init);
10
+ if (!res.ok)
11
+ throw new Error(`Raindrop error ${res.status}: ${await res.text()}`);
12
+ return res.json();
13
+ }
14
+ export default function raindrop(rl) {
15
+ rl.setName("raindrop");
16
+ rl.setVersion("0.1.0");
17
+ rl.setConnectionSchema({
18
+ accessToken: { type: "string", required: true, description: "Raindrop.io access token", env: "RAINDROP_ACCESS_TOKEN" },
19
+ });
20
+ const key = (ctx) => ctx.connection.config.accessToken;
21
+ // ── Bookmark ────────────────────────────────────────
22
+ rl.registerAction("bookmark.create", {
23
+ description: "Create a bookmark (raindrop)",
24
+ inputSchema: {
25
+ link: { type: "string", required: true, description: "URL to bookmark" },
26
+ collectionId: { type: "string", required: true },
27
+ title: { type: "string", required: false },
28
+ tags: { type: "string", required: false, description: "Comma-separated tags" },
29
+ pleaseParse: { type: "boolean", required: false, description: "Auto-parse page metadata" },
30
+ },
31
+ async execute(input, ctx) {
32
+ const p = input;
33
+ const body = { link: p.link, collection: { $id: Number(p.collectionId) } };
34
+ if (p.title)
35
+ body.title = p.title;
36
+ if (p.tags)
37
+ body.tags = p.tags.split(",").map(t => t.trim());
38
+ if (p.pleaseParse)
39
+ body.pleaseParse = {};
40
+ const data = (await apiRequest(key(ctx), "POST", "/raindrop", body));
41
+ return data.item;
42
+ },
43
+ });
44
+ rl.registerAction("bookmark.get", {
45
+ description: "Get a bookmark by ID",
46
+ inputSchema: { bookmarkId: { type: "string", required: true } },
47
+ async execute(input, ctx) {
48
+ const { bookmarkId } = input;
49
+ const data = (await apiRequest(key(ctx), "GET", `/raindrop/${bookmarkId}`));
50
+ return data.item;
51
+ },
52
+ });
53
+ rl.registerAction("bookmark.list", {
54
+ description: "List bookmarks in a collection",
55
+ inputSchema: {
56
+ collectionId: { type: "string", required: true },
57
+ limit: { type: "number", required: false },
58
+ },
59
+ async execute(input, ctx) {
60
+ const p = input;
61
+ const data = (await apiRequest(key(ctx), "GET", `/raindrops/${p.collectionId}`));
62
+ let items = (data.items ?? []);
63
+ if (p.limit)
64
+ items = items.slice(0, p.limit);
65
+ return items;
66
+ },
67
+ });
68
+ rl.registerAction("bookmark.update", {
69
+ description: "Update a bookmark",
70
+ inputSchema: {
71
+ bookmarkId: { type: "string", required: true },
72
+ title: { type: "string", required: false },
73
+ link: { type: "string", required: false },
74
+ tags: { type: "string", required: false, description: "Comma-separated tags" },
75
+ collectionId: { type: "string", required: false },
76
+ },
77
+ async execute(input, ctx) {
78
+ const p = input;
79
+ const body = {};
80
+ if (p.title)
81
+ body.title = p.title;
82
+ if (p.link)
83
+ body.link = p.link;
84
+ if (p.tags)
85
+ body.tags = p.tags.split(",").map(t => t.trim());
86
+ if (p.collectionId)
87
+ body.collection = { $id: Number(p.collectionId) };
88
+ const data = (await apiRequest(key(ctx), "PUT", `/raindrop/${p.bookmarkId}`, body));
89
+ return data.item;
90
+ },
91
+ });
92
+ rl.registerAction("bookmark.delete", {
93
+ description: "Delete a bookmark",
94
+ inputSchema: { bookmarkId: { type: "string", required: true } },
95
+ async execute(input, ctx) {
96
+ const { bookmarkId } = input;
97
+ return apiRequest(key(ctx), "DELETE", `/raindrop/${bookmarkId}`);
98
+ },
99
+ });
100
+ // ── Collection ──────────────────────────────────────
101
+ rl.registerAction("collection.create", {
102
+ description: "Create a collection",
103
+ inputSchema: {
104
+ title: { type: "string", required: true },
105
+ parentId: { type: "string", required: false, description: "Parent collection ID" },
106
+ },
107
+ async execute(input, ctx) {
108
+ const p = input;
109
+ const body = { title: p.title };
110
+ if (p.parentId)
111
+ body["parent.$id"] = Number(p.parentId);
112
+ const data = (await apiRequest(key(ctx), "POST", "/collection", body));
113
+ return data.item;
114
+ },
115
+ });
116
+ rl.registerAction("collection.get", {
117
+ description: "Get a collection by ID",
118
+ inputSchema: { collectionId: { type: "string", required: true } },
119
+ async execute(input, ctx) {
120
+ const { collectionId } = input;
121
+ const data = (await apiRequest(key(ctx), "GET", `/collection/${collectionId}`));
122
+ return data.item;
123
+ },
124
+ });
125
+ rl.registerAction("collection.list", {
126
+ description: "List collections",
127
+ inputSchema: {
128
+ type: { type: "string", required: false, description: "parent (default) or children" },
129
+ limit: { type: "number", required: false },
130
+ },
131
+ async execute(input, ctx) {
132
+ const p = (input ?? {});
133
+ const endpoint = p.type === "children" ? "/collections/childrens" : "/collections";
134
+ const data = (await apiRequest(key(ctx), "GET", endpoint));
135
+ let items = (data.items ?? []);
136
+ if (p.limit)
137
+ items = items.slice(0, p.limit);
138
+ return items;
139
+ },
140
+ });
141
+ rl.registerAction("collection.update", {
142
+ description: "Update a collection",
143
+ inputSchema: {
144
+ collectionId: { type: "string", required: true },
145
+ title: { type: "string", required: false },
146
+ parentId: { type: "string", required: false },
147
+ },
148
+ async execute(input, ctx) {
149
+ const p = input;
150
+ const body = {};
151
+ if (p.title)
152
+ body.title = p.title;
153
+ if (p.parentId)
154
+ body["parent.$id"] = Number(p.parentId);
155
+ const data = (await apiRequest(key(ctx), "PUT", `/collection/${p.collectionId}`, body));
156
+ return data.item;
157
+ },
158
+ });
159
+ rl.registerAction("collection.delete", {
160
+ description: "Delete a collection",
161
+ inputSchema: { collectionId: { type: "string", required: true } },
162
+ async execute(input, ctx) {
163
+ const { collectionId } = input;
164
+ return apiRequest(key(ctx), "DELETE", `/collection/${collectionId}`);
165
+ },
166
+ });
167
+ // ── Tag ─────────────────────────────────────────────
168
+ rl.registerAction("tag.list", {
169
+ description: "List tags (optionally filtered by collection)",
170
+ inputSchema: {
171
+ collectionId: { type: "string", required: false },
172
+ limit: { type: "number", required: false },
173
+ },
174
+ async execute(input, ctx) {
175
+ const p = (input ?? {});
176
+ const endpoint = p.collectionId ? `/tags/${p.collectionId}` : "/tags";
177
+ const data = (await apiRequest(key(ctx), "GET", endpoint));
178
+ let items = (data.items ?? []);
179
+ if (p.limit)
180
+ items = items.slice(0, p.limit);
181
+ return items;
182
+ },
183
+ });
184
+ rl.registerAction("tag.delete", {
185
+ description: "Delete tags",
186
+ inputSchema: {
187
+ tags: { type: "string", required: true, description: "Comma-separated tag names to delete" },
188
+ collectionId: { type: "string", required: false },
189
+ },
190
+ async execute(input, ctx) {
191
+ const p = input;
192
+ const endpoint = p.collectionId ? `/tags/${p.collectionId}` : "/tags";
193
+ return apiRequest(key(ctx), "DELETE", endpoint, { tags: p.tags.split(",").map(t => t.trim()) });
194
+ },
195
+ });
196
+ // ── User ────────────────────────────────────────────
197
+ rl.registerAction("user.get", {
198
+ description: "Get user info (self or by ID)",
199
+ inputSchema: {
200
+ userId: { type: "string", required: false, description: "User ID (omit for self)" },
201
+ },
202
+ async execute(input, ctx) {
203
+ const userId = input?.userId;
204
+ const endpoint = userId ? `/user/${userId}` : "/user";
205
+ const data = (await apiRequest(key(ctx), "GET", endpoint));
206
+ return data.user;
207
+ },
208
+ });
209
+ }