runline 0.2.1 → 0.3.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 (203) hide show
  1. package/dist/commands/auth.d.ts +7 -0
  2. package/dist/commands/auth.js +96 -0
  3. package/dist/config/loader.d.ts +11 -0
  4. package/dist/config/loader.js +46 -0
  5. package/dist/core/engine.js +7 -1
  6. package/dist/core/oauth.d.ts +46 -0
  7. package/dist/core/oauth.js +145 -0
  8. package/dist/index.d.ts +4 -2
  9. package/dist/index.js +2 -1
  10. package/dist/main.js +28 -0
  11. package/dist/plugin/api.d.ts +7 -1
  12. package/dist/plugin/api.js +7 -0
  13. package/dist/plugin/types.d.ts +47 -0
  14. package/dist/plugins/actionNetwork/src/index.js +118 -25
  15. package/dist/plugins/activeCampaign/src/index.js +184 -38
  16. package/dist/plugins/adalo/src/index.js +40 -8
  17. package/dist/plugins/affinity/src/index.js +100 -20
  18. package/dist/plugins/agileCrm/src/index.js +115 -27
  19. package/dist/plugins/airtable/src/index.js +94 -19
  20. package/dist/plugins/airtop/src/index.js +266 -62
  21. package/dist/plugins/apiTemplateIo/src/index.js +25 -5
  22. package/dist/plugins/asana/src/index.js +195 -41
  23. package/dist/plugins/autopilot/src/index.js +39 -8
  24. package/dist/plugins/bambooHr/src/index.js +109 -22
  25. package/dist/plugins/bannerbear/src/index.js +36 -8
  26. package/dist/plugins/baserow/src/index.js +35 -7
  27. package/dist/plugins/beeminder/src/index.js +198 -40
  28. package/dist/plugins/bitly/src/index.js +46 -10
  29. package/dist/plugins/bitwarden/src/index.js +167 -36
  30. package/dist/plugins/box/src/index.js +172 -37
  31. package/dist/plugins/brandfetch/src/index.js +5 -1
  32. package/dist/plugins/brevo/src/index.js +136 -29
  33. package/dist/plugins/bubble/src/index.js +76 -17
  34. package/dist/plugins/chargebee/src/index.js +35 -7
  35. package/dist/plugins/circleci/src/index.js +50 -10
  36. package/dist/plugins/ciscoWebex/src/index.js +131 -27
  37. package/dist/plugins/clearbit/src/index.js +76 -17
  38. package/dist/plugins/clickup/src/index.js +500 -107
  39. package/dist/plugins/clockify/src/index.js +229 -47
  40. package/dist/plugins/cloudflare/src/index.js +28 -6
  41. package/dist/plugins/cockpit/src/index.js +54 -12
  42. package/dist/plugins/coda/src/index.js +81 -19
  43. package/dist/plugins/coingecko/src/index.js +157 -33
  44. package/dist/plugins/contentful/src/index.js +85 -17
  45. package/dist/plugins/convertkit/src/index.js +74 -18
  46. package/dist/plugins/copper/src/index.js +59 -11
  47. package/dist/plugins/cortex/src/index.js +55 -13
  48. package/dist/plugins/currents/src/index.js +310 -71
  49. package/dist/plugins/customerIo/src/index.js +112 -23
  50. package/dist/plugins/databricks/src/index.js +549 -115
  51. package/dist/plugins/deepl/src/index.js +26 -6
  52. package/dist/plugins/demio/src/index.js +56 -11
  53. package/dist/plugins/dhl/src/index.js +16 -3
  54. package/dist/plugins/discord/src/index.js +141 -31
  55. package/dist/plugins/discourse/src/index.js +136 -31
  56. package/dist/plugins/disqus/src/index.js +96 -20
  57. package/dist/plugins/docker/src/index.js +20 -4
  58. package/dist/plugins/drift/src/index.js +19 -5
  59. package/dist/plugins/dropbox/src/index.js +139 -30
  60. package/dist/plugins/dropcontact/src/index.js +21 -4
  61. package/dist/plugins/egoi/src/index.js +61 -15
  62. package/dist/plugins/elasticsearch/src/index.js +59 -13
  63. package/dist/plugins/emelia/src/index.js +95 -19
  64. package/dist/plugins/erpnext/src/index.js +74 -15
  65. package/dist/plugins/facebookGraph/src/index.js +52 -11
  66. package/dist/plugins/freshdesk/src/index.js +220 -48
  67. package/dist/plugins/freshservice/src/index.js +39 -9
  68. package/dist/plugins/freshworksCrm/src/index.js +58 -12
  69. package/dist/plugins/getresponse/src/index.js +87 -18
  70. package/dist/plugins/ghost/src/index.js +114 -26
  71. package/dist/plugins/github/src/index.js +483 -109
  72. package/dist/plugins/gitlab/src/index.js +193 -45
  73. package/dist/plugins/gmail/src/index.js +1075 -0
  74. package/dist/plugins/gong/src/index.js +68 -14
  75. package/dist/plugins/gotify/src/index.js +43 -9
  76. package/dist/plugins/gotowebinar/src/index.js +233 -47
  77. package/dist/plugins/grafana/src/index.js +92 -21
  78. package/dist/plugins/graphql/src/index.js +38 -8
  79. package/dist/plugins/grist/src/index.js +52 -10
  80. package/dist/plugins/hackernews/src/index.js +32 -6
  81. package/dist/plugins/halopsa/src/index.js +131 -26
  82. package/dist/plugins/harvest/src/index.js +182 -42
  83. package/dist/plugins/helpscout/src/index.js +153 -31
  84. package/dist/plugins/highlevel/src/index.js +291 -58
  85. package/dist/plugins/homeAssistant/src/index.js +124 -26
  86. package/dist/plugins/hubspot/src/index.js +163 -29
  87. package/dist/plugins/humanticAi/src/index.js +54 -5
  88. package/dist/plugins/hunter/src/index.js +21 -4
  89. package/dist/plugins/intercom/src/index.js +95 -20
  90. package/dist/plugins/iterable/src/index.js +96 -20
  91. package/dist/plugins/jenkins/src/index.js +75 -17
  92. package/dist/plugins/jira/src/index.js +193 -43
  93. package/dist/plugins/keap/src/index.js +222 -56
  94. package/dist/plugins/kobotoolbox/src/index.js +113 -25
  95. package/dist/plugins/lemlist/src/index.js +79 -18
  96. package/dist/plugins/linear/src/index.js +86 -19
  97. package/dist/plugins/lingvanex/src/index.js +38 -8
  98. package/dist/plugins/linkedin/src/index.js +37 -8
  99. package/dist/plugins/lonescale/src/index.js +41 -9
  100. package/dist/plugins/magento/src/index.js +98 -27
  101. package/dist/plugins/mailcheck/src/index.js +11 -2
  102. package/dist/plugins/mailchimp/src/index.js +193 -42
  103. package/dist/plugins/mailerlite/src/index.js +61 -12
  104. package/dist/plugins/mailgun/src/index.js +39 -7
  105. package/dist/plugins/mailjet/src/index.js +141 -30
  106. package/dist/plugins/mandrill/src/index.js +67 -14
  107. package/dist/plugins/marketstack/src/index.js +56 -10
  108. package/dist/plugins/matrix/src/index.js +97 -20
  109. package/dist/plugins/mattermost/src/index.js +124 -26
  110. package/dist/plugins/mautic/src/index.js +129 -26
  111. package/dist/plugins/medium/src/index.js +64 -13
  112. package/dist/plugins/messagebird/src/index.js +80 -15
  113. package/dist/plugins/metabase/src/index.js +57 -12
  114. package/dist/plugins/misp/src/index.js +135 -33
  115. package/dist/plugins/mocean/src/index.js +33 -7
  116. package/dist/plugins/monday/src/index.js +97 -23
  117. package/dist/plugins/monicaCrm/src/index.js +112 -23
  118. package/dist/plugins/msg91/src/index.js +11 -2
  119. package/dist/plugins/nasa/src/index.js +108 -21
  120. package/dist/plugins/netlify/src/index.js +28 -6
  121. package/dist/plugins/netscalerAdc/src/index.js +144 -29
  122. package/dist/plugins/nextcloud/src/index.js +103 -20
  123. package/dist/plugins/nocodb/src/index.js +57 -11
  124. package/dist/plugins/notion/src/index.js +148 -37
  125. package/dist/plugins/npm/src/index.js +59 -12
  126. package/dist/plugins/odoo/src/index.js +102 -20
  127. package/dist/plugins/okta/src/index.js +50 -10
  128. package/dist/plugins/oneSimpleApi/src/index.js +84 -17
  129. package/dist/plugins/onfleet/src/index.js +139 -32
  130. package/dist/plugins/openThesaurus/src/index.js +46 -9
  131. package/dist/plugins/openweathermap/src/index.js +31 -6
  132. package/dist/plugins/oura/src/index.js +36 -7
  133. package/dist/plugins/paddle/src/index.js +80 -17
  134. package/dist/plugins/pagerduty/src/index.js +53 -12
  135. package/dist/plugins/paypal/src/index.js +51 -11
  136. package/dist/plugins/peekalink/src/index.js +12 -3
  137. package/dist/plugins/phantombuster/src/index.js +39 -8
  138. package/dist/plugins/philipsHue/src/index.js +64 -13
  139. package/dist/plugins/pipedrive/src/index.js +167 -45
  140. package/dist/plugins/plivo/src/index.js +43 -8
  141. package/dist/plugins/postbin/src/index.js +9 -2
  142. package/dist/plugins/posthog/src/index.js +50 -13
  143. package/dist/plugins/profitwell/src/index.js +24 -5
  144. package/dist/plugins/pushbullet/src/index.js +45 -9
  145. package/dist/plugins/pushcut/src/index.js +31 -6
  146. package/dist/plugins/pushover/src/index.js +51 -10
  147. package/dist/plugins/quickbase/src/index.js +66 -13
  148. package/dist/plugins/quickbooks/src/index.js +86 -19
  149. package/dist/plugins/quickchart/src/index.js +35 -7
  150. package/dist/plugins/raindrop/src/index.js +54 -13
  151. package/dist/plugins/reddit/src/index.js +73 -18
  152. package/dist/plugins/rocketchat/src/index.js +47 -9
  153. package/dist/plugins/rundeck/src/index.js +26 -5
  154. package/dist/plugins/salesforce/src/index.js +161 -31
  155. package/dist/plugins/salesmate/src/index.js +75 -16
  156. package/dist/plugins/securityScorecard/src/index.js +73 -15
  157. package/dist/plugins/segment/src/index.js +21 -4
  158. package/dist/plugins/sendgrid/src/index.js +102 -24
  159. package/dist/plugins/sendy/src/index.js +54 -11
  160. package/dist/plugins/sentry/src/index.js +174 -34
  161. package/dist/plugins/servicenow/src/index.js +120 -27
  162. package/dist/plugins/shopify/src/index.js +53 -12
  163. package/dist/plugins/signl4/src/index.js +16 -3
  164. package/dist/plugins/slack/src/index.js +407 -105
  165. package/dist/plugins/sms77/src/index.js +26 -5
  166. package/dist/plugins/splunk/src/index.js +186 -45
  167. package/dist/plugins/spotify/src/index.js +265 -66
  168. package/dist/plugins/stackby/src/index.js +18 -6
  169. package/dist/plugins/storyblok/src/index.js +57 -11
  170. package/dist/plugins/strapi/src/index.js +63 -12
  171. package/dist/plugins/strava/src/index.js +58 -13
  172. package/dist/plugins/stripe/src/index.js +143 -30
  173. package/dist/plugins/supabase/src/index.js +49 -10
  174. package/dist/plugins/syncromsp/src/index.js +245 -67
  175. package/dist/plugins/tapfiliate/src/index.js +57 -14
  176. package/dist/plugins/telegram/src/index.js +202 -39
  177. package/dist/plugins/thehive/src/index.js +271 -66
  178. package/dist/plugins/thehiveProject/src/index.js +457 -89
  179. package/dist/plugins/todoist/src/index.js +326 -77
  180. package/dist/plugins/travisci/src/index.js +35 -8
  181. package/dist/plugins/trello/src/index.js +204 -46
  182. package/dist/plugins/twake/src/index.js +10 -2
  183. package/dist/plugins/twilio/src/index.js +56 -11
  184. package/dist/plugins/twist/src/index.js +241 -48
  185. package/dist/plugins/twitter/src/index.js +128 -30
  186. package/dist/plugins/unleashedSoftware/src/index.js +30 -6
  187. package/dist/plugins/uplead/src/index.js +9 -2
  188. package/dist/plugins/uproc/src/index.js +31 -6
  189. package/dist/plugins/uptimerobot/src/index.js +119 -25
  190. package/dist/plugins/urlscanio/src/index.js +25 -6
  191. package/dist/plugins/vero/src/index.js +68 -13
  192. package/dist/plugins/vonage/src/index.js +32 -6
  193. package/dist/plugins/wekan/src/index.js +297 -52
  194. package/dist/plugins/woocommerce/src/index.js +57 -12
  195. package/dist/plugins/wordpress/src/index.js +94 -18
  196. package/dist/plugins/xero/src/index.js +79 -13
  197. package/dist/plugins/yourls/src/index.js +33 -6
  198. package/dist/plugins/zammad/src/index.js +139 -36
  199. package/dist/plugins/zendesk/src/index.js +201 -48
  200. package/dist/plugins/zoho/src/index.js +88 -21
  201. package/dist/plugins/zoom/src/index.js +41 -7
  202. package/dist/plugins/zulip/src/index.js +101 -20
  203. package/package.json +3 -1
@@ -8,9 +8,15 @@ async function apiRequest(baseUrl, apiKey, method, endpoint, body, qs) {
8
8
  }
9
9
  const opts = {
10
10
  method,
11
- headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
11
+ headers: {
12
+ Authorization: `Bearer ${apiKey}`,
13
+ "Content-Type": "application/json",
14
+ },
12
15
  };
13
- if (body && Object.keys(body).length > 0 && method !== "GET" && method !== "DELETE") {
16
+ if (body &&
17
+ Object.keys(body).length > 0 &&
18
+ method !== "GET" &&
19
+ method !== "DELETE") {
14
20
  opts.body = JSON.stringify(body);
15
21
  }
16
22
  const res = await fetch(url.toString(), opts);
@@ -34,16 +40,34 @@ export default function grafana(rl) {
34
40
  rl.setName("grafana");
35
41
  rl.setVersion("0.1.0");
36
42
  rl.setConnectionSchema({
37
- baseUrl: { type: "string", required: true, description: "Grafana base URL (e.g. https://grafana.example.com)", env: "GRAFANA_URL" },
38
- apiKey: { type: "string", required: true, description: "Grafana API key or service account token", env: "GRAFANA_API_KEY" },
43
+ baseUrl: {
44
+ type: "string",
45
+ required: true,
46
+ description: "Grafana base URL (e.g. https://grafana.example.com)",
47
+ env: "GRAFANA_URL",
48
+ },
49
+ apiKey: {
50
+ type: "string",
51
+ required: true,
52
+ description: "Grafana API key or service account token",
53
+ env: "GRAFANA_API_KEY",
54
+ },
39
55
  });
40
56
  // ── Dashboard ───────────────────────────────────────
41
57
  rl.registerAction("dashboard.create", {
42
58
  description: "Create or save a dashboard",
43
59
  inputSchema: {
44
- dashboard: { type: "object", required: true, description: "Dashboard JSON model" },
60
+ dashboard: {
61
+ type: "object",
62
+ required: true,
63
+ description: "Dashboard JSON model",
64
+ },
45
65
  folderId: { type: "number", required: false, description: "Folder ID" },
46
- overwrite: { type: "boolean", required: false, description: "Overwrite existing" },
66
+ overwrite: {
67
+ type: "boolean",
68
+ required: false,
69
+ description: "Overwrite existing",
70
+ },
47
71
  message: { type: "string", required: false, description: "Save message" },
48
72
  },
49
73
  async execute(input, ctx) {
@@ -60,7 +84,9 @@ export default function grafana(rl) {
60
84
  });
61
85
  rl.registerAction("dashboard.get", {
62
86
  description: "Get a dashboard by UID",
63
- inputSchema: { uid: { type: "string", required: true, description: "Dashboard UID" } },
87
+ inputSchema: {
88
+ uid: { type: "string", required: true, description: "Dashboard UID" },
89
+ },
64
90
  async execute(input, ctx) {
65
91
  return gf(ctx, "GET", `/dashboards/uid/${input.uid}`);
66
92
  },
@@ -70,8 +96,16 @@ export default function grafana(rl) {
70
96
  inputSchema: {
71
97
  query: { type: "string", required: false, description: "Search query" },
72
98
  tag: { type: "string", required: false, description: "Filter by tag" },
73
- type: { type: "string", required: false, description: "dash-db or dash-folder" },
74
- folderId: { type: "number", required: false, description: "Filter by folder ID" },
99
+ type: {
100
+ type: "string",
101
+ required: false,
102
+ description: "dash-db or dash-folder",
103
+ },
104
+ folderId: {
105
+ type: "number",
106
+ required: false,
107
+ description: "Filter by folder ID",
108
+ },
75
109
  limit: { type: "number", required: false, description: "Max results" },
76
110
  },
77
111
  async execute(input, ctx) {
@@ -92,7 +126,9 @@ export default function grafana(rl) {
92
126
  });
93
127
  rl.registerAction("dashboard.delete", {
94
128
  description: "Delete a dashboard by UID",
95
- inputSchema: { uid: { type: "string", required: true, description: "Dashboard UID" } },
129
+ inputSchema: {
130
+ uid: { type: "string", required: true, description: "Dashboard UID" },
131
+ },
96
132
  async execute(input, ctx) {
97
133
  return gf(ctx, "DELETE", `/dashboards/uid/${input.uid}`);
98
134
  },
@@ -100,14 +136,25 @@ export default function grafana(rl) {
100
136
  rl.registerAction("dashboard.update", {
101
137
  description: "Update an existing dashboard",
102
138
  inputSchema: {
103
- uid: { type: "string", required: true, description: "Dashboard UID to update" },
104
- dashboard: { type: "object", required: true, description: "Updated dashboard JSON model" },
139
+ uid: {
140
+ type: "string",
141
+ required: true,
142
+ description: "Dashboard UID to update",
143
+ },
144
+ dashboard: {
145
+ type: "object",
146
+ required: true,
147
+ description: "Updated dashboard JSON model",
148
+ },
105
149
  folderId: { type: "number", required: false, description: "Folder ID" },
106
150
  message: { type: "string", required: false, description: "Save message" },
107
151
  },
108
152
  async execute(input, ctx) {
109
153
  const { uid, dashboard, folderId, message } = input;
110
- const body = { dashboard: { ...dashboard, uid }, overwrite: true };
154
+ const body = {
155
+ dashboard: { ...dashboard, uid },
156
+ overwrite: true,
157
+ };
111
158
  if (folderId !== undefined)
112
159
  body.folderId = folderId;
113
160
  if (message)
@@ -132,7 +179,9 @@ export default function grafana(rl) {
132
179
  });
133
180
  rl.registerAction("team.get", {
134
181
  description: "Get a team by ID",
135
- inputSchema: { teamId: { type: "number", required: true, description: "Team ID" } },
182
+ inputSchema: {
183
+ teamId: { type: "number", required: true, description: "Team ID" },
184
+ },
136
185
  async execute(input, ctx) {
137
186
  return gf(ctx, "GET", `/teams/${input.teamId}`);
138
187
  },
@@ -176,7 +225,9 @@ export default function grafana(rl) {
176
225
  });
177
226
  rl.registerAction("team.delete", {
178
227
  description: "Delete a team",
179
- inputSchema: { teamId: { type: "number", required: true, description: "Team ID" } },
228
+ inputSchema: {
229
+ teamId: { type: "number", required: true, description: "Team ID" },
230
+ },
180
231
  async execute(input, ctx) {
181
232
  return gf(ctx, "DELETE", `/teams/${input.teamId}`);
182
233
  },
@@ -197,7 +248,11 @@ export default function grafana(rl) {
197
248
  description: "Remove a user from a team",
198
249
  inputSchema: {
199
250
  teamId: { type: "number", required: true, description: "Team ID" },
200
- userId: { type: "number", required: true, description: "User ID to remove" },
251
+ userId: {
252
+ type: "number",
253
+ required: true,
254
+ description: "User ID to remove",
255
+ },
201
256
  },
202
257
  async execute(input, ctx) {
203
258
  const { teamId, userId } = input;
@@ -206,7 +261,9 @@ export default function grafana(rl) {
206
261
  });
207
262
  rl.registerAction("teamMember.list", {
208
263
  description: "List members of a team",
209
- inputSchema: { teamId: { type: "number", required: true, description: "Team ID" } },
264
+ inputSchema: {
265
+ teamId: { type: "number", required: true, description: "Team ID" },
266
+ },
210
267
  async execute(input, ctx) {
211
268
  return gf(ctx, "GET", `/teams/${input.teamId}/members`);
212
269
  },
@@ -215,8 +272,16 @@ export default function grafana(rl) {
215
272
  rl.registerAction("user.create", {
216
273
  description: "Add a user to the current organization",
217
274
  inputSchema: {
218
- loginOrEmail: { type: "string", required: true, description: "Login name or email" },
219
- role: { type: "string", required: true, description: "Viewer, Editor, or Admin" },
275
+ loginOrEmail: {
276
+ type: "string",
277
+ required: true,
278
+ description: "Login name or email",
279
+ },
280
+ role: {
281
+ type: "string",
282
+ required: true,
283
+ description: "Viewer, Editor, or Admin",
284
+ },
220
285
  },
221
286
  async execute(input, ctx) {
222
287
  const { loginOrEmail, role } = input;
@@ -233,7 +298,11 @@ export default function grafana(rl) {
233
298
  description: "Update a user's role in the organization",
234
299
  inputSchema: {
235
300
  userId: { type: "number", required: true, description: "User ID" },
236
- role: { type: "string", required: true, description: "Viewer, Editor, or Admin" },
301
+ role: {
302
+ type: "string",
303
+ required: true,
304
+ description: "Viewer, Editor, or Admin",
305
+ },
237
306
  },
238
307
  async execute(input, ctx) {
239
308
  const { userId, role } = input;
@@ -242,7 +311,9 @@ export default function grafana(rl) {
242
311
  });
243
312
  rl.registerAction("user.delete", {
244
313
  description: "Remove a user from the organization",
245
- inputSchema: { userId: { type: "number", required: true, description: "User ID" } },
314
+ inputSchema: {
315
+ userId: { type: "number", required: true, description: "User ID" },
316
+ },
246
317
  async execute(input, ctx) {
247
318
  return gf(ctx, "DELETE", `/org/users/${input.userId}`);
248
319
  },
@@ -2,22 +2,50 @@ export default function graphql(rl) {
2
2
  rl.setName("graphql");
3
3
  rl.setVersion("0.1.0");
4
4
  rl.setConnectionSchema({
5
- endpoint: { type: "string", required: true, description: "GraphQL endpoint URL", env: "GRAPHQL_ENDPOINT" },
6
- headerAuth: { type: "string", required: false, description: "Authorization header value (e.g. 'Bearer xxx')", env: "GRAPHQL_AUTH_HEADER" },
7
- headers: { type: "object", required: false, description: "Additional headers as key-value pairs" },
5
+ endpoint: {
6
+ type: "string",
7
+ required: true,
8
+ description: "GraphQL endpoint URL",
9
+ env: "GRAPHQL_ENDPOINT",
10
+ },
11
+ headerAuth: {
12
+ type: "string",
13
+ required: false,
14
+ description: "Authorization header value (e.g. 'Bearer xxx')",
15
+ env: "GRAPHQL_AUTH_HEADER",
16
+ },
17
+ headers: {
18
+ type: "object",
19
+ required: false,
20
+ description: "Additional headers as key-value pairs",
21
+ },
8
22
  });
9
23
  rl.registerAction("query", {
10
24
  description: "Execute a GraphQL query",
11
25
  inputSchema: {
12
- query: { type: "string", required: true, description: "GraphQL query or mutation string" },
13
- variables: { type: "object", required: false, description: "Query variables" },
14
- operationName: { type: "string", required: false, description: "Operation name (if query contains multiple)" },
26
+ query: {
27
+ type: "string",
28
+ required: true,
29
+ description: "GraphQL query or mutation string",
30
+ },
31
+ variables: {
32
+ type: "object",
33
+ required: false,
34
+ description: "Query variables",
35
+ },
36
+ operationName: {
37
+ type: "string",
38
+ required: false,
39
+ description: "Operation name (if query contains multiple)",
40
+ },
15
41
  },
16
42
  async execute(input, ctx) {
17
43
  const { query, variables, operationName } = input;
18
44
  const cfg = ctx.connection.config;
19
45
  const endpoint = cfg.endpoint;
20
- const hdrs = { "Content-Type": "application/json" };
46
+ const hdrs = {
47
+ "Content-Type": "application/json",
48
+ };
21
49
  if (cfg.headerAuth)
22
50
  hdrs.Authorization = cfg.headerAuth;
23
51
  if (cfg.headers) {
@@ -48,7 +76,9 @@ export default function graphql(rl) {
48
76
  async execute(_input, ctx) {
49
77
  const cfg = ctx.connection.config;
50
78
  const endpoint = cfg.endpoint;
51
- const hdrs = { "Content-Type": "application/json" };
79
+ const hdrs = {
80
+ "Content-Type": "application/json",
81
+ };
52
82
  if (cfg.headerAuth)
53
83
  hdrs.Authorization = cfg.headerAuth;
54
84
  if (cfg.headers) {
@@ -8,7 +8,10 @@ async function apiRequest(baseUrl, apiKey, method, endpoint, body, qs) {
8
8
  }
9
9
  const opts = {
10
10
  method,
11
- headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
11
+ headers: {
12
+ Authorization: `Bearer ${apiKey}`,
13
+ "Content-Type": "application/json",
14
+ },
12
15
  };
13
16
  if (body !== undefined && method !== "GET" && method !== "DELETE") {
14
17
  opts.body = JSON.stringify(body);
@@ -36,17 +39,40 @@ export default function grist(rl) {
36
39
  rl.setName("grist");
37
40
  rl.setVersion("0.1.0");
38
41
  rl.setConnectionSchema({
39
- apiKey: { type: "string", required: true, description: "Grist API key", env: "GRIST_API_KEY" },
40
- planType: { type: "string", required: false, description: "free (default), paid, or selfHosted", default: "free" },
41
- subdomain: { type: "string", required: false, description: "Subdomain for paid plan" },
42
- selfHostedUrl: { type: "string", required: false, description: "Full URL for self-hosted", env: "GRIST_URL" },
42
+ apiKey: {
43
+ type: "string",
44
+ required: true,
45
+ description: "Grist API key",
46
+ env: "GRIST_API_KEY",
47
+ },
48
+ planType: {
49
+ type: "string",
50
+ required: false,
51
+ description: "free (default), paid, or selfHosted",
52
+ default: "free",
53
+ },
54
+ subdomain: {
55
+ type: "string",
56
+ required: false,
57
+ description: "Subdomain for paid plan",
58
+ },
59
+ selfHostedUrl: {
60
+ type: "string",
61
+ required: false,
62
+ description: "Full URL for self-hosted",
63
+ env: "GRIST_URL",
64
+ },
43
65
  });
44
66
  rl.registerAction("record.create", {
45
67
  description: "Create records in a table",
46
68
  inputSchema: {
47
69
  docId: { type: "string", required: true, description: "Document ID" },
48
70
  tableId: { type: "string", required: true, description: "Table ID" },
49
- records: { type: "array", required: true, description: "Array of {fields: {col: value}} objects" },
71
+ records: {
72
+ type: "array",
73
+ required: true,
74
+ description: "Array of {fields: {col: value}} objects",
75
+ },
50
76
  },
51
77
  async execute(input, ctx) {
52
78
  const { docId, tableId, records } = input;
@@ -60,8 +86,16 @@ export default function grist(rl) {
60
86
  docId: { type: "string", required: true, description: "Document ID" },
61
87
  tableId: { type: "string", required: true, description: "Table ID" },
62
88
  limit: { type: "number", required: false, description: "Max results" },
63
- sort: { type: "string", required: false, description: "Sort columns (e.g. 'Name,-Age')" },
64
- filter: { type: "object", required: false, description: "Filter as {column: [values]}" },
89
+ sort: {
90
+ type: "string",
91
+ required: false,
92
+ description: "Sort columns (e.g. 'Name,-Age')",
93
+ },
94
+ filter: {
95
+ type: "object",
96
+ required: false,
97
+ description: "Filter as {column: [values]}",
98
+ },
65
99
  },
66
100
  async execute(input, ctx) {
67
101
  const { docId, tableId, limit, sort, filter } = (input ?? {});
@@ -82,7 +116,11 @@ export default function grist(rl) {
82
116
  inputSchema: {
83
117
  docId: { type: "string", required: true, description: "Document ID" },
84
118
  tableId: { type: "string", required: true, description: "Table ID" },
85
- records: { type: "array", required: true, description: "Array of {id, fields: {col: value}} objects" },
119
+ records: {
120
+ type: "array",
121
+ required: true,
122
+ description: "Array of {id, fields: {col: value}} objects",
123
+ },
86
124
  },
87
125
  async execute(input, ctx) {
88
126
  const { docId, tableId, records } = input;
@@ -95,7 +133,11 @@ export default function grist(rl) {
95
133
  inputSchema: {
96
134
  docId: { type: "string", required: true, description: "Document ID" },
97
135
  tableId: { type: "string", required: true, description: "Table ID" },
98
- rowIds: { type: "array", required: true, description: "Array of row IDs to delete" },
136
+ rowIds: {
137
+ type: "array",
138
+ required: true,
139
+ description: "Array of row IDs to delete",
140
+ },
99
141
  },
100
142
  async execute(input, ctx) {
101
143
  const { docId, tableId, rowIds } = input;
@@ -26,7 +26,9 @@ export default function hackernews(rl) {
26
26
  rl.setConnectionSchema({});
27
27
  rl.registerAction("article.get", {
28
28
  description: "Get a Hacker News article/item by ID",
29
- inputSchema: { articleId: { type: "string", required: true, description: "Item ID" } },
29
+ inputSchema: {
30
+ articleId: { type: "string", required: true, description: "Item ID" },
31
+ },
30
32
  async execute(input) {
31
33
  return firebaseRequest(`item/${input.articleId}`);
32
34
  },
@@ -35,7 +37,11 @@ export default function hackernews(rl) {
35
37
  description: "Search Hacker News articles",
36
38
  inputSchema: {
37
39
  query: { type: "string", required: true, description: "Search query" },
38
- tags: { type: "string", required: false, description: "Filter tags: story, comment, ask_hn, show_hn, poll, front_page" },
40
+ tags: {
41
+ type: "string",
42
+ required: false,
43
+ description: "Filter tags: story, comment, ask_hn, show_hn, poll, front_page",
44
+ },
39
45
  limit: { type: "number", required: false, description: "Max results" },
40
46
  },
41
47
  async execute(input) {
@@ -51,14 +57,22 @@ export default function hackernews(rl) {
51
57
  });
52
58
  rl.registerAction("user.get", {
53
59
  description: "Get a Hacker News user by username",
54
- inputSchema: { username: { type: "string", required: true, description: "Username" } },
60
+ inputSchema: {
61
+ username: { type: "string", required: true, description: "Username" },
62
+ },
55
63
  async execute(input) {
56
64
  return firebaseRequest(`user/${input.username}`);
57
65
  },
58
66
  });
59
67
  rl.registerAction("all.top", {
60
68
  description: "Get top stories",
61
- inputSchema: { limit: { type: "number", required: false, description: "Max results (default: 30)" } },
69
+ inputSchema: {
70
+ limit: {
71
+ type: "number",
72
+ required: false,
73
+ description: "Max results (default: 30)",
74
+ },
75
+ },
62
76
  async execute(input) {
63
77
  const { limit = 30 } = (input ?? {});
64
78
  const ids = (await firebaseRequest("topstories"));
@@ -68,7 +82,13 @@ export default function hackernews(rl) {
68
82
  });
69
83
  rl.registerAction("all.new", {
70
84
  description: "Get newest stories",
71
- inputSchema: { limit: { type: "number", required: false, description: "Max results (default: 30)" } },
85
+ inputSchema: {
86
+ limit: {
87
+ type: "number",
88
+ required: false,
89
+ description: "Max results (default: 30)",
90
+ },
91
+ },
72
92
  async execute(input) {
73
93
  const { limit = 30 } = (input ?? {});
74
94
  const ids = (await firebaseRequest("newstories"));
@@ -78,7 +98,13 @@ export default function hackernews(rl) {
78
98
  });
79
99
  rl.registerAction("all.best", {
80
100
  description: "Get best stories",
81
- inputSchema: { limit: { type: "number", required: false, description: "Max results (default: 30)" } },
101
+ inputSchema: {
102
+ limit: {
103
+ type: "number",
104
+ required: false,
105
+ description: "Max results (default: 30)",
106
+ },
107
+ },
82
108
  async execute(input) {
83
109
  const { limit = 30 } = (input ?? {});
84
110
  const ids = (await firebaseRequest("beststories"));
@@ -3,12 +3,24 @@ async function getToken(authUrl, clientId, clientSecret, scope, tenant) {
3
3
  if (cachedToken && Date.now() < cachedToken.expiresAt)
4
4
  return cachedToken.token;
5
5
  const url = tenant ? `${authUrl}?tenant=${tenant}` : authUrl;
6
- const body = new URLSearchParams({ grant_type: "client_credentials", client_id: clientId, client_secret: clientSecret, scope });
7
- const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: body.toString() });
6
+ const body = new URLSearchParams({
7
+ grant_type: "client_credentials",
8
+ client_id: clientId,
9
+ client_secret: clientSecret,
10
+ scope,
11
+ });
12
+ const res = await fetch(url, {
13
+ method: "POST",
14
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
15
+ body: body.toString(),
16
+ });
8
17
  if (!res.ok)
9
18
  throw new Error(`HaloPSA auth error ${res.status}: ${await res.text()}`);
10
19
  const data = (await res.json());
11
- cachedToken = { token: data.access_token, expiresAt: Date.now() + (data.expires_in - 60) * 1000 };
20
+ cachedToken = {
21
+ token: data.access_token,
22
+ expiresAt: Date.now() + (data.expires_in - 60) * 1000,
23
+ };
12
24
  return cachedToken.token;
13
25
  }
14
26
  async function apiRequest(apiUrl, token, method, endpoint, body, qs) {
@@ -19,8 +31,17 @@ async function apiRequest(apiUrl, token, method, endpoint, body, qs) {
19
31
  url.searchParams.set(k, String(v));
20
32
  }
21
33
  }
22
- const opts = { method, headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" } };
23
- if (body && Object.keys(body).length > 0 && method !== "GET" && method !== "DELETE")
34
+ const opts = {
35
+ method,
36
+ headers: {
37
+ Authorization: `Bearer ${token}`,
38
+ "Content-Type": "application/json",
39
+ },
40
+ };
41
+ if (body &&
42
+ Object.keys(body).length > 0 &&
43
+ method !== "GET" &&
44
+ method !== "DELETE")
24
45
  opts.body = JSON.stringify(body);
25
46
  const res = await fetch(url.toString(), opts);
26
47
  if (!res.ok)
@@ -31,46 +52,130 @@ async function apiRequest(apiUrl, token, method, endpoint, body, qs) {
31
52
  }
32
53
  async function req(ctx, method, endpoint, body, qs) {
33
54
  const cfg = ctx.connection.config;
34
- const authUrl = cfg.hostingType === "on-premise" ? `${cfg.appUrl}/auth/token` : `${cfg.authUrl}/token`;
55
+ const authUrl = cfg.hostingType === "on-premise"
56
+ ? `${cfg.appUrl}/auth/token`
57
+ : `${cfg.authUrl}/token`;
35
58
  const token = await getToken(authUrl, cfg.clientId, cfg.clientSecret, cfg.scope ?? "all", cfg.tenant);
36
59
  return apiRequest(cfg.resourceApiUrl.replace(/\/$/, ""), token, method, endpoint, body, qs);
37
60
  }
38
61
  function registerCrud(rl, resource, apiPath) {
39
62
  rl.registerAction(`${resource}.create`, {
40
- description: `Create a ${resource}`, inputSchema: { properties: { type: "object", required: true, description: `${resource} data` } },
41
- async execute(input, ctx) { return req(ctx, "POST", apiPath, { ...input.properties }); },
63
+ description: `Create a ${resource}`,
64
+ inputSchema: {
65
+ properties: {
66
+ type: "object",
67
+ required: true,
68
+ description: `${resource} data`,
69
+ },
70
+ },
71
+ async execute(input, ctx) {
72
+ return req(ctx, "POST", apiPath, {
73
+ ...input.properties,
74
+ });
75
+ },
42
76
  });
43
77
  rl.registerAction(`${resource}.get`, {
44
- description: `Get a ${resource}`, inputSchema: { id: { type: "number", required: true, description: `${resource} ID` } },
45
- async execute(input, ctx) { return req(ctx, "GET", `${apiPath}/${input.id}`); },
78
+ description: `Get a ${resource}`,
79
+ inputSchema: {
80
+ id: { type: "number", required: true, description: `${resource} ID` },
81
+ },
82
+ async execute(input, ctx) {
83
+ return req(ctx, "GET", `${apiPath}/${input.id}`);
84
+ },
46
85
  });
47
86
  rl.registerAction(`${resource}.list`, {
48
- description: `List ${resource}s`, inputSchema: { limit: { type: "number", required: false, description: "Max results" }, page: { type: "number", required: false, description: "Page" } },
49
- async execute(input, ctx) { const { limit, page } = (input ?? {}); const qs = {}; if (limit)
50
- qs.count = limit; if (page)
51
- qs.page_no = page; return req(ctx, "GET", apiPath, undefined, qs); },
87
+ description: `List ${resource}s`,
88
+ inputSchema: {
89
+ limit: { type: "number", required: false, description: "Max results" },
90
+ page: { type: "number", required: false, description: "Page" },
91
+ },
92
+ async execute(input, ctx) {
93
+ const { limit, page } = (input ?? {});
94
+ const qs = {};
95
+ if (limit)
96
+ qs.count = limit;
97
+ if (page)
98
+ qs.page_no = page;
99
+ return req(ctx, "GET", apiPath, undefined, qs);
100
+ },
52
101
  });
53
102
  rl.registerAction(`${resource}.update`, {
54
- description: `Update a ${resource}`, inputSchema: { id: { type: "number", required: true, description: `${resource} ID` }, properties: { type: "object", required: true, description: "Fields to update" } },
55
- async execute(input, ctx) { const { id, properties } = input; return req(ctx, "PUT", apiPath, { id, ...properties }); },
103
+ description: `Update a ${resource}`,
104
+ inputSchema: {
105
+ id: { type: "number", required: true, description: `${resource} ID` },
106
+ properties: {
107
+ type: "object",
108
+ required: true,
109
+ description: "Fields to update",
110
+ },
111
+ },
112
+ async execute(input, ctx) {
113
+ const { id, properties } = input;
114
+ return req(ctx, "PUT", apiPath, { id, ...properties });
115
+ },
56
116
  });
57
117
  rl.registerAction(`${resource}.delete`, {
58
- description: `Delete a ${resource}`, inputSchema: { id: { type: "number", required: true, description: `${resource} ID` } },
59
- async execute(input, ctx) { await req(ctx, "DELETE", `${apiPath}/${input.id}`); return { success: true }; },
118
+ description: `Delete a ${resource}`,
119
+ inputSchema: {
120
+ id: { type: "number", required: true, description: `${resource} ID` },
121
+ },
122
+ async execute(input, ctx) {
123
+ await req(ctx, "DELETE", `${apiPath}/${input.id}`);
124
+ return { success: true };
125
+ },
60
126
  });
61
127
  }
62
128
  export default function halopsa(rl) {
63
129
  rl.setName("halopsa");
64
130
  rl.setVersion("0.1.0");
65
131
  rl.setConnectionSchema({
66
- hostingType: { type: "string", required: false, description: "cloud (default) or on-premise", default: "cloud" },
67
- authUrl: { type: "string", required: false, description: "Auth server URL (cloud)", env: "HALOPSA_AUTH_URL" },
68
- appUrl: { type: "string", required: false, description: "App URL (on-premise)", env: "HALOPSA_APP_URL" },
69
- resourceApiUrl: { type: "string", required: true, description: "Resource API URL", env: "HALOPSA_API_URL" },
70
- clientId: { type: "string", required: true, description: "OAuth2 client ID", env: "HALOPSA_CLIENT_ID" },
71
- clientSecret: { type: "string", required: true, description: "OAuth2 client secret", env: "HALOPSA_CLIENT_SECRET" },
72
- scope: { type: "string", required: false, description: "OAuth2 scope (default: all)", default: "all" },
73
- tenant: { type: "string", required: false, description: "Tenant (cloud only)" },
132
+ hostingType: {
133
+ type: "string",
134
+ required: false,
135
+ description: "cloud (default) or on-premise",
136
+ default: "cloud",
137
+ },
138
+ authUrl: {
139
+ type: "string",
140
+ required: false,
141
+ description: "Auth server URL (cloud)",
142
+ env: "HALOPSA_AUTH_URL",
143
+ },
144
+ appUrl: {
145
+ type: "string",
146
+ required: false,
147
+ description: "App URL (on-premise)",
148
+ env: "HALOPSA_APP_URL",
149
+ },
150
+ resourceApiUrl: {
151
+ type: "string",
152
+ required: true,
153
+ description: "Resource API URL",
154
+ env: "HALOPSA_API_URL",
155
+ },
156
+ clientId: {
157
+ type: "string",
158
+ required: true,
159
+ description: "OAuth2 client ID",
160
+ env: "HALOPSA_CLIENT_ID",
161
+ },
162
+ clientSecret: {
163
+ type: "string",
164
+ required: true,
165
+ description: "OAuth2 client secret",
166
+ env: "HALOPSA_CLIENT_SECRET",
167
+ },
168
+ scope: {
169
+ type: "string",
170
+ required: false,
171
+ description: "OAuth2 scope (default: all)",
172
+ default: "all",
173
+ },
174
+ tenant: {
175
+ type: "string",
176
+ required: false,
177
+ description: "Tenant (cloud only)",
178
+ },
74
179
  });
75
180
  registerCrud(rl, "client", "/client");
76
181
  registerCrud(rl, "site", "/site");