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,316 @@
1
+ const BASE_URL = "https://api.getgo.com/G2W/rest/v2";
2
+ async function apiRequest(accessToken, method, endpoint, body, qs) {
3
+ const url = new URL(`${BASE_URL}/${endpoint}`);
4
+ if (qs) {
5
+ for (const [k, v] of Object.entries(qs)) {
6
+ if (v !== undefined && v !== null)
7
+ url.searchParams.set(k, String(v));
8
+ }
9
+ }
10
+ const opts = {
11
+ method,
12
+ headers: { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json", Accept: "application/json" },
13
+ };
14
+ if (body !== undefined && method !== "GET" && method !== "DELETE") {
15
+ opts.body = JSON.stringify(body);
16
+ }
17
+ const res = await fetch(url.toString(), opts);
18
+ if (!res.ok)
19
+ throw new Error(`GoToWebinar API error ${res.status}: ${await res.text()}`);
20
+ if (res.status === 204)
21
+ return { success: true };
22
+ const ct = res.headers.get("content-type") ?? "";
23
+ if (ct.includes("json"))
24
+ return res.json();
25
+ return { success: true };
26
+ }
27
+ function getConn(ctx) {
28
+ return {
29
+ accessToken: ctx.connection.config.accessToken,
30
+ organizerKey: ctx.connection.config.organizerKey,
31
+ };
32
+ }
33
+ export default function gotowebinar(rl) {
34
+ rl.setName("gotowebinar");
35
+ rl.setVersion("0.1.0");
36
+ rl.setConnectionSchema({
37
+ accessToken: { type: "string", required: true, description: "GoTo OAuth2 access token", env: "GOTO_ACCESS_TOKEN" },
38
+ organizerKey: { type: "string", required: true, description: "Organizer key", env: "GOTO_ORGANIZER_KEY" },
39
+ });
40
+ // ── Webinar ─────────────────────────────────────────
41
+ rl.registerAction("webinar.create", {
42
+ description: "Create a webinar",
43
+ inputSchema: {
44
+ subject: { type: "string", required: true, description: "Webinar subject" },
45
+ times: { type: "array", required: true, description: "Array of {startTime, endTime} (ISO 8601)" },
46
+ description: { type: "string", required: false, description: "Description" },
47
+ timeZone: { type: "string", required: false, description: "Time zone" },
48
+ type: { type: "string", required: false, description: "single_session, series, sequence" },
49
+ isPasswordProtected: { type: "boolean", required: false, description: "Require password" },
50
+ },
51
+ async execute(input, ctx) {
52
+ const { subject, times, description: desc, timeZone, type, isPasswordProtected } = input;
53
+ const { accessToken, organizerKey } = getConn(ctx);
54
+ const body = { subject, times };
55
+ if (desc)
56
+ body.description = desc;
57
+ if (timeZone)
58
+ body.timeZone = timeZone;
59
+ if (type)
60
+ body.type = type;
61
+ if (isPasswordProtected !== undefined)
62
+ body.isPasswordProtected = isPasswordProtected;
63
+ return apiRequest(accessToken, "POST", `organizers/${organizerKey}/webinars`, body);
64
+ },
65
+ });
66
+ rl.registerAction("webinar.get", {
67
+ description: "Get a webinar",
68
+ inputSchema: { webinarKey: { type: "string", required: true, description: "Webinar key" } },
69
+ async execute(input, ctx) {
70
+ const { accessToken, organizerKey } = getConn(ctx);
71
+ return apiRequest(accessToken, "GET", `organizers/${organizerKey}/webinars/${input.webinarKey}`);
72
+ },
73
+ });
74
+ rl.registerAction("webinar.list", {
75
+ description: "List webinars",
76
+ inputSchema: { limit: { type: "number", required: false, description: "Max results" } },
77
+ async execute(input, ctx) {
78
+ const { accessToken, organizerKey } = getConn(ctx);
79
+ const data = (await apiRequest(accessToken, "GET", `organizers/${organizerKey}/webinars`));
80
+ const list = data._embedded?.webinars ?? data;
81
+ if (input?.limit && Array.isArray(list))
82
+ return list.slice(0, input.limit);
83
+ return list;
84
+ },
85
+ });
86
+ rl.registerAction("webinar.update", {
87
+ description: "Update a webinar",
88
+ inputSchema: {
89
+ webinarKey: { type: "string", required: true, description: "Webinar key" },
90
+ subject: { type: "string", required: false, description: "New subject" },
91
+ description: { type: "string", required: false, description: "New description" },
92
+ times: { type: "array", required: false, description: "New times" },
93
+ timeZone: { type: "string", required: false, description: "New time zone" },
94
+ },
95
+ async execute(input, ctx) {
96
+ const { webinarKey, subject, description: desc, times, timeZone } = input;
97
+ const { accessToken, organizerKey } = getConn(ctx);
98
+ const body = {};
99
+ if (subject)
100
+ body.subject = subject;
101
+ if (desc)
102
+ body.description = desc;
103
+ if (times)
104
+ body.times = times;
105
+ if (timeZone)
106
+ body.timeZone = timeZone;
107
+ return apiRequest(accessToken, "PUT", `organizers/${organizerKey}/webinars/${webinarKey}`, body);
108
+ },
109
+ });
110
+ rl.registerAction("webinar.delete", {
111
+ description: "Delete a webinar",
112
+ inputSchema: {
113
+ webinarKey: { type: "string", required: true, description: "Webinar key" },
114
+ sendCancellationEmails: { type: "boolean", required: false, description: "Send cancellation emails" },
115
+ },
116
+ async execute(input, ctx) {
117
+ const { webinarKey, sendCancellationEmails } = input;
118
+ const { accessToken, organizerKey } = getConn(ctx);
119
+ const qs = {};
120
+ if (sendCancellationEmails !== undefined)
121
+ qs.sendCancellationEmails = sendCancellationEmails;
122
+ await apiRequest(accessToken, "DELETE", `organizers/${organizerKey}/webinars/${webinarKey}`, undefined, qs);
123
+ return { success: true };
124
+ },
125
+ });
126
+ // ── Registrant ──────────────────────────────────────
127
+ rl.registerAction("registrant.create", {
128
+ description: "Register a person for a webinar",
129
+ inputSchema: {
130
+ webinarKey: { type: "string", required: true, description: "Webinar key" },
131
+ firstName: { type: "string", required: true, description: "First name" },
132
+ lastName: { type: "string", required: true, description: "Last name" },
133
+ email: { type: "string", required: true, description: "Email" },
134
+ },
135
+ async execute(input, ctx) {
136
+ const { webinarKey, firstName, lastName, email } = input;
137
+ const { accessToken, organizerKey } = getConn(ctx);
138
+ return apiRequest(accessToken, "POST", `organizers/${organizerKey}/webinars/${webinarKey}/registrants`, { firstName, lastName, email });
139
+ },
140
+ });
141
+ rl.registerAction("registrant.get", {
142
+ description: "Get a registrant",
143
+ inputSchema: {
144
+ webinarKey: { type: "string", required: true, description: "Webinar key" },
145
+ registrantKey: { type: "string", required: true, description: "Registrant key" },
146
+ },
147
+ async execute(input, ctx) {
148
+ const { webinarKey, registrantKey } = input;
149
+ const { accessToken, organizerKey } = getConn(ctx);
150
+ return apiRequest(accessToken, "GET", `organizers/${organizerKey}/webinars/${webinarKey}/registrants/${registrantKey}`);
151
+ },
152
+ });
153
+ rl.registerAction("registrant.list", {
154
+ description: "List registrants for a webinar",
155
+ inputSchema: { webinarKey: { type: "string", required: true, description: "Webinar key" } },
156
+ async execute(input, ctx) {
157
+ const { accessToken, organizerKey } = getConn(ctx);
158
+ return apiRequest(accessToken, "GET", `organizers/${organizerKey}/webinars/${input.webinarKey}/registrants`);
159
+ },
160
+ });
161
+ rl.registerAction("registrant.delete", {
162
+ description: "Delete a registrant",
163
+ inputSchema: {
164
+ webinarKey: { type: "string", required: true, description: "Webinar key" },
165
+ registrantKey: { type: "string", required: true, description: "Registrant key" },
166
+ },
167
+ async execute(input, ctx) {
168
+ const { webinarKey, registrantKey } = input;
169
+ const { accessToken, organizerKey } = getConn(ctx);
170
+ await apiRequest(accessToken, "DELETE", `organizers/${organizerKey}/webinars/${webinarKey}/registrants/${registrantKey}`);
171
+ return { success: true };
172
+ },
173
+ });
174
+ // ── Session ─────────────────────────────────────────
175
+ rl.registerAction("session.get", {
176
+ description: "Get a session",
177
+ inputSchema: {
178
+ webinarKey: { type: "string", required: true, description: "Webinar key" },
179
+ sessionKey: { type: "string", required: true, description: "Session key" },
180
+ },
181
+ async execute(input, ctx) {
182
+ const { webinarKey, sessionKey } = input;
183
+ const { accessToken, organizerKey } = getConn(ctx);
184
+ return apiRequest(accessToken, "GET", `organizers/${organizerKey}/webinars/${webinarKey}/sessions/${sessionKey}`);
185
+ },
186
+ });
187
+ rl.registerAction("session.list", {
188
+ description: "List sessions for a webinar",
189
+ inputSchema: { webinarKey: { type: "string", required: true, description: "Webinar key" } },
190
+ async execute(input, ctx) {
191
+ const { accessToken, organizerKey } = getConn(ctx);
192
+ return apiRequest(accessToken, "GET", `organizers/${organizerKey}/webinars/${input.webinarKey}/sessions`);
193
+ },
194
+ });
195
+ rl.registerAction("session.getPerformance", {
196
+ description: "Get session performance details",
197
+ inputSchema: {
198
+ webinarKey: { type: "string", required: true, description: "Webinar key" },
199
+ sessionKey: { type: "string", required: true, description: "Session key" },
200
+ },
201
+ async execute(input, ctx) {
202
+ const { webinarKey, sessionKey } = input;
203
+ const { accessToken, organizerKey } = getConn(ctx);
204
+ return apiRequest(accessToken, "GET", `organizers/${organizerKey}/webinars/${webinarKey}/sessions/${sessionKey}/performance`);
205
+ },
206
+ });
207
+ // ── Attendee ────────────────────────────────────────
208
+ rl.registerAction("attendee.get", {
209
+ description: "Get an attendee",
210
+ inputSchema: {
211
+ webinarKey: { type: "string", required: true, description: "Webinar key" },
212
+ sessionKey: { type: "string", required: true, description: "Session key" },
213
+ registrantKey: { type: "string", required: true, description: "Registrant key" },
214
+ },
215
+ async execute(input, ctx) {
216
+ const { webinarKey, sessionKey, registrantKey } = input;
217
+ const { accessToken, organizerKey } = getConn(ctx);
218
+ return apiRequest(accessToken, "GET", `organizers/${organizerKey}/webinars/${webinarKey}/sessions/${sessionKey}/attendees/${registrantKey}`);
219
+ },
220
+ });
221
+ rl.registerAction("attendee.list", {
222
+ description: "List attendees for a session",
223
+ inputSchema: {
224
+ webinarKey: { type: "string", required: true, description: "Webinar key" },
225
+ sessionKey: { type: "string", required: true, description: "Session key" },
226
+ },
227
+ async execute(input, ctx) {
228
+ const { webinarKey, sessionKey } = input;
229
+ const { accessToken, organizerKey } = getConn(ctx);
230
+ return apiRequest(accessToken, "GET", `organizers/${organizerKey}/webinars/${webinarKey}/sessions/${sessionKey}/attendees`);
231
+ },
232
+ });
233
+ // ── Coorganizer ─────────────────────────────────────
234
+ rl.registerAction("coorganizer.create", {
235
+ description: "Add a co-organizer to a webinar",
236
+ inputSchema: {
237
+ webinarKey: { type: "string", required: true, description: "Webinar key" },
238
+ external: { type: "boolean", required: true, description: "true for external, false for internal" },
239
+ organizerKey: { type: "string", required: false, description: "Organizer key (internal)" },
240
+ givenName: { type: "string", required: false, description: "First name (external)" },
241
+ email: { type: "string", required: false, description: "Email (external)" },
242
+ },
243
+ async execute(input, ctx) {
244
+ const { webinarKey, external, organizerKey: coorgKey, givenName, email } = input;
245
+ const { accessToken, organizerKey } = getConn(ctx);
246
+ const body = { external };
247
+ if (coorgKey)
248
+ body.organizerKey = coorgKey;
249
+ if (givenName)
250
+ body.givenName = givenName;
251
+ if (email)
252
+ body.email = email;
253
+ return apiRequest(accessToken, "POST", `organizers/${organizerKey}/webinars/${webinarKey}/coorganizers`, [body]);
254
+ },
255
+ });
256
+ rl.registerAction("coorganizer.list", {
257
+ description: "List co-organizers",
258
+ inputSchema: { webinarKey: { type: "string", required: true, description: "Webinar key" } },
259
+ async execute(input, ctx) {
260
+ const { accessToken, organizerKey } = getConn(ctx);
261
+ return apiRequest(accessToken, "GET", `organizers/${organizerKey}/webinars/${input.webinarKey}/coorganizers`);
262
+ },
263
+ });
264
+ rl.registerAction("coorganizer.delete", {
265
+ description: "Remove a co-organizer",
266
+ inputSchema: {
267
+ webinarKey: { type: "string", required: true, description: "Webinar key" },
268
+ coorganizerKey: { type: "string", required: true, description: "Co-organizer key" },
269
+ external: { type: "boolean", required: false, description: "Whether external" },
270
+ },
271
+ async execute(input, ctx) {
272
+ const { webinarKey, coorganizerKey, external } = input;
273
+ const { accessToken, organizerKey } = getConn(ctx);
274
+ const qs = {};
275
+ if (external !== undefined)
276
+ qs.external = external;
277
+ await apiRequest(accessToken, "DELETE", `organizers/${organizerKey}/webinars/${webinarKey}/coorganizers/${coorganizerKey}`, undefined, qs);
278
+ return { success: true };
279
+ },
280
+ });
281
+ // ── Panelist ────────────────────────────────────────
282
+ rl.registerAction("panelist.create", {
283
+ description: "Add a panelist to a webinar",
284
+ inputSchema: {
285
+ webinarKey: { type: "string", required: true, description: "Webinar key" },
286
+ name: { type: "string", required: true, description: "Panelist name" },
287
+ email: { type: "string", required: true, description: "Panelist email" },
288
+ },
289
+ async execute(input, ctx) {
290
+ const { webinarKey, name, email } = input;
291
+ const { accessToken, organizerKey } = getConn(ctx);
292
+ return apiRequest(accessToken, "POST", `organizers/${organizerKey}/webinars/${webinarKey}/panelists`, [{ name, email }]);
293
+ },
294
+ });
295
+ rl.registerAction("panelist.list", {
296
+ description: "List panelists",
297
+ inputSchema: { webinarKey: { type: "string", required: true, description: "Webinar key" } },
298
+ async execute(input, ctx) {
299
+ const { accessToken, organizerKey } = getConn(ctx);
300
+ return apiRequest(accessToken, "GET", `organizers/${organizerKey}/webinars/${input.webinarKey}/panelists`);
301
+ },
302
+ });
303
+ rl.registerAction("panelist.delete", {
304
+ description: "Remove a panelist",
305
+ inputSchema: {
306
+ webinarKey: { type: "string", required: true, description: "Webinar key" },
307
+ panelistKey: { type: "string", required: true, description: "Panelist key" },
308
+ },
309
+ async execute(input, ctx) {
310
+ const { webinarKey, panelistKey } = input;
311
+ const { accessToken, organizerKey } = getConn(ctx);
312
+ await apiRequest(accessToken, "DELETE", `organizers/${organizerKey}/webinars/${webinarKey}/panelists/${panelistKey}`);
313
+ return { success: true };
314
+ },
315
+ });
316
+ }
@@ -0,0 +1,250 @@
1
+ async function apiRequest(baseUrl, apiKey, method, endpoint, body, qs) {
2
+ const url = new URL(`${baseUrl}/api${endpoint}`);
3
+ if (qs) {
4
+ for (const [k, v] of Object.entries(qs)) {
5
+ if (v !== undefined && v !== null)
6
+ url.searchParams.set(k, String(v));
7
+ }
8
+ }
9
+ const opts = {
10
+ method,
11
+ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
12
+ };
13
+ if (body && Object.keys(body).length > 0 && method !== "GET" && method !== "DELETE") {
14
+ opts.body = JSON.stringify(body);
15
+ }
16
+ const res = await fetch(url.toString(), opts);
17
+ if (!res.ok)
18
+ throw new Error(`Grafana API error ${res.status}: ${await res.text()}`);
19
+ if (res.status === 204)
20
+ return { success: true };
21
+ return res.json();
22
+ }
23
+ function getConn(ctx) {
24
+ return {
25
+ baseUrl: ctx.connection.config.baseUrl.replace(/\/$/, ""),
26
+ apiKey: ctx.connection.config.apiKey,
27
+ };
28
+ }
29
+ function gf(ctx, method, endpoint, body, qs) {
30
+ const { baseUrl, apiKey } = getConn(ctx);
31
+ return apiRequest(baseUrl, apiKey, method, endpoint, body, qs);
32
+ }
33
+ export default function grafana(rl) {
34
+ rl.setName("grafana");
35
+ rl.setVersion("0.1.0");
36
+ 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" },
39
+ });
40
+ // ── Dashboard ───────────────────────────────────────
41
+ rl.registerAction("dashboard.create", {
42
+ description: "Create or save a dashboard",
43
+ inputSchema: {
44
+ dashboard: { type: "object", required: true, description: "Dashboard JSON model" },
45
+ folderId: { type: "number", required: false, description: "Folder ID" },
46
+ overwrite: { type: "boolean", required: false, description: "Overwrite existing" },
47
+ message: { type: "string", required: false, description: "Save message" },
48
+ },
49
+ async execute(input, ctx) {
50
+ const { dashboard, folderId, overwrite, message } = input;
51
+ const body = { dashboard };
52
+ if (folderId !== undefined)
53
+ body.folderId = folderId;
54
+ if (overwrite !== undefined)
55
+ body.overwrite = overwrite;
56
+ if (message)
57
+ body.message = message;
58
+ return gf(ctx, "POST", "/dashboards/db", body);
59
+ },
60
+ });
61
+ rl.registerAction("dashboard.get", {
62
+ description: "Get a dashboard by UID",
63
+ inputSchema: { uid: { type: "string", required: true, description: "Dashboard UID" } },
64
+ async execute(input, ctx) {
65
+ return gf(ctx, "GET", `/dashboards/uid/${input.uid}`);
66
+ },
67
+ });
68
+ rl.registerAction("dashboard.list", {
69
+ description: "Search dashboards",
70
+ inputSchema: {
71
+ query: { type: "string", required: false, description: "Search query" },
72
+ 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" },
75
+ limit: { type: "number", required: false, description: "Max results" },
76
+ },
77
+ async execute(input, ctx) {
78
+ const { query, tag, type, folderId, limit } = (input ?? {});
79
+ const qs = {};
80
+ if (query)
81
+ qs.query = query;
82
+ if (tag)
83
+ qs.tag = tag;
84
+ if (type)
85
+ qs.type = type;
86
+ if (folderId !== undefined)
87
+ qs.folderIds = folderId;
88
+ if (limit)
89
+ qs.limit = limit;
90
+ return gf(ctx, "GET", "/search", undefined, qs);
91
+ },
92
+ });
93
+ rl.registerAction("dashboard.delete", {
94
+ description: "Delete a dashboard by UID",
95
+ inputSchema: { uid: { type: "string", required: true, description: "Dashboard UID" } },
96
+ async execute(input, ctx) {
97
+ return gf(ctx, "DELETE", `/dashboards/uid/${input.uid}`);
98
+ },
99
+ });
100
+ rl.registerAction("dashboard.update", {
101
+ description: "Update an existing dashboard",
102
+ inputSchema: {
103
+ uid: { type: "string", required: true, description: "Dashboard UID to update" },
104
+ dashboard: { type: "object", required: true, description: "Updated dashboard JSON model" },
105
+ folderId: { type: "number", required: false, description: "Folder ID" },
106
+ message: { type: "string", required: false, description: "Save message" },
107
+ },
108
+ async execute(input, ctx) {
109
+ const { uid, dashboard, folderId, message } = input;
110
+ const body = { dashboard: { ...dashboard, uid }, overwrite: true };
111
+ if (folderId !== undefined)
112
+ body.folderId = folderId;
113
+ if (message)
114
+ body.message = message;
115
+ return gf(ctx, "POST", "/dashboards/db", body);
116
+ },
117
+ });
118
+ // ── Team ────────────────────────────────────────────
119
+ rl.registerAction("team.create", {
120
+ description: "Create a team",
121
+ inputSchema: {
122
+ name: { type: "string", required: true, description: "Team name" },
123
+ email: { type: "string", required: false, description: "Team email" },
124
+ },
125
+ async execute(input, ctx) {
126
+ const { name, email } = input;
127
+ const body = { name };
128
+ if (email)
129
+ body.email = email;
130
+ return gf(ctx, "POST", "/teams", body);
131
+ },
132
+ });
133
+ rl.registerAction("team.get", {
134
+ description: "Get a team by ID",
135
+ inputSchema: { teamId: { type: "number", required: true, description: "Team ID" } },
136
+ async execute(input, ctx) {
137
+ return gf(ctx, "GET", `/teams/${input.teamId}`);
138
+ },
139
+ });
140
+ rl.registerAction("team.list", {
141
+ description: "Search teams",
142
+ inputSchema: {
143
+ query: { type: "string", required: false, description: "Search by name" },
144
+ limit: { type: "number", required: false, description: "Max results" },
145
+ page: { type: "number", required: false, description: "Page number" },
146
+ },
147
+ async execute(input, ctx) {
148
+ const { query, limit, page } = (input ?? {});
149
+ const qs = {};
150
+ if (query)
151
+ qs.query = query;
152
+ if (limit)
153
+ qs.perpage = limit;
154
+ if (page)
155
+ qs.page = page;
156
+ const data = (await gf(ctx, "GET", "/teams/search", undefined, qs));
157
+ return data.teams;
158
+ },
159
+ });
160
+ rl.registerAction("team.update", {
161
+ description: "Update a team",
162
+ inputSchema: {
163
+ teamId: { type: "number", required: true, description: "Team ID" },
164
+ name: { type: "string", required: false, description: "New name" },
165
+ email: { type: "string", required: false, description: "New email" },
166
+ },
167
+ async execute(input, ctx) {
168
+ const { teamId, name, email } = input;
169
+ const body = {};
170
+ if (name)
171
+ body.name = name;
172
+ if (email)
173
+ body.email = email;
174
+ return gf(ctx, "PUT", `/teams/${teamId}`, body);
175
+ },
176
+ });
177
+ rl.registerAction("team.delete", {
178
+ description: "Delete a team",
179
+ inputSchema: { teamId: { type: "number", required: true, description: "Team ID" } },
180
+ async execute(input, ctx) {
181
+ return gf(ctx, "DELETE", `/teams/${input.teamId}`);
182
+ },
183
+ });
184
+ // ── Team Member ─────────────────────────────────────
185
+ rl.registerAction("teamMember.add", {
186
+ description: "Add a user to a team",
187
+ inputSchema: {
188
+ teamId: { type: "number", required: true, description: "Team ID" },
189
+ userId: { type: "number", required: true, description: "User ID to add" },
190
+ },
191
+ async execute(input, ctx) {
192
+ const { teamId, userId } = input;
193
+ return gf(ctx, "POST", `/teams/${teamId}/members`, { userId });
194
+ },
195
+ });
196
+ rl.registerAction("teamMember.remove", {
197
+ description: "Remove a user from a team",
198
+ inputSchema: {
199
+ teamId: { type: "number", required: true, description: "Team ID" },
200
+ userId: { type: "number", required: true, description: "User ID to remove" },
201
+ },
202
+ async execute(input, ctx) {
203
+ const { teamId, userId } = input;
204
+ return gf(ctx, "DELETE", `/teams/${teamId}/members/${userId}`);
205
+ },
206
+ });
207
+ rl.registerAction("teamMember.list", {
208
+ description: "List members of a team",
209
+ inputSchema: { teamId: { type: "number", required: true, description: "Team ID" } },
210
+ async execute(input, ctx) {
211
+ return gf(ctx, "GET", `/teams/${input.teamId}/members`);
212
+ },
213
+ });
214
+ // ── User (Org) ──────────────────────────────────────
215
+ rl.registerAction("user.create", {
216
+ description: "Add a user to the current organization",
217
+ inputSchema: {
218
+ loginOrEmail: { type: "string", required: true, description: "Login name or email" },
219
+ role: { type: "string", required: true, description: "Viewer, Editor, or Admin" },
220
+ },
221
+ async execute(input, ctx) {
222
+ const { loginOrEmail, role } = input;
223
+ return gf(ctx, "POST", "/org/users", { loginOrEmail, role });
224
+ },
225
+ });
226
+ rl.registerAction("user.list", {
227
+ description: "List users in the current organization",
228
+ async execute(_input, ctx) {
229
+ return gf(ctx, "GET", "/org/users");
230
+ },
231
+ });
232
+ rl.registerAction("user.update", {
233
+ description: "Update a user's role in the organization",
234
+ inputSchema: {
235
+ userId: { type: "number", required: true, description: "User ID" },
236
+ role: { type: "string", required: true, description: "Viewer, Editor, or Admin" },
237
+ },
238
+ async execute(input, ctx) {
239
+ const { userId, role } = input;
240
+ return gf(ctx, "PATCH", `/org/users/${userId}`, { role });
241
+ },
242
+ });
243
+ rl.registerAction("user.delete", {
244
+ description: "Remove a user from the organization",
245
+ inputSchema: { userId: { type: "number", required: true, description: "User ID" } },
246
+ async execute(input, ctx) {
247
+ return gf(ctx, "DELETE", `/org/users/${input.userId}`);
248
+ },
249
+ });
250
+ }
@@ -0,0 +1,78 @@
1
+ export default function graphql(rl) {
2
+ rl.setName("graphql");
3
+ rl.setVersion("0.1.0");
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" },
8
+ });
9
+ rl.registerAction("query", {
10
+ description: "Execute a GraphQL query",
11
+ 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)" },
15
+ },
16
+ async execute(input, ctx) {
17
+ const { query, variables, operationName } = input;
18
+ const cfg = ctx.connection.config;
19
+ const endpoint = cfg.endpoint;
20
+ const hdrs = { "Content-Type": "application/json" };
21
+ if (cfg.headerAuth)
22
+ hdrs.Authorization = cfg.headerAuth;
23
+ if (cfg.headers) {
24
+ for (const [k, v] of Object.entries(cfg.headers)) {
25
+ hdrs[k] = v;
26
+ }
27
+ }
28
+ const body = { query };
29
+ if (variables)
30
+ body.variables = variables;
31
+ if (operationName)
32
+ body.operationName = operationName;
33
+ const res = await fetch(endpoint, {
34
+ method: "POST",
35
+ headers: hdrs,
36
+ body: JSON.stringify(body),
37
+ });
38
+ if (!res.ok)
39
+ throw new Error(`GraphQL error ${res.status}: ${await res.text()}`);
40
+ const data = (await res.json());
41
+ if (data.errors)
42
+ throw new Error(`GraphQL errors: ${JSON.stringify(data.errors)}`);
43
+ return data.data;
44
+ },
45
+ });
46
+ rl.registerAction("introspect", {
47
+ description: "Run an introspection query to get the schema",
48
+ async execute(_input, ctx) {
49
+ const cfg = ctx.connection.config;
50
+ const endpoint = cfg.endpoint;
51
+ const hdrs = { "Content-Type": "application/json" };
52
+ if (cfg.headerAuth)
53
+ hdrs.Authorization = cfg.headerAuth;
54
+ if (cfg.headers) {
55
+ for (const [k, v] of Object.entries(cfg.headers)) {
56
+ hdrs[k] = v;
57
+ }
58
+ }
59
+ const introspectionQuery = `{
60
+ __schema {
61
+ types { name kind description fields { name type { name kind ofType { name kind } } } }
62
+ queryType { name }
63
+ mutationType { name }
64
+ subscriptionType { name }
65
+ }
66
+ }`;
67
+ const res = await fetch(endpoint, {
68
+ method: "POST",
69
+ headers: hdrs,
70
+ body: JSON.stringify({ query: introspectionQuery }),
71
+ });
72
+ if (!res.ok)
73
+ throw new Error(`GraphQL error ${res.status}: ${await res.text()}`);
74
+ const data = (await res.json());
75
+ return data.data;
76
+ },
77
+ });
78
+ }