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,137 @@
1
+ const BASE = "https://www.strava.com/api/v3";
2
+ async function apiRequest(token, method, endpoint, body, qs) {
3
+ const url = new URL(`${BASE}${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 init = { method, headers: { Authorization: `Bearer ${token}` } };
11
+ if (body && Object.keys(body).length > 0) {
12
+ const form = new URLSearchParams();
13
+ for (const [k, v] of Object.entries(body)) {
14
+ if (v !== undefined && v !== null)
15
+ form.set(k, String(v));
16
+ }
17
+ init.body = form;
18
+ init.headers["Content-Type"] = "application/x-www-form-urlencoded";
19
+ }
20
+ const res = await fetch(url.toString(), init);
21
+ if (!res.ok)
22
+ throw new Error(`Strava error ${res.status}: ${await res.text()}`);
23
+ return res.json();
24
+ }
25
+ export default function strava(rl) {
26
+ rl.setName("strava");
27
+ rl.setVersion("0.1.0");
28
+ rl.setConnectionSchema({
29
+ accessToken: { type: "string", required: true, description: "Strava OAuth2 access token", env: "STRAVA_ACCESS_TOKEN" },
30
+ });
31
+ const key = (ctx) => ctx.connection.config.accessToken;
32
+ rl.registerAction("activity.create", {
33
+ description: "Create an activity",
34
+ inputSchema: {
35
+ name: { type: "string", required: true },
36
+ sportType: { type: "string", required: true, description: "e.g. Run, Ride, Swim, Hike" },
37
+ startDateLocal: { type: "string", required: true, description: "ISO 8601 start time" },
38
+ elapsedTime: { type: "number", required: true, description: "Duration in seconds" },
39
+ description: { type: "string", required: false },
40
+ distance: { type: "number", required: false, description: "Distance in meters" },
41
+ trainer: { type: "boolean", required: false },
42
+ commute: { type: "boolean", required: false },
43
+ },
44
+ async execute(input, ctx) {
45
+ const p = input;
46
+ const body = {
47
+ name: p.name, sport_type: p.sportType,
48
+ start_date_local: new Date(p.startDateLocal).toISOString(),
49
+ elapsed_time: p.elapsedTime,
50
+ };
51
+ if (p.description)
52
+ body.description = p.description;
53
+ if (p.distance)
54
+ body.distance = p.distance;
55
+ if (p.trainer)
56
+ body.trainer = 1;
57
+ if (p.commute)
58
+ body.commute = 1;
59
+ return apiRequest(key(ctx), "POST", "/activities", body);
60
+ },
61
+ });
62
+ rl.registerAction("activity.get", {
63
+ description: "Get an activity by ID",
64
+ inputSchema: { activityId: { type: "string", required: true } },
65
+ async execute(input, ctx) {
66
+ return apiRequest(key(ctx), "GET", `/activities/${input.activityId}`);
67
+ },
68
+ });
69
+ rl.registerAction("activity.list", {
70
+ description: "List the authenticated athlete's activities",
71
+ inputSchema: { limit: { type: "number", required: false } },
72
+ async execute(input, ctx) {
73
+ const qs = {};
74
+ if (input?.limit)
75
+ qs.per_page = input.limit;
76
+ return apiRequest(key(ctx), "GET", "/activities", undefined, qs);
77
+ },
78
+ });
79
+ rl.registerAction("activity.update", {
80
+ description: "Update an activity",
81
+ inputSchema: {
82
+ activityId: { type: "string", required: true },
83
+ name: { type: "string", required: false },
84
+ sportType: { type: "string", required: false },
85
+ description: { type: "string", required: false },
86
+ trainer: { type: "boolean", required: false },
87
+ commute: { type: "boolean", required: false },
88
+ gearId: { type: "string", required: false },
89
+ },
90
+ async execute(input, ctx) {
91
+ const { activityId, ...fields } = input;
92
+ const body = {};
93
+ if (fields.name)
94
+ body.name = fields.name;
95
+ if (fields.sportType)
96
+ body.sport_type = fields.sportType;
97
+ if (fields.description)
98
+ body.description = fields.description;
99
+ if (fields.trainer !== undefined)
100
+ body.trainer = fields.trainer;
101
+ if (fields.commute !== undefined)
102
+ body.commute = fields.commute;
103
+ if (fields.gearId)
104
+ body.gear_id = fields.gearId;
105
+ return apiRequest(key(ctx), "PUT", `/activities/${activityId}`, body);
106
+ },
107
+ });
108
+ for (const sub of [
109
+ { name: "getLaps", path: "laps", description: "Get laps for an activity" },
110
+ { name: "getZones", path: "zones", description: "Get zones for an activity" },
111
+ { name: "getKudos", path: "kudos", description: "Get kudos for an activity" },
112
+ { name: "getComments", path: "comments", description: "Get comments for an activity" },
113
+ ]) {
114
+ rl.registerAction(`activity.${sub.name}`, {
115
+ description: sub.description,
116
+ inputSchema: { activityId: { type: "string", required: true }, limit: { type: "number", required: false } },
117
+ async execute(input, ctx) {
118
+ const p = input;
119
+ const data = (await apiRequest(key(ctx), "GET", `/activities/${p.activityId}/${sub.path}`));
120
+ if (p.limit)
121
+ return data.slice(0, p.limit);
122
+ return data;
123
+ },
124
+ });
125
+ }
126
+ rl.registerAction("activity.getStreams", {
127
+ description: "Get activity streams (time-series data)",
128
+ inputSchema: {
129
+ activityId: { type: "string", required: true },
130
+ keys: { type: "string", required: true, description: "Comma-separated stream types: time, distance, latlng, altitude, heartrate, cadence, watts, temp, moving, grade_smooth" },
131
+ },
132
+ async execute(input, ctx) {
133
+ const p = input;
134
+ return apiRequest(key(ctx), "GET", `/activities/${p.activityId}/streams`, undefined, { keys: p.keys, key_by_type: "true" });
135
+ },
136
+ });
137
+ }
@@ -0,0 +1,222 @@
1
+ const BASE = "https://api.stripe.com/v1";
2
+ async function apiRequest(secretKey, method, endpoint, body, qs) {
3
+ const url = new URL(`${BASE}${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 init = { method, headers: { Authorization: `Bearer ${secretKey}` } };
11
+ if (body && Object.keys(body).length > 0) {
12
+ const form = new URLSearchParams();
13
+ function flatten(obj, prefix = "") {
14
+ for (const [k, v] of Object.entries(obj)) {
15
+ const key = prefix ? `${prefix}[${k}]` : k;
16
+ if (v !== null && v !== undefined && typeof v === "object" && !Array.isArray(v)) {
17
+ flatten(v, key);
18
+ }
19
+ else if (v !== null && v !== undefined) {
20
+ form.set(key, String(v));
21
+ }
22
+ }
23
+ }
24
+ flatten(body);
25
+ init.body = form;
26
+ init.headers["Content-Type"] = "application/x-www-form-urlencoded";
27
+ }
28
+ const res = await fetch(url.toString(), init);
29
+ if (!res.ok)
30
+ throw new Error(`Stripe error ${res.status}: ${await res.text()}`);
31
+ return res.json();
32
+ }
33
+ export default function stripe(rl) {
34
+ rl.setName("stripe");
35
+ rl.setVersion("0.1.0");
36
+ rl.setConnectionSchema({ secretKey: { type: "string", required: true, description: "Stripe secret API key", env: "STRIPE_SECRET_KEY" } });
37
+ const key = (ctx) => ctx.connection.config.secretKey;
38
+ // ── Balance ─────────────────────────────────────────
39
+ rl.registerAction("balance.get", {
40
+ description: "Get current balance",
41
+ inputSchema: {},
42
+ async execute(_input, ctx) { return apiRequest(key(ctx), "GET", "/balance"); },
43
+ });
44
+ // ── Customer ────────────────────────────────────────
45
+ rl.registerAction("customer.create", {
46
+ description: "Create a customer",
47
+ inputSchema: { name: { type: "string", required: true }, email: { type: "string", required: false }, phone: { type: "string", required: false }, description: { type: "string", required: false } },
48
+ async execute(input, ctx) { return apiRequest(key(ctx), "POST", "/customers", input); },
49
+ });
50
+ rl.registerAction("customer.get", {
51
+ description: "Get a customer by ID",
52
+ inputSchema: { customerId: { type: "string", required: true } },
53
+ async execute(input, ctx) { return apiRequest(key(ctx), "GET", `/customers/${input.customerId}`); },
54
+ });
55
+ rl.registerAction("customer.list", {
56
+ description: "List customers",
57
+ inputSchema: { limit: { type: "number", required: false }, email: { type: "string", required: false } },
58
+ async execute(input, ctx) {
59
+ const p = (input ?? {});
60
+ const qs = {};
61
+ if (p.limit)
62
+ qs.limit = p.limit;
63
+ if (p.email)
64
+ qs.email = p.email;
65
+ const data = (await apiRequest(key(ctx), "GET", "/customers", undefined, qs));
66
+ return data.data;
67
+ },
68
+ });
69
+ rl.registerAction("customer.update", {
70
+ description: "Update a customer",
71
+ inputSchema: { customerId: { type: "string", required: true }, name: { type: "string", required: false }, email: { type: "string", required: false }, phone: { type: "string", required: false }, description: { type: "string", required: false } },
72
+ async execute(input, ctx) {
73
+ const { customerId, ...fields } = input;
74
+ return apiRequest(key(ctx), "POST", `/customers/${customerId}`, fields);
75
+ },
76
+ });
77
+ rl.registerAction("customer.delete", {
78
+ description: "Delete a customer",
79
+ inputSchema: { customerId: { type: "string", required: true } },
80
+ async execute(input, ctx) { return apiRequest(key(ctx), "DELETE", `/customers/${input.customerId}`); },
81
+ });
82
+ // ── Charge ──────────────────────────────────────────
83
+ rl.registerAction("charge.create", {
84
+ description: "Create a charge",
85
+ inputSchema: {
86
+ amount: { type: "number", required: true, description: "Amount in smallest currency unit (e.g. cents)" },
87
+ currency: { type: "string", required: true },
88
+ source: { type: "string", required: true, description: "Payment source token or ID" },
89
+ customer: { type: "string", required: false },
90
+ description: { type: "string", required: false },
91
+ },
92
+ async execute(input, ctx) { return apiRequest(key(ctx), "POST", "/charges", input); },
93
+ });
94
+ rl.registerAction("charge.get", {
95
+ description: "Get a charge by ID",
96
+ inputSchema: { chargeId: { type: "string", required: true } },
97
+ async execute(input, ctx) { return apiRequest(key(ctx), "GET", `/charges/${input.chargeId}`); },
98
+ });
99
+ rl.registerAction("charge.list", {
100
+ description: "List charges",
101
+ inputSchema: { limit: { type: "number", required: false } },
102
+ async execute(input, ctx) {
103
+ const qs = {};
104
+ if (input?.limit)
105
+ qs.limit = input.limit;
106
+ const data = (await apiRequest(key(ctx), "GET", "/charges", undefined, qs));
107
+ return data.data;
108
+ },
109
+ });
110
+ rl.registerAction("charge.update", {
111
+ description: "Update a charge",
112
+ inputSchema: { chargeId: { type: "string", required: true }, description: { type: "string", required: false } },
113
+ async execute(input, ctx) {
114
+ const { chargeId, ...fields } = input;
115
+ return apiRequest(key(ctx), "POST", `/charges/${chargeId}`, fields);
116
+ },
117
+ });
118
+ // ── Coupon ──────────────────────────────────────────
119
+ rl.registerAction("coupon.create", {
120
+ description: "Create a coupon",
121
+ inputSchema: {
122
+ duration: { type: "string", required: true, description: "forever, once, or repeating" },
123
+ percentOff: { type: "number", required: false },
124
+ amountOff: { type: "number", required: false, description: "In smallest currency unit" },
125
+ currency: { type: "string", required: false },
126
+ },
127
+ async execute(input, ctx) {
128
+ const p = input;
129
+ const body = { duration: p.duration };
130
+ if (p.percentOff)
131
+ body.percent_off = p.percentOff;
132
+ if (p.amountOff)
133
+ body.amount_off = p.amountOff;
134
+ if (p.currency)
135
+ body.currency = p.currency;
136
+ return apiRequest(key(ctx), "POST", "/coupons", body);
137
+ },
138
+ });
139
+ rl.registerAction("coupon.list", {
140
+ description: "List coupons",
141
+ inputSchema: { limit: { type: "number", required: false } },
142
+ async execute(input, ctx) {
143
+ const qs = {};
144
+ if (input?.limit)
145
+ qs.limit = input.limit;
146
+ const data = (await apiRequest(key(ctx), "GET", "/coupons", undefined, qs));
147
+ return data.data;
148
+ },
149
+ });
150
+ // ── Customer Card ───────────────────────────────────
151
+ rl.registerAction("customerCard.add", {
152
+ description: "Add a card to a customer",
153
+ inputSchema: { customerId: { type: "string", required: true }, token: { type: "string", required: true, description: "Card token from Stripe.js/Elements" } },
154
+ async execute(input, ctx) {
155
+ const p = input;
156
+ return apiRequest(key(ctx), "POST", `/customers/${p.customerId}/sources`, { source: p.token });
157
+ },
158
+ });
159
+ rl.registerAction("customerCard.get", {
160
+ description: "Get a customer's card/source",
161
+ inputSchema: { customerId: { type: "string", required: true }, sourceId: { type: "string", required: true } },
162
+ async execute(input, ctx) {
163
+ const p = input;
164
+ return apiRequest(key(ctx), "GET", `/customers/${p.customerId}/sources/${p.sourceId}`);
165
+ },
166
+ });
167
+ rl.registerAction("customerCard.remove", {
168
+ description: "Remove a card from a customer",
169
+ inputSchema: { customerId: { type: "string", required: true }, cardId: { type: "string", required: true } },
170
+ async execute(input, ctx) {
171
+ const p = input;
172
+ return apiRequest(key(ctx), "DELETE", `/customers/${p.customerId}/sources/${p.cardId}`);
173
+ },
174
+ });
175
+ // ── Source ──────────────────────────────────────────
176
+ rl.registerAction("source.create", {
177
+ description: "Create a source and attach to customer",
178
+ inputSchema: { customerId: { type: "string", required: true }, type: { type: "string", required: true }, amount: { type: "number", required: true }, currency: { type: "string", required: true } },
179
+ async execute(input, ctx) {
180
+ const p = input;
181
+ const source = (await apiRequest(key(ctx), "POST", "/sources", { type: p.type, amount: p.amount, currency: p.currency }));
182
+ await apiRequest(key(ctx), "POST", `/customers/${p.customerId}/sources`, { source: source.id });
183
+ return source;
184
+ },
185
+ });
186
+ rl.registerAction("source.get", {
187
+ description: "Get a source by ID",
188
+ inputSchema: { sourceId: { type: "string", required: true } },
189
+ async execute(input, ctx) { return apiRequest(key(ctx), "GET", `/sources/${input.sourceId}`); },
190
+ });
191
+ rl.registerAction("source.delete", {
192
+ description: "Detach a source from a customer",
193
+ inputSchema: { customerId: { type: "string", required: true }, sourceId: { type: "string", required: true } },
194
+ async execute(input, ctx) {
195
+ const p = input;
196
+ return apiRequest(key(ctx), "DELETE", `/customers/${p.customerId}/sources/${p.sourceId}`);
197
+ },
198
+ });
199
+ // ── Token ───────────────────────────────────────────
200
+ rl.registerAction("token.createCard", {
201
+ description: "Create a card token",
202
+ inputSchema: { number: { type: "string", required: true }, expMonth: { type: "number", required: true }, expYear: { type: "number", required: true }, cvc: { type: "string", required: true } },
203
+ async execute(input, ctx) {
204
+ const p = input;
205
+ return apiRequest(key(ctx), "POST", "/tokens", { card: { number: p.number, exp_month: p.expMonth, exp_year: p.expYear, cvc: p.cvc } });
206
+ },
207
+ });
208
+ // ── Meter Event ─────────────────────────────────────
209
+ rl.registerAction("meterEvent.create", {
210
+ description: "Create a billing meter event",
211
+ inputSchema: { eventName: { type: "string", required: true }, customerId: { type: "string", required: true }, value: { type: "number", required: true }, identifier: { type: "string", required: false }, timestamp: { type: "string", required: false, description: "ISO datetime" } },
212
+ async execute(input, ctx) {
213
+ const p = input;
214
+ const body = { event_name: p.eventName, payload: { stripe_customer_id: p.customerId, value: p.value } };
215
+ if (p.identifier)
216
+ body.identifier = p.identifier;
217
+ if (p.timestamp)
218
+ body.timestamp = Math.floor(new Date(p.timestamp).getTime() / 1000);
219
+ return apiRequest(key(ctx), "POST", "/billing/meter_events", body);
220
+ },
221
+ });
222
+ }
@@ -0,0 +1,121 @@
1
+ function getConn(ctx) {
2
+ const c = ctx.connection.config;
3
+ return { host: c.host.replace(/\/$/, ""), serviceRole: c.serviceRole };
4
+ }
5
+ async function apiRequest(conn, method, endpoint, body, qs, extraHeaders) {
6
+ const url = new URL(`${conn.host}/rest/v1${endpoint}`);
7
+ if (qs) {
8
+ for (const [k, v] of Object.entries(qs)) {
9
+ if (v !== undefined && v !== null)
10
+ url.searchParams.set(k, String(v));
11
+ }
12
+ }
13
+ const headers = {
14
+ apikey: conn.serviceRole,
15
+ Authorization: `Bearer ${conn.serviceRole}`,
16
+ Prefer: "return=representation",
17
+ "Content-Type": "application/json",
18
+ ...extraHeaders,
19
+ };
20
+ const init = { method, headers };
21
+ if (body !== undefined)
22
+ init.body = JSON.stringify(body);
23
+ const res = await fetch(url.toString(), init);
24
+ if (!res.ok)
25
+ throw new Error(`Supabase error ${res.status}: ${await res.text()}`);
26
+ const text = await res.text();
27
+ return text ? JSON.parse(text) : {};
28
+ }
29
+ export default function supabase(rl) {
30
+ rl.setName("supabase");
31
+ rl.setVersion("0.1.0");
32
+ rl.setConnectionSchema({
33
+ host: { type: "string", required: true, description: "Supabase project URL (e.g. https://xxx.supabase.co)", env: "SUPABASE_URL" },
34
+ serviceRole: { type: "string", required: true, description: "Supabase service_role key", env: "SUPABASE_SERVICE_ROLE_KEY" },
35
+ });
36
+ rl.registerAction("row.create", {
37
+ description: "Insert rows into a table",
38
+ inputSchema: {
39
+ table: { type: "string", required: true },
40
+ data: { type: "object", required: true, description: "Row data (or array of rows)" },
41
+ schema: { type: "string", required: false, description: "Database schema (default: public)" },
42
+ },
43
+ async execute(input, ctx) {
44
+ const conn = getConn(ctx);
45
+ const p = input;
46
+ const headers = {};
47
+ if (p.schema && p.schema !== "public")
48
+ headers["Content-Profile"] = p.schema;
49
+ return apiRequest(conn, "POST", `/${p.table}`, p.data, undefined, headers);
50
+ },
51
+ });
52
+ rl.registerAction("row.get", {
53
+ description: "Get rows by filter (PostgREST query params)",
54
+ inputSchema: {
55
+ table: { type: "string", required: true },
56
+ filters: { type: "object", required: true, description: "PostgREST filters, e.g. { id: 'eq.5' }" },
57
+ schema: { type: "string", required: false },
58
+ },
59
+ async execute(input, ctx) {
60
+ const conn = getConn(ctx);
61
+ const p = input;
62
+ const headers = {};
63
+ if (p.schema && p.schema !== "public")
64
+ headers["Accept-Profile"] = p.schema;
65
+ return apiRequest(conn, "GET", `/${p.table}`, undefined, p.filters, headers);
66
+ },
67
+ });
68
+ rl.registerAction("row.list", {
69
+ description: "List rows from a table",
70
+ inputSchema: {
71
+ table: { type: "string", required: true },
72
+ limit: { type: "number", required: false },
73
+ filters: { type: "object", required: false, description: "PostgREST filters" },
74
+ schema: { type: "string", required: false },
75
+ },
76
+ async execute(input, ctx) {
77
+ const conn = getConn(ctx);
78
+ const p = (input ?? {});
79
+ const qs = { ...(p.filters ?? {}) };
80
+ if (p.limit)
81
+ qs.limit = p.limit;
82
+ const headers = {};
83
+ if (p.schema && p.schema !== "public")
84
+ headers["Accept-Profile"] = p.schema;
85
+ return apiRequest(conn, "GET", `/${p.table}`, undefined, qs, headers);
86
+ },
87
+ });
88
+ rl.registerAction("row.update", {
89
+ description: "Update rows matching a filter",
90
+ inputSchema: {
91
+ table: { type: "string", required: true },
92
+ data: { type: "object", required: true, description: "Fields to update" },
93
+ filters: { type: "object", required: true, description: "PostgREST filters to match rows" },
94
+ schema: { type: "string", required: false },
95
+ },
96
+ async execute(input, ctx) {
97
+ const conn = getConn(ctx);
98
+ const p = input;
99
+ const headers = {};
100
+ if (p.schema && p.schema !== "public")
101
+ headers["Content-Profile"] = p.schema;
102
+ return apiRequest(conn, "PATCH", `/${p.table}`, p.data, p.filters, headers);
103
+ },
104
+ });
105
+ rl.registerAction("row.delete", {
106
+ description: "Delete rows matching a filter",
107
+ inputSchema: {
108
+ table: { type: "string", required: true },
109
+ filters: { type: "object", required: true, description: "PostgREST filters to match rows" },
110
+ schema: { type: "string", required: false },
111
+ },
112
+ async execute(input, ctx) {
113
+ const conn = getConn(ctx);
114
+ const p = input;
115
+ const headers = {};
116
+ if (p.schema && p.schema !== "public")
117
+ headers["Content-Profile"] = p.schema;
118
+ return apiRequest(conn, "DELETE", `/${p.table}`, undefined, p.filters, headers);
119
+ },
120
+ });
121
+ }