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,476 @@
1
+ async function apiRequest(baseUrl, apiKey, method, endpoint, body) {
2
+ const opts = {
3
+ method,
4
+ headers: { Authorization: apiKey, Accept: "application/json", "Content-Type": "application/json" },
5
+ };
6
+ if (body && Object.keys(body).length > 0 && method !== "GET" && method !== "DELETE")
7
+ opts.body = JSON.stringify(body);
8
+ const res = await fetch(`${baseUrl}${endpoint}`, opts);
9
+ if (!res.ok)
10
+ throw new Error(`MISP API error ${res.status}: ${await res.text()}`);
11
+ return res.json();
12
+ }
13
+ export default function misp(rl) {
14
+ rl.setName("misp");
15
+ rl.setVersion("0.1.0");
16
+ rl.setConnectionSchema({
17
+ baseUrl: { type: "string", required: true, description: "MISP instance URL", env: "MISP_URL" },
18
+ apiKey: { type: "string", required: true, description: "MISP API key (Authorization header)", env: "MISP_API_KEY" },
19
+ });
20
+ const conn = (ctx) => ({
21
+ baseUrl: ctx.connection.config.baseUrl.replace(/\/$/, ""),
22
+ apiKey: ctx.connection.config.apiKey,
23
+ });
24
+ const req = (ctx, method, ep, body) => {
25
+ const c = conn(ctx);
26
+ return apiRequest(c.baseUrl, c.apiKey, method, ep, body);
27
+ };
28
+ // ── Attribute ───────────────────────────────────────
29
+ rl.registerAction("attribute.create", {
30
+ description: "Add an attribute to an event",
31
+ inputSchema: {
32
+ eventId: { type: "string", required: true },
33
+ type: { type: "string", required: true, description: "Attribute type (ip-src, domain, md5, etc.)" },
34
+ value: { type: "string", required: true },
35
+ additionalFields: { type: "object", required: false, description: "category, comment, to_ids, distribution, sharing_group_id, etc." },
36
+ },
37
+ async execute(input, ctx) {
38
+ const { eventId, type, value, additionalFields } = input;
39
+ const body = { type, value };
40
+ if (additionalFields)
41
+ Object.assign(body, additionalFields);
42
+ const data = (await req(ctx, "POST", `/attributes/add/${eventId}`, body));
43
+ return data.Attribute;
44
+ },
45
+ });
46
+ rl.registerAction("attribute.get", {
47
+ description: "Get an attribute by ID",
48
+ inputSchema: { attributeId: { type: "string", required: true } },
49
+ async execute(input, ctx) {
50
+ const data = (await req(ctx, "GET", `/attributes/view/${input.attributeId}`));
51
+ return data.Attribute;
52
+ },
53
+ });
54
+ rl.registerAction("attribute.list", {
55
+ description: "List all attributes",
56
+ inputSchema: { limit: { type: "number", required: false } },
57
+ async execute(input, ctx) {
58
+ let data = (await req(ctx, "GET", "/attributes"));
59
+ if (input?.limit)
60
+ data = data.slice(0, input.limit);
61
+ return data;
62
+ },
63
+ });
64
+ rl.registerAction("attribute.search", {
65
+ description: "Search attributes via restSearch",
66
+ inputSchema: {
67
+ value: { type: "string", required: false },
68
+ searchBody: { type: "object", required: false, description: "Full search body (value, type, category, tags, etc.)" },
69
+ },
70
+ async execute(input, ctx) {
71
+ const { value, searchBody } = (input ?? {});
72
+ const body = searchBody ?? {};
73
+ if (value)
74
+ body.value = value;
75
+ const data = (await req(ctx, "POST", "/attributes/restSearch", body));
76
+ return data.response?.Attribute ?? [];
77
+ },
78
+ });
79
+ rl.registerAction("attribute.update", {
80
+ description: "Update an attribute",
81
+ inputSchema: { attributeId: { type: "string", required: true }, updateFields: { type: "object", required: true } },
82
+ async execute(input, ctx) {
83
+ const { attributeId, updateFields } = input;
84
+ const data = (await req(ctx, "PUT", `/attributes/edit/${attributeId}`, updateFields));
85
+ return data.Attribute;
86
+ },
87
+ });
88
+ rl.registerAction("attribute.delete", {
89
+ description: "Delete an attribute",
90
+ inputSchema: { attributeId: { type: "string", required: true } },
91
+ async execute(input, ctx) { return req(ctx, "DELETE", `/attributes/delete/${input.attributeId}`); },
92
+ });
93
+ // ── Event ───────────────────────────────────────────
94
+ rl.registerAction("event.create", {
95
+ description: "Create an event",
96
+ inputSchema: {
97
+ orgId: { type: "string", required: true, description: "Organisation ID" },
98
+ info: { type: "string", required: true, description: "Event description/info" },
99
+ additionalFields: { type: "object", required: false, description: "distribution, threat_level_id, analysis, date, etc." },
100
+ },
101
+ async execute(input, ctx) {
102
+ const { orgId, info, additionalFields } = input;
103
+ const body = { org_id: orgId, info };
104
+ if (additionalFields)
105
+ Object.assign(body, additionalFields);
106
+ const data = (await req(ctx, "POST", "/events", body));
107
+ return data.Event;
108
+ },
109
+ });
110
+ rl.registerAction("event.get", {
111
+ description: "Get an event by ID",
112
+ inputSchema: { eventId: { type: "string", required: true } },
113
+ async execute(input, ctx) {
114
+ const data = (await req(ctx, "GET", `/events/view/${input.eventId}`));
115
+ const event = data.Event;
116
+ delete event.Attribute; // prevent excessive payload
117
+ return event;
118
+ },
119
+ });
120
+ rl.registerAction("event.list", {
121
+ description: "List all events",
122
+ inputSchema: { limit: { type: "number", required: false } },
123
+ async execute(input, ctx) {
124
+ let data = (await req(ctx, "GET", "/events"));
125
+ if (input?.limit)
126
+ data = data.slice(0, input.limit);
127
+ return data;
128
+ },
129
+ });
130
+ rl.registerAction("event.search", {
131
+ description: "Search events via restSearch",
132
+ inputSchema: {
133
+ value: { type: "string", required: false },
134
+ searchBody: { type: "object", required: false, description: "Full search body" },
135
+ },
136
+ async execute(input, ctx) {
137
+ const { value, searchBody } = (input ?? {});
138
+ const body = searchBody ?? {};
139
+ if (value)
140
+ body.value = value;
141
+ const data = (await req(ctx, "POST", "/events/restSearch", body));
142
+ const response = data.response;
143
+ return response?.map((e) => e.Event) ?? [];
144
+ },
145
+ });
146
+ rl.registerAction("event.update", {
147
+ description: "Update an event",
148
+ inputSchema: { eventId: { type: "string", required: true }, updateFields: { type: "object", required: true } },
149
+ async execute(input, ctx) {
150
+ const { eventId, updateFields } = input;
151
+ const data = (await req(ctx, "PUT", `/events/edit/${eventId}`, updateFields));
152
+ const event = data.Event;
153
+ delete event.Attribute;
154
+ return event;
155
+ },
156
+ });
157
+ rl.registerAction("event.publish", {
158
+ description: "Publish an event",
159
+ inputSchema: { eventId: { type: "string", required: true } },
160
+ async execute(input, ctx) { return req(ctx, "POST", `/events/publish/${input.eventId}`); },
161
+ });
162
+ rl.registerAction("event.unpublish", {
163
+ description: "Unpublish an event",
164
+ inputSchema: { eventId: { type: "string", required: true } },
165
+ async execute(input, ctx) { return req(ctx, "POST", `/events/unpublish/${input.eventId}`); },
166
+ });
167
+ rl.registerAction("event.delete", {
168
+ description: "Delete an event",
169
+ inputSchema: { eventId: { type: "string", required: true } },
170
+ async execute(input, ctx) { return req(ctx, "DELETE", `/events/delete/${input.eventId}`); },
171
+ });
172
+ // ── Event Tag ───────────────────────────────────────
173
+ rl.registerAction("eventTag.add", {
174
+ description: "Add a tag to an event",
175
+ inputSchema: { eventId: { type: "string", required: true }, tagId: { type: "string", required: true } },
176
+ async execute(input, ctx) {
177
+ const { eventId, tagId } = input;
178
+ return req(ctx, "POST", "/events/addTag", { event: eventId, tag: tagId });
179
+ },
180
+ });
181
+ rl.registerAction("eventTag.remove", {
182
+ description: "Remove a tag from an event",
183
+ inputSchema: { eventId: { type: "string", required: true }, tagId: { type: "string", required: true } },
184
+ async execute(input, ctx) {
185
+ const { eventId, tagId } = input;
186
+ return req(ctx, "POST", `/events/removeTag/${eventId}/${tagId}`);
187
+ },
188
+ });
189
+ // ── Feed ────────────────────────────────────────────
190
+ rl.registerAction("feed.create", {
191
+ description: "Create a feed",
192
+ inputSchema: {
193
+ name: { type: "string", required: true },
194
+ provider: { type: "string", required: true },
195
+ url: { type: "string", required: true },
196
+ additionalFields: { type: "object", required: false, description: "input_source, source_format, enabled, distribution, etc." },
197
+ },
198
+ async execute(input, ctx) {
199
+ const { name, provider, url, additionalFields } = input;
200
+ const body = { name, provider, url };
201
+ if (additionalFields)
202
+ Object.assign(body, additionalFields);
203
+ const data = (await req(ctx, "POST", "/feeds/add", body));
204
+ return data.Feed;
205
+ },
206
+ });
207
+ rl.registerAction("feed.get", {
208
+ description: "Get a feed by ID",
209
+ inputSchema: { feedId: { type: "string", required: true } },
210
+ async execute(input, ctx) {
211
+ const data = (await req(ctx, "GET", `/feeds/view/${input.feedId}`));
212
+ return data.Feed;
213
+ },
214
+ });
215
+ rl.registerAction("feed.list", {
216
+ description: "List all feeds",
217
+ inputSchema: { limit: { type: "number", required: false } },
218
+ async execute(input, ctx) {
219
+ let data = (await req(ctx, "GET", "/feeds"));
220
+ data = data.map((e) => e.Feed);
221
+ if (input?.limit)
222
+ data = data.slice(0, input.limit);
223
+ return data;
224
+ },
225
+ });
226
+ rl.registerAction("feed.update", {
227
+ description: "Update a feed",
228
+ inputSchema: { feedId: { type: "string", required: true }, updateFields: { type: "object", required: true } },
229
+ async execute(input, ctx) {
230
+ const { feedId, updateFields } = input;
231
+ const data = (await req(ctx, "PUT", `/feeds/edit/${feedId}`, updateFields));
232
+ return data.Feed;
233
+ },
234
+ });
235
+ rl.registerAction("feed.enable", {
236
+ description: "Enable a feed",
237
+ inputSchema: { feedId: { type: "string", required: true } },
238
+ async execute(input, ctx) { return req(ctx, "POST", `/feeds/enable/${input.feedId}`); },
239
+ });
240
+ rl.registerAction("feed.disable", {
241
+ description: "Disable a feed",
242
+ inputSchema: { feedId: { type: "string", required: true } },
243
+ async execute(input, ctx) { return req(ctx, "POST", `/feeds/disable/${input.feedId}`); },
244
+ });
245
+ // ── Galaxy ──────────────────────────────────────────
246
+ rl.registerAction("galaxy.get", {
247
+ description: "Get a galaxy by ID",
248
+ inputSchema: { galaxyId: { type: "string", required: true } },
249
+ async execute(input, ctx) {
250
+ const data = (await req(ctx, "GET", `/galaxies/view/${input.galaxyId}`));
251
+ return data.Galaxy;
252
+ },
253
+ });
254
+ rl.registerAction("galaxy.list", {
255
+ description: "List all galaxies",
256
+ inputSchema: { limit: { type: "number", required: false } },
257
+ async execute(input, ctx) {
258
+ let data = (await req(ctx, "GET", "/galaxies"));
259
+ data = data.map((e) => e.Galaxy);
260
+ if (input?.limit)
261
+ data = data.slice(0, input.limit);
262
+ return data;
263
+ },
264
+ });
265
+ rl.registerAction("galaxy.delete", {
266
+ description: "Delete a galaxy",
267
+ inputSchema: { galaxyId: { type: "string", required: true } },
268
+ async execute(input, ctx) { return req(ctx, "DELETE", `/galaxies/delete/${input.galaxyId}`); },
269
+ });
270
+ // ── Noticelist ──────────────────────────────────────
271
+ rl.registerAction("noticelist.get", {
272
+ description: "Get a noticelist by ID",
273
+ inputSchema: { noticelistId: { type: "string", required: true } },
274
+ async execute(input, ctx) {
275
+ const data = (await req(ctx, "GET", `/noticelists/view/${input.noticelistId}`));
276
+ return data.Noticelist;
277
+ },
278
+ });
279
+ rl.registerAction("noticelist.list", {
280
+ description: "List all noticelists",
281
+ inputSchema: { limit: { type: "number", required: false } },
282
+ async execute(input, ctx) {
283
+ let data = (await req(ctx, "GET", "/noticelists"));
284
+ data = data.map((e) => e.Noticelist);
285
+ if (input?.limit)
286
+ data = data.slice(0, input.limit);
287
+ return data;
288
+ },
289
+ });
290
+ // ── Object ──────────────────────────────────────────
291
+ rl.registerAction("object.search", {
292
+ description: "Search objects via restSearch",
293
+ inputSchema: {
294
+ value: { type: "string", required: false },
295
+ searchBody: { type: "object", required: false },
296
+ },
297
+ async execute(input, ctx) {
298
+ const { value, searchBody } = (input ?? {});
299
+ const body = searchBody ?? {};
300
+ if (value)
301
+ body.value = value;
302
+ const data = (await req(ctx, "POST", "/objects/restSearch", body));
303
+ const response = data.response;
304
+ return response?.map((o) => o.Object) ?? [];
305
+ },
306
+ });
307
+ // ── Organisation ────────────────────────────────────
308
+ rl.registerAction("organisation.create", {
309
+ description: "Create an organisation",
310
+ inputSchema: {
311
+ name: { type: "string", required: true },
312
+ additionalFields: { type: "object", required: false, description: "description, type, nationality, sector, contacts, uuid, local" },
313
+ },
314
+ async execute(input, ctx) {
315
+ const { name, additionalFields } = input;
316
+ const body = { name };
317
+ if (additionalFields)
318
+ Object.assign(body, additionalFields);
319
+ const data = (await req(ctx, "POST", "/admin/organisations/add", body));
320
+ return data.Organisation;
321
+ },
322
+ });
323
+ rl.registerAction("organisation.get", {
324
+ description: "Get an organisation by ID",
325
+ inputSchema: { organisationId: { type: "string", required: true } },
326
+ async execute(input, ctx) {
327
+ const data = (await req(ctx, "GET", `/organisations/view/${input.organisationId}`));
328
+ return data.Organisation;
329
+ },
330
+ });
331
+ rl.registerAction("organisation.list", {
332
+ description: "List all organisations",
333
+ inputSchema: { limit: { type: "number", required: false } },
334
+ async execute(input, ctx) {
335
+ let data = (await req(ctx, "GET", "/organisations"));
336
+ data = data.map((e) => e.Organisation);
337
+ if (input?.limit)
338
+ data = data.slice(0, input.limit);
339
+ return data;
340
+ },
341
+ });
342
+ rl.registerAction("organisation.update", {
343
+ description: "Update an organisation",
344
+ inputSchema: { organisationId: { type: "string", required: true }, updateFields: { type: "object", required: true } },
345
+ async execute(input, ctx) {
346
+ const { organisationId, updateFields } = input;
347
+ const data = (await req(ctx, "PUT", `/admin/organisations/edit/${organisationId}`, updateFields));
348
+ return data.Organisation;
349
+ },
350
+ });
351
+ rl.registerAction("organisation.delete", {
352
+ description: "Delete an organisation",
353
+ inputSchema: { organisationId: { type: "string", required: true } },
354
+ async execute(input, ctx) { return req(ctx, "DELETE", `/admin/organisations/delete/${input.organisationId}`); },
355
+ });
356
+ // ── Tag ─────────────────────────────────────────────
357
+ rl.registerAction("tag.create", {
358
+ description: "Create a tag",
359
+ inputSchema: {
360
+ name: { type: "string", required: true },
361
+ colour: { type: "string", required: false, description: "Hex colour (e.g. #ff0000)" },
362
+ },
363
+ async execute(input, ctx) {
364
+ const { name, colour } = input;
365
+ const body = { name };
366
+ if (colour)
367
+ body.colour = colour.startsWith("#") ? colour : `#${colour}`;
368
+ const data = (await req(ctx, "POST", "/tags/add", body));
369
+ return data.Tag;
370
+ },
371
+ });
372
+ rl.registerAction("tag.list", {
373
+ description: "List all tags",
374
+ inputSchema: { limit: { type: "number", required: false } },
375
+ async execute(input, ctx) {
376
+ const data = (await req(ctx, "GET", "/tags"));
377
+ let tags = data.Tag;
378
+ if (input?.limit)
379
+ tags = tags.slice(0, input.limit);
380
+ return tags;
381
+ },
382
+ });
383
+ rl.registerAction("tag.update", {
384
+ description: "Update a tag",
385
+ inputSchema: {
386
+ tagId: { type: "string", required: true },
387
+ name: { type: "string", required: false },
388
+ colour: { type: "string", required: false },
389
+ },
390
+ async execute(input, ctx) {
391
+ const { tagId, name, colour } = input;
392
+ const body = {};
393
+ if (name)
394
+ body.name = name;
395
+ if (colour)
396
+ body.colour = colour.startsWith("#") ? colour : `#${colour}`;
397
+ const data = (await req(ctx, "POST", `/tags/edit/${tagId}`, body));
398
+ return data.Tag;
399
+ },
400
+ });
401
+ rl.registerAction("tag.delete", {
402
+ description: "Delete a tag",
403
+ inputSchema: { tagId: { type: "string", required: true } },
404
+ async execute(input, ctx) { return req(ctx, "POST", `/tags/delete/${input.tagId}`); },
405
+ });
406
+ // ── User ────────────────────────────────────────────
407
+ rl.registerAction("user.create", {
408
+ description: "Create a user",
409
+ inputSchema: {
410
+ email: { type: "string", required: true },
411
+ roleId: { type: "string", required: true, description: "Role ID" },
412
+ additionalFields: { type: "object", required: false, description: "org_id, password, termsaccepted, change_pw, etc." },
413
+ },
414
+ async execute(input, ctx) {
415
+ const { email, roleId, additionalFields } = input;
416
+ const body = { email, role_id: roleId };
417
+ if (additionalFields)
418
+ Object.assign(body, additionalFields);
419
+ const data = (await req(ctx, "POST", "/admin/users/add", body));
420
+ return data.User;
421
+ },
422
+ });
423
+ rl.registerAction("user.get", {
424
+ description: "Get a user by ID",
425
+ inputSchema: { userId: { type: "string", required: true } },
426
+ async execute(input, ctx) {
427
+ const data = (await req(ctx, "GET", `/admin/users/view/${input.userId}`));
428
+ return data.User;
429
+ },
430
+ });
431
+ rl.registerAction("user.list", {
432
+ description: "List all users",
433
+ inputSchema: { limit: { type: "number", required: false } },
434
+ async execute(input, ctx) {
435
+ let data = (await req(ctx, "GET", "/admin/users"));
436
+ data = data.map((e) => e.User);
437
+ if (input?.limit)
438
+ data = data.slice(0, input.limit);
439
+ return data;
440
+ },
441
+ });
442
+ rl.registerAction("user.update", {
443
+ description: "Update a user",
444
+ inputSchema: { userId: { type: "string", required: true }, updateFields: { type: "object", required: true } },
445
+ async execute(input, ctx) {
446
+ const { userId, updateFields } = input;
447
+ const data = (await req(ctx, "PUT", `/admin/users/edit/${userId}`, updateFields));
448
+ return data.User;
449
+ },
450
+ });
451
+ rl.registerAction("user.delete", {
452
+ description: "Delete a user",
453
+ inputSchema: { userId: { type: "string", required: true } },
454
+ async execute(input, ctx) { return req(ctx, "DELETE", `/admin/users/delete/${input.userId}`); },
455
+ });
456
+ // ── Warninglist ─────────────────────────────────────
457
+ rl.registerAction("warninglist.get", {
458
+ description: "Get a warninglist by ID",
459
+ inputSchema: { warninglistId: { type: "string", required: true } },
460
+ async execute(input, ctx) {
461
+ const data = (await req(ctx, "GET", `/warninglists/view/${input.warninglistId}`));
462
+ return data.Warninglist;
463
+ },
464
+ });
465
+ rl.registerAction("warninglist.list", {
466
+ description: "List all warninglists",
467
+ inputSchema: { limit: { type: "number", required: false } },
468
+ async execute(input, ctx) {
469
+ const data = (await req(ctx, "GET", "/warninglists"));
470
+ let lists = (data.Warninglists ?? []).map((e) => e.Warninglist);
471
+ if (input?.limit)
472
+ lists = lists.slice(0, input.limit);
473
+ return lists;
474
+ },
475
+ });
476
+ }
@@ -0,0 +1,67 @@
1
+ const BASE_URL = "https://rest.moceanapi.com";
2
+ async function apiRequest(apiKey, apiSecret, endpoint, body) {
3
+ body["mocean-api-key"] = apiKey;
4
+ body["mocean-api-secret"] = apiSecret;
5
+ body["mocean-resp-format"] = "JSON";
6
+ const form = new URLSearchParams();
7
+ for (const [k, v] of Object.entries(body)) {
8
+ if (v !== undefined && v !== null)
9
+ form.set(k, String(v));
10
+ }
11
+ const res = await fetch(`${BASE_URL}${endpoint}`, {
12
+ method: "POST",
13
+ body: form,
14
+ });
15
+ if (!res.ok)
16
+ throw new Error(`Mocean API error ${res.status}: ${await res.text()}`);
17
+ return res.json();
18
+ }
19
+ export default function mocean(rl) {
20
+ rl.setName("mocean");
21
+ rl.setVersion("0.1.0");
22
+ rl.setConnectionSchema({
23
+ apiKey: { type: "string", required: true, description: "Mocean API key", env: "MOCEAN_API_KEY" },
24
+ apiSecret: { type: "string", required: true, description: "Mocean API secret", env: "MOCEAN_API_SECRET" },
25
+ });
26
+ const creds = (ctx) => ({
27
+ apiKey: ctx.connection.config.apiKey,
28
+ apiSecret: ctx.connection.config.apiSecret,
29
+ });
30
+ rl.registerAction("sms.send", {
31
+ description: "Send an SMS message",
32
+ inputSchema: {
33
+ from: { type: "string", required: true, description: "Sender number" },
34
+ to: { type: "string", required: true, description: "Recipient number" },
35
+ message: { type: "string", required: true },
36
+ dlrUrl: { type: "string", required: false, description: "Delivery report URL" },
37
+ },
38
+ async execute(input, ctx) {
39
+ const { from, to, message, dlrUrl } = input;
40
+ const { apiKey, apiSecret } = creds(ctx);
41
+ const body = { "mocean-from": from, "mocean-to": to, "mocean-text": message };
42
+ if (dlrUrl) {
43
+ body["mocean-dlr-url"] = dlrUrl;
44
+ body["mocean-dlr-mask"] = "1";
45
+ }
46
+ const data = (await apiRequest(apiKey, apiSecret, "/rest/2/sms", body));
47
+ return data.messages;
48
+ },
49
+ });
50
+ rl.registerAction("voice.send", {
51
+ description: "Make a voice call with text-to-speech",
52
+ inputSchema: {
53
+ from: { type: "string", required: true, description: "Caller number" },
54
+ to: { type: "string", required: true, description: "Recipient number" },
55
+ message: { type: "string", required: true, description: "Text to speak" },
56
+ language: { type: "string", required: false, description: "Language code: en-US (default), en-GB, cmn-CN, ja-JP, ko-KR" },
57
+ },
58
+ async execute(input, ctx) {
59
+ const { from, to, message, language = "en-US" } = input;
60
+ const { apiKey, apiSecret } = creds(ctx);
61
+ const command = [{ action: "say", language, text: message }];
62
+ const body = { "mocean-from": from, "mocean-to": to, "mocean-command": JSON.stringify(command) };
63
+ const data = (await apiRequest(apiKey, apiSecret, "/rest/2/voice/dial", body));
64
+ return data.voice;
65
+ },
66
+ });
67
+ }