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.
- package/.pi/extensions/runline-context/index.ts +135 -0
- package/.pi/extensions/runline-context/package.json +17 -0
- package/README.md +273 -0
- package/dist/commands/actions.d.ts +3 -0
- package/dist/commands/actions.js +43 -0
- package/dist/commands/connection.d.ts +11 -0
- package/dist/commands/connection.js +56 -0
- package/dist/commands/exec.d.ts +5 -0
- package/dist/commands/exec.js +46 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +26 -0
- package/dist/commands/plugin.d.ts +10 -0
- package/dist/commands/plugin.js +57 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.js +2 -0
- package/dist/config/loader.d.ts +11 -0
- package/dist/config/loader.js +82 -0
- package/dist/config/types.d.ts +9 -0
- package/dist/config/types.js +5 -0
- package/dist/core/engine.d.ts +21 -0
- package/dist/core/engine.js +280 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +9 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +127 -0
- package/dist/plugin/api.d.ts +32 -0
- package/dist/plugin/api.js +68 -0
- package/dist/plugin/installer.d.ts +27 -0
- package/dist/plugin/installer.js +181 -0
- package/dist/plugin/loader.d.ts +13 -0
- package/dist/plugin/loader.js +164 -0
- package/dist/plugin/registry.d.ts +18 -0
- package/dist/plugin/registry.js +43 -0
- package/dist/plugin/types.d.ts +40 -0
- package/dist/plugin/types.js +1 -0
- package/dist/plugins/actionNetwork/src/index.js +353 -0
- package/dist/plugins/activeCampaign/src/index.js +711 -0
- package/dist/plugins/adalo/src/index.js +131 -0
- package/dist/plugins/affinity/src/index.js +279 -0
- package/dist/plugins/agileCrm/src/index.js +415 -0
- package/dist/plugins/airtable/src/index.js +280 -0
- package/dist/plugins/airtop/src/index.js +527 -0
- package/dist/plugins/apiTemplateIo/src/index.js +86 -0
- package/dist/plugins/asana/src/index.js +413 -0
- package/dist/plugins/autopilot/src/index.js +203 -0
- package/dist/plugins/bambooHr/src/index.js +252 -0
- package/dist/plugins/bannerbear/src/index.js +100 -0
- package/dist/plugins/baserow/src/index.js +180 -0
- package/dist/plugins/beeminder/src/index.js +298 -0
- package/dist/plugins/bitly/src/index.js +107 -0
- package/dist/plugins/bitwarden/src/index.js +383 -0
- package/dist/plugins/box/src/index.js +300 -0
- package/dist/plugins/brandfetch/src/index.js +80 -0
- package/dist/plugins/brevo/src/index.js +305 -0
- package/dist/plugins/bubble/src/index.js +181 -0
- package/dist/plugins/chargebee/src/index.js +126 -0
- package/dist/plugins/circleci/src/index.js +111 -0
- package/dist/plugins/ciscoWebex/src/index.js +245 -0
- package/dist/plugins/clearbit/src/index.js +103 -0
- package/dist/plugins/clickup/src/index.js +1043 -0
- package/dist/plugins/clockify/src/index.js +443 -0
- package/dist/plugins/cloudflare/src/index.js +93 -0
- package/dist/plugins/cockpit/src/index.js +131 -0
- package/dist/plugins/coda/src/index.js +327 -0
- package/dist/plugins/coingecko/src/index.js +244 -0
- package/dist/plugins/contentful/src/index.js +146 -0
- package/dist/plugins/convertkit/src/index.js +270 -0
- package/dist/plugins/copper/src/index.js +140 -0
- package/dist/plugins/cortex/src/index.js +147 -0
- package/dist/plugins/currents/src/index.js +405 -0
- package/dist/plugins/customerIo/src/index.js +184 -0
- package/dist/plugins/databricks/src/index.js +342 -0
- package/dist/plugins/deepl/src/index.js +87 -0
- package/dist/plugins/demio/src/index.js +111 -0
- package/dist/plugins/dhl/src/index.js +40 -0
- package/dist/plugins/discord/src/index.js +275 -0
- package/dist/plugins/discourse/src/index.js +273 -0
- package/dist/plugins/disqus/src/index.js +145 -0
- package/dist/plugins/docker/src/index.js +76 -0
- package/dist/plugins/drift/src/index.js +89 -0
- package/dist/plugins/dropbox/src/index.js +159 -0
- package/dist/plugins/dropcontact/src/index.js +59 -0
- package/dist/plugins/egoi/src/index.js +151 -0
- package/dist/plugins/elasticsearch/src/index.js +157 -0
- package/dist/plugins/emelia/src/index.js +174 -0
- package/dist/plugins/erpnext/src/index.js +121 -0
- package/dist/plugins/facebookGraph/src/index.js +57 -0
- package/dist/plugins/freshdesk/src/index.js +320 -0
- package/dist/plugins/freshservice/src/index.js +146 -0
- package/dist/plugins/freshworksCrm/src/index.js +149 -0
- package/dist/plugins/getresponse/src/index.js +140 -0
- package/dist/plugins/ghost/src/index.js +192 -0
- package/dist/plugins/github/src/index.js +630 -0
- package/dist/plugins/gitlab/src/index.js +358 -0
- package/dist/plugins/gong/src/index.js +126 -0
- package/dist/plugins/gotify/src/index.js +77 -0
- package/dist/plugins/gotowebinar/src/index.js +316 -0
- package/dist/plugins/grafana/src/index.js +250 -0
- package/dist/plugins/graphql/src/index.js +78 -0
- package/dist/plugins/grist/src/index.js +106 -0
- package/dist/plugins/hackernews/src/index.js +89 -0
- package/dist/plugins/halopsa/src/index.js +79 -0
- package/dist/plugins/harvest/src/index.js +163 -0
- package/dist/plugins/helpscout/src/index.js +176 -0
- package/dist/plugins/highlevel/src/index.js +172 -0
- package/dist/plugins/homeAssistant/src/index.js +148 -0
- package/dist/plugins/hubspot/src/index.js +176 -0
- package/dist/plugins/humanticAi/src/index.js +60 -0
- package/dist/plugins/hunter/src/index.js +59 -0
- package/dist/plugins/intercom/src/index.js +156 -0
- package/dist/plugins/iterable/src/index.js +139 -0
- package/dist/plugins/jenkins/src/index.js +132 -0
- package/dist/plugins/jira/src/index.js +229 -0
- package/dist/plugins/keap/src/index.js +502 -0
- package/dist/plugins/kobotoolbox/src/index.js +281 -0
- package/dist/plugins/lemlist/src/index.js +231 -0
- package/dist/plugins/linear/src/index.js +133 -0
- package/dist/plugins/lingvanex/src/index.js +31 -0
- package/dist/plugins/linkedin/src/index.js +80 -0
- package/dist/plugins/lonescale/src/index.js +119 -0
- package/dist/plugins/magento/src/index.js +300 -0
- package/dist/plugins/mailcheck/src/index.js +27 -0
- package/dist/plugins/mailchimp/src/index.js +321 -0
- package/dist/plugins/mailerlite/src/index.js +123 -0
- package/dist/plugins/mailgun/src/index.js +48 -0
- package/dist/plugins/mailjet/src/index.js +155 -0
- package/dist/plugins/mandrill/src/index.js +145 -0
- package/dist/plugins/marketstack/src/index.js +97 -0
- package/dist/plugins/matrix/src/index.js +194 -0
- package/dist/plugins/mattermost/src/index.js +331 -0
- package/dist/plugins/mautic/src/index.js +311 -0
- package/dist/plugins/medium/src/index.js +77 -0
- package/dist/plugins/messagebird/src/index.js +57 -0
- package/dist/plugins/metabase/src/index.js +130 -0
- package/dist/plugins/misp/src/index.js +476 -0
- package/dist/plugins/mocean/src/index.js +67 -0
- package/dist/plugins/monday/src/index.js +231 -0
- package/dist/plugins/monicaCrm/src/index.js +52 -0
- package/dist/plugins/msg91/src/index.js +31 -0
- package/dist/plugins/nasa/src/index.js +146 -0
- package/dist/plugins/netlify/src/index.js +151 -0
- package/dist/plugins/netscalerAdc/src/index.js +131 -0
- package/dist/plugins/nextcloud/src/index.js +263 -0
- package/dist/plugins/nocodb/src/index.js +130 -0
- package/dist/plugins/notion/src/index.js +112 -0
- package/dist/plugins/npm/src/index.js +104 -0
- package/dist/plugins/odoo/src/index.js +157 -0
- package/dist/plugins/okta/src/index.js +141 -0
- package/dist/plugins/oneSimpleApi/src/index.js +155 -0
- package/dist/plugins/onfleet/src/index.js +254 -0
- package/dist/plugins/openThesaurus/src/index.js +32 -0
- package/dist/plugins/openweathermap/src/index.js +60 -0
- package/dist/plugins/oura/src/index.js +62 -0
- package/dist/plugins/paddle/src/index.js +247 -0
- package/dist/plugins/pagerduty/src/index.js +201 -0
- package/dist/plugins/paypal/src/index.js +106 -0
- package/dist/plugins/peekalink/src/index.js +35 -0
- package/dist/plugins/phantombuster/src/index.js +94 -0
- package/dist/plugins/philipsHue/src/index.js +98 -0
- package/dist/plugins/pipedrive/src/index.js +169 -0
- package/dist/plugins/plivo/src/index.js +66 -0
- package/dist/plugins/postbin/src/index.js +93 -0
- package/dist/plugins/posthog/src/index.js +113 -0
- package/dist/plugins/profitwell/src/index.js +50 -0
- package/dist/plugins/pushbullet/src/index.js +102 -0
- package/dist/plugins/pushcut/src/index.js +39 -0
- package/dist/plugins/pushover/src/index.js +65 -0
- package/dist/plugins/quickbase/src/index.js +153 -0
- package/dist/plugins/quickbooks/src/index.js +73 -0
- package/dist/plugins/quickchart/src/index.js +36 -0
- package/dist/plugins/raindrop/src/index.js +209 -0
- package/dist/plugins/reddit/src/index.js +185 -0
- package/dist/plugins/rocketchat/src/index.js +53 -0
- package/dist/plugins/rundeck/src/index.js +62 -0
- package/dist/plugins/salesforce/src/index.js +94 -0
- package/dist/plugins/salesmate/src/index.js +83 -0
- package/dist/plugins/securityScorecard/src/index.js +200 -0
- package/dist/plugins/segment/src/index.js +125 -0
- package/dist/plugins/sendgrid/src/index.js +187 -0
- package/dist/plugins/sendy/src/index.js +138 -0
- package/dist/plugins/sentry/src/index.js +233 -0
- package/dist/plugins/servicenow/src/index.js +108 -0
- package/dist/plugins/shopify/src/index.js +222 -0
- package/dist/plugins/signl4/src/index.js +61 -0
- package/dist/plugins/slack/src/index.js +236 -0
- package/dist/plugins/sms77/src/index.js +63 -0
- package/dist/plugins/splunk/src/index.js +207 -0
- package/dist/plugins/spotify/src/index.js +188 -0
- package/dist/plugins/stackby/src/index.js +82 -0
- package/dist/plugins/storyblok/src/index.js +141 -0
- package/dist/plugins/strapi/src/index.js +152 -0
- package/dist/plugins/strava/src/index.js +137 -0
- package/dist/plugins/stripe/src/index.js +222 -0
- package/dist/plugins/supabase/src/index.js +121 -0
- package/dist/plugins/syncromsp/src/index.js +255 -0
- package/dist/plugins/tapfiliate/src/index.js +125 -0
- package/dist/plugins/telegram/src/index.js +233 -0
- package/dist/plugins/thehive/src/index.js +142 -0
- package/dist/plugins/thehiveProject/src/index.js +194 -0
- package/dist/plugins/todoist/src/index.js +244 -0
- package/dist/plugins/travisci/src/index.js +71 -0
- package/dist/plugins/trello/src/index.js +341 -0
- package/dist/plugins/twake/src/index.js +40 -0
- package/dist/plugins/twilio/src/index.js +75 -0
- package/dist/plugins/twist/src/index.js +90 -0
- package/dist/plugins/twitter/src/index.js +123 -0
- package/dist/plugins/unleashedSoftware/src/index.js +84 -0
- package/dist/plugins/uplead/src/index.js +59 -0
- package/dist/plugins/uproc/src/index.js +34 -0
- package/dist/plugins/uptimerobot/src/index.js +264 -0
- package/dist/plugins/urlscanio/src/index.js +64 -0
- package/dist/plugins/vero/src/index.js +80 -0
- package/dist/plugins/vonage/src/index.js +42 -0
- package/dist/plugins/wekan/src/index.js +91 -0
- package/dist/plugins/woocommerce/src/index.js +92 -0
- package/dist/plugins/wordpress/src/index.js +121 -0
- package/dist/plugins/xero/src/index.js +136 -0
- package/dist/plugins/yourls/src/index.js +56 -0
- package/dist/plugins/zammad/src/index.js +91 -0
- package/dist/plugins/zendesk/src/index.js +137 -0
- package/dist/plugins/zoho/src/index.js +85 -0
- package/dist/plugins/zoom/src/index.js +122 -0
- package/dist/plugins/zulip/src/index.js +170 -0
- package/dist/sdk.d.ts +38 -0
- package/dist/sdk.js +105 -0
- package/dist/utils/cli.d.ts +13 -0
- package/dist/utils/cli.js +32 -0
- package/dist/utils/output.d.ts +4 -0
- package/dist/utils/output.js +13 -0
- package/package.json +57 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
function getConn(ctx) {
|
|
2
|
+
const c = ctx.connection.config;
|
|
3
|
+
return { url: c.url.replace(/\/$/, ""), token: c.token };
|
|
4
|
+
}
|
|
5
|
+
async function api(conn, method, endpoint, body, qs) {
|
|
6
|
+
const url = new URL(`${conn.url}/api/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 init = { method, headers: { Authorization: `Token token=${conn.token}`, "Content-Type": "application/json" } };
|
|
14
|
+
if (body && Object.keys(body).length > 0)
|
|
15
|
+
init.body = JSON.stringify(body);
|
|
16
|
+
const res = await fetch(url.toString(), init);
|
|
17
|
+
if (!res.ok)
|
|
18
|
+
throw new Error(`Zammad error ${res.status}: ${await res.text()}`);
|
|
19
|
+
if (res.status === 204)
|
|
20
|
+
return { success: true };
|
|
21
|
+
return res.json();
|
|
22
|
+
}
|
|
23
|
+
function registerCrud(rl, resource, plural, conn, createSchema) {
|
|
24
|
+
rl.registerAction(`${resource}.create`, { description: `Create a ${resource}`, inputSchema: createSchema,
|
|
25
|
+
async execute(input, ctx) { return api(conn(ctx), "POST", `/${plural}`, input); } });
|
|
26
|
+
rl.registerAction(`${resource}.get`, { description: `Get a ${resource} by ID`, inputSchema: { id: { type: "string", required: true } },
|
|
27
|
+
async execute(input, ctx) { return api(conn(ctx), "GET", `/${plural}/${input.id}`); } });
|
|
28
|
+
rl.registerAction(`${resource}.list`, { description: `List ${plural}`, inputSchema: { limit: { type: "number", required: false } },
|
|
29
|
+
async execute(input, ctx) {
|
|
30
|
+
const p = (input ?? {});
|
|
31
|
+
const qs = { per_page: p.limit ?? 100 };
|
|
32
|
+
return api(conn(ctx), "GET", `/${plural}`, undefined, qs);
|
|
33
|
+
} });
|
|
34
|
+
rl.registerAction(`${resource}.update`, { description: `Update a ${resource}`, inputSchema: { id: { type: "string", required: true }, data: { type: "object", required: true } },
|
|
35
|
+
async execute(input, ctx) { const p = input; return api(conn(ctx), "PUT", `/${plural}/${p.id}`, p.data); } });
|
|
36
|
+
rl.registerAction(`${resource}.delete`, { description: `Delete a ${resource}`, inputSchema: { id: { type: "string", required: true } },
|
|
37
|
+
async execute(input, ctx) { await api(conn(ctx), "DELETE", `/${plural}/${input.id}`); return { success: true }; } });
|
|
38
|
+
}
|
|
39
|
+
export default function zammad(rl) {
|
|
40
|
+
rl.setName("zammad");
|
|
41
|
+
rl.setVersion("0.1.0");
|
|
42
|
+
rl.setConnectionSchema({
|
|
43
|
+
url: { type: "string", required: true, description: "Zammad instance URL", env: "ZAMMAD_URL" },
|
|
44
|
+
token: { type: "string", required: true, description: "Zammad access token", env: "ZAMMAD_TOKEN" },
|
|
45
|
+
});
|
|
46
|
+
registerCrud(rl, "user", "users", getConn, { firstname: { type: "string", required: true }, lastname: { type: "string", required: true }, email: { type: "string", required: false } });
|
|
47
|
+
registerCrud(rl, "organization", "organizations", getConn, { name: { type: "string", required: true } });
|
|
48
|
+
registerCrud(rl, "group", "groups", getConn, { name: { type: "string", required: true } });
|
|
49
|
+
// ── Ticket (special: includes article) ──────────────
|
|
50
|
+
rl.registerAction("ticket.create", { description: "Create a ticket", inputSchema: {
|
|
51
|
+
title: { type: "string", required: true }, group: { type: "string", required: true },
|
|
52
|
+
customer: { type: "string", required: true, description: "Customer email" },
|
|
53
|
+
articleBody: { type: "string", required: true }, articleSubject: { type: "string", required: false },
|
|
54
|
+
articleInternal: { type: "boolean", required: false },
|
|
55
|
+
},
|
|
56
|
+
async execute(input, ctx) {
|
|
57
|
+
const p = input;
|
|
58
|
+
const body = { title: p.title, group: p.group, customer: p.customer, article: { body: p.articleBody, internal: p.articleInternal ?? false } };
|
|
59
|
+
if (p.articleSubject)
|
|
60
|
+
body.article.subject = p.articleSubject;
|
|
61
|
+
return api(getConn(ctx), "POST", "/tickets", body);
|
|
62
|
+
} });
|
|
63
|
+
rl.registerAction("ticket.get", { description: "Get a ticket with articles", inputSchema: { id: { type: "string", required: true } },
|
|
64
|
+
async execute(input, ctx) {
|
|
65
|
+
const c = getConn(ctx);
|
|
66
|
+
const id = input.id;
|
|
67
|
+
const ticket = (await api(c, "GET", `/tickets/${id}`));
|
|
68
|
+
ticket.articles = await api(c, "GET", `/ticket_articles/by_ticket/${id}`);
|
|
69
|
+
return ticket;
|
|
70
|
+
} });
|
|
71
|
+
rl.registerAction("ticket.list", { description: "List tickets", inputSchema: { limit: { type: "number", required: false } },
|
|
72
|
+
async execute(input, ctx) {
|
|
73
|
+
const qs = { per_page: (input ?? {}).limit ?? 100 };
|
|
74
|
+
return api(getConn(ctx), "GET", "/tickets", undefined, qs);
|
|
75
|
+
} });
|
|
76
|
+
rl.registerAction("ticket.update", { description: "Update a ticket", inputSchema: { id: { type: "string", required: true }, data: { type: "object", required: true } },
|
|
77
|
+
async execute(input, ctx) { const p = input; return api(getConn(ctx), "PUT", `/tickets/${p.id}`, p.data); } });
|
|
78
|
+
rl.registerAction("ticket.delete", { description: "Delete a ticket", inputSchema: { id: { type: "string", required: true } },
|
|
79
|
+
async execute(input, ctx) { await api(getConn(ctx), "DELETE", `/tickets/${input.id}`); return { success: true }; } });
|
|
80
|
+
// ── User extras ─────────────────────────────────────
|
|
81
|
+
rl.registerAction("user.getSelf", { description: "Get the current user", inputSchema: {},
|
|
82
|
+
async execute(_input, ctx) { return api(getConn(ctx), "GET", "/users/me"); } });
|
|
83
|
+
rl.registerAction("user.search", { description: "Search users", inputSchema: { query: { type: "string", required: true }, limit: { type: "number", required: false } },
|
|
84
|
+
async execute(input, ctx) {
|
|
85
|
+
const p = input;
|
|
86
|
+
const qs = { query: p.query };
|
|
87
|
+
if (p.limit)
|
|
88
|
+
qs.per_page = p.limit;
|
|
89
|
+
return api(getConn(ctx), "GET", "/users/search", undefined, qs);
|
|
90
|
+
} });
|
|
91
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
function getConn(ctx) {
|
|
2
|
+
const c = ctx.connection.config;
|
|
3
|
+
return { subdomain: c.subdomain, email: c.email, apiToken: c.apiToken };
|
|
4
|
+
}
|
|
5
|
+
async function api(conn, method, endpoint, body, qs) {
|
|
6
|
+
const url = new URL(`https://${conn.subdomain}.zendesk.com/api/v2${endpoint}.json`);
|
|
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 init = { method, headers: { Authorization: `Basic ${btoa(`${conn.email}/token:${conn.apiToken}`)}`, "Content-Type": "application/json" } };
|
|
14
|
+
if (body && Object.keys(body).length > 0)
|
|
15
|
+
init.body = JSON.stringify(body);
|
|
16
|
+
const res = await fetch(url.toString(), init);
|
|
17
|
+
if (!res.ok)
|
|
18
|
+
throw new Error(`Zendesk error ${res.status}: ${await res.text()}`);
|
|
19
|
+
if (res.status === 204)
|
|
20
|
+
return { success: true };
|
|
21
|
+
return res.json();
|
|
22
|
+
}
|
|
23
|
+
export default function zendesk(rl) {
|
|
24
|
+
rl.setName("zendesk");
|
|
25
|
+
rl.setVersion("0.1.0");
|
|
26
|
+
rl.setConnectionSchema({
|
|
27
|
+
subdomain: { type: "string", required: true, description: "Zendesk subdomain", env: "ZENDESK_SUBDOMAIN" },
|
|
28
|
+
email: { type: "string", required: true, description: "Agent email", env: "ZENDESK_EMAIL" },
|
|
29
|
+
apiToken: { type: "string", required: true, description: "Zendesk API token", env: "ZENDESK_API_TOKEN" },
|
|
30
|
+
});
|
|
31
|
+
// ── Ticket ──────────────────────────────────────────
|
|
32
|
+
rl.registerAction("ticket.create", { description: "Create a ticket", inputSchema: { description: { type: "string", required: true }, subject: { type: "string", required: false }, type: { type: "string", required: false }, status: { type: "string", required: false }, priority: { type: "string", required: false }, tags: { type: "object", required: false }, customFields: { type: "object", required: false } },
|
|
33
|
+
async execute(input, ctx) {
|
|
34
|
+
const p = input;
|
|
35
|
+
const ticket = { comment: { body: p.description } };
|
|
36
|
+
if (p.subject)
|
|
37
|
+
ticket.subject = p.subject;
|
|
38
|
+
if (p.type)
|
|
39
|
+
ticket.type = p.type;
|
|
40
|
+
if (p.status)
|
|
41
|
+
ticket.status = p.status;
|
|
42
|
+
if (p.priority)
|
|
43
|
+
ticket.priority = p.priority;
|
|
44
|
+
if (p.tags)
|
|
45
|
+
ticket.tags = p.tags;
|
|
46
|
+
if (p.customFields)
|
|
47
|
+
ticket.custom_fields = p.customFields;
|
|
48
|
+
const data = (await api(getConn(ctx), "POST", "/tickets", { ticket }));
|
|
49
|
+
return data.ticket;
|
|
50
|
+
} });
|
|
51
|
+
rl.registerAction("ticket.get", { description: "Get a ticket", inputSchema: { id: { type: "string", required: true } },
|
|
52
|
+
async execute(input, ctx) { const data = (await api(getConn(ctx), "GET", `/tickets/${input.id}`)); return data.ticket; } });
|
|
53
|
+
rl.registerAction("ticket.list", { description: "Search tickets", inputSchema: { query: { type: "string", required: false, description: "Zendesk search query" }, limit: { type: "number", required: false }, status: { type: "string", required: false } },
|
|
54
|
+
async execute(input, ctx) {
|
|
55
|
+
const p = (input ?? {});
|
|
56
|
+
let q = "type:ticket";
|
|
57
|
+
if (p.query)
|
|
58
|
+
q += ` ${p.query}`;
|
|
59
|
+
if (p.status)
|
|
60
|
+
q += ` status:${p.status}`;
|
|
61
|
+
const qs = { query: q };
|
|
62
|
+
if (p.limit)
|
|
63
|
+
qs.per_page = p.limit;
|
|
64
|
+
const data = (await api(getConn(ctx), "GET", "/search", undefined, qs));
|
|
65
|
+
return data.results;
|
|
66
|
+
} });
|
|
67
|
+
rl.registerAction("ticket.update", { description: "Update a ticket", inputSchema: { id: { type: "string", required: true }, data: { type: "object", required: true, description: "Ticket fields to update" } },
|
|
68
|
+
async execute(input, ctx) {
|
|
69
|
+
const p = input;
|
|
70
|
+
const data = (await api(getConn(ctx), "PUT", `/tickets/${p.id}`, { ticket: p.data }));
|
|
71
|
+
return data.ticket;
|
|
72
|
+
} });
|
|
73
|
+
rl.registerAction("ticket.delete", { description: "Delete a ticket", inputSchema: { id: { type: "string", required: true } },
|
|
74
|
+
async execute(input, ctx) { await api(getConn(ctx), "DELETE", `/tickets/${input.id}`); return { success: true }; } });
|
|
75
|
+
// ── User ────────────────────────────────────────────
|
|
76
|
+
rl.registerAction("user.create", { description: "Create a user", inputSchema: { name: { type: "string", required: true }, email: { type: "string", required: false }, role: { type: "string", required: false } },
|
|
77
|
+
async execute(input, ctx) {
|
|
78
|
+
const data = (await api(getConn(ctx), "POST", "/users", { user: input }));
|
|
79
|
+
return data.user;
|
|
80
|
+
} });
|
|
81
|
+
rl.registerAction("user.get", { description: "Get a user", inputSchema: { id: { type: "string", required: true } },
|
|
82
|
+
async execute(input, ctx) { const data = (await api(getConn(ctx), "GET", `/users/${input.id}`)); return data.user; } });
|
|
83
|
+
rl.registerAction("user.list", { description: "List users", inputSchema: { limit: { type: "number", required: false } },
|
|
84
|
+
async execute(input, ctx) {
|
|
85
|
+
const qs = {};
|
|
86
|
+
if (input?.limit)
|
|
87
|
+
qs.per_page = input.limit;
|
|
88
|
+
const data = (await api(getConn(ctx), "GET", "/users", undefined, qs));
|
|
89
|
+
return data.users;
|
|
90
|
+
} });
|
|
91
|
+
rl.registerAction("user.update", { description: "Update a user", inputSchema: { id: { type: "string", required: true }, data: { type: "object", required: true } },
|
|
92
|
+
async execute(input, ctx) {
|
|
93
|
+
const p = input;
|
|
94
|
+
const data = (await api(getConn(ctx), "PUT", `/users/${p.id}`, { user: p.data }));
|
|
95
|
+
return data.user;
|
|
96
|
+
} });
|
|
97
|
+
rl.registerAction("user.delete", { description: "Delete a user", inputSchema: { id: { type: "string", required: true } },
|
|
98
|
+
async execute(input, ctx) { const data = (await api(getConn(ctx), "DELETE", `/users/${input.id}`)); return data.user; } });
|
|
99
|
+
rl.registerAction("user.search", { description: "Search users", inputSchema: { query: { type: "string", required: true }, limit: { type: "number", required: false } },
|
|
100
|
+
async execute(input, ctx) {
|
|
101
|
+
const p = input;
|
|
102
|
+
const qs = { query: p.query };
|
|
103
|
+
if (p.limit)
|
|
104
|
+
qs.per_page = p.limit;
|
|
105
|
+
const data = (await api(getConn(ctx), "GET", "/users/search", undefined, qs));
|
|
106
|
+
return data.users;
|
|
107
|
+
} });
|
|
108
|
+
// ── Organization ────────────────────────────────────
|
|
109
|
+
rl.registerAction("organization.create", { description: "Create an organization", inputSchema: { name: { type: "string", required: true } },
|
|
110
|
+
async execute(input, ctx) {
|
|
111
|
+
const data = (await api(getConn(ctx), "POST", "/organizations", { organization: input }));
|
|
112
|
+
return data.organization;
|
|
113
|
+
} });
|
|
114
|
+
rl.registerAction("organization.get", { description: "Get an organization", inputSchema: { id: { type: "string", required: true } },
|
|
115
|
+
async execute(input, ctx) { const data = (await api(getConn(ctx), "GET", `/organizations/${input.id}`)); return data.organization; } });
|
|
116
|
+
rl.registerAction("organization.list", { description: "List organizations", inputSchema: { limit: { type: "number", required: false } },
|
|
117
|
+
async execute(input, ctx) {
|
|
118
|
+
const qs = {};
|
|
119
|
+
if (input?.limit)
|
|
120
|
+
qs.per_page = input.limit;
|
|
121
|
+
const data = (await api(getConn(ctx), "GET", "/organizations", undefined, qs));
|
|
122
|
+
return data.organizations;
|
|
123
|
+
} });
|
|
124
|
+
rl.registerAction("organization.update", { description: "Update an organization", inputSchema: { id: { type: "string", required: true }, data: { type: "object", required: true } },
|
|
125
|
+
async execute(input, ctx) {
|
|
126
|
+
const p = input;
|
|
127
|
+
const data = (await api(getConn(ctx), "PUT", `/organizations/${p.id}`, { organization: p.data }));
|
|
128
|
+
return data.organization;
|
|
129
|
+
} });
|
|
130
|
+
rl.registerAction("organization.delete", { description: "Delete an organization", inputSchema: { id: { type: "string", required: true } },
|
|
131
|
+
async execute(input, ctx) { await api(getConn(ctx), "DELETE", `/organizations/${input.id}`); return { success: true }; } });
|
|
132
|
+
// ── Ticket Field ────────────────────────────────────
|
|
133
|
+
rl.registerAction("ticketField.get", { description: "Get a ticket field", inputSchema: { id: { type: "string", required: true } },
|
|
134
|
+
async execute(input, ctx) { const data = (await api(getConn(ctx), "GET", `/ticket_fields/${input.id}`)); return data.ticket_field; } });
|
|
135
|
+
rl.registerAction("ticketField.list", { description: "List ticket fields", inputSchema: {},
|
|
136
|
+
async execute(_input, ctx) { const data = (await api(getConn(ctx), "GET", "/ticket_fields")); return data.ticket_fields; } });
|
|
137
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
function getConn(ctx) {
|
|
2
|
+
const c = ctx.connection.config;
|
|
3
|
+
return { accessToken: c.accessToken, apiDomain: (c.apiDomain || "https://www.zohoapis.com").replace(/\/$/, "") };
|
|
4
|
+
}
|
|
5
|
+
async function api(conn, method, endpoint, body, qs) {
|
|
6
|
+
const url = new URL(`${conn.apiDomain}/crm/v2${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 init = { method, headers: { Authorization: `Zoho-oauthtoken ${conn.accessToken}`, "Content-Type": "application/json" } };
|
|
14
|
+
if (body && Object.keys(body).length > 0)
|
|
15
|
+
init.body = JSON.stringify({ data: [body] });
|
|
16
|
+
const res = await fetch(url.toString(), init);
|
|
17
|
+
if (!res.ok)
|
|
18
|
+
throw new Error(`Zoho CRM error ${res.status}: ${await res.text()}`);
|
|
19
|
+
if (res.status === 204)
|
|
20
|
+
return { success: true };
|
|
21
|
+
return res.json();
|
|
22
|
+
}
|
|
23
|
+
const MODULES = {
|
|
24
|
+
account: "Accounts", contact: "Contacts", deal: "Deals", invoice: "Invoices",
|
|
25
|
+
lead: "Leads", product: "Products", purchaseOrder: "Purchase_Orders",
|
|
26
|
+
salesOrder: "Sales_Orders", vendor: "Vendors", quote: "Quotes",
|
|
27
|
+
};
|
|
28
|
+
function registerCrmResource(rl, resource, conn) {
|
|
29
|
+
const mod = MODULES[resource];
|
|
30
|
+
rl.registerAction(`${resource}.create`, { description: `Create a ${resource}`, inputSchema: { data: { type: "object", required: true, description: "Record fields" } },
|
|
31
|
+
async execute(input, ctx) {
|
|
32
|
+
const data = (await api(conn(ctx), "POST", `/${mod}`, input.data));
|
|
33
|
+
return data.data;
|
|
34
|
+
} });
|
|
35
|
+
rl.registerAction(`${resource}.get`, { description: `Get a ${resource} by ID`, inputSchema: { id: { type: "string", required: true } },
|
|
36
|
+
async execute(input, ctx) {
|
|
37
|
+
const data = (await api(conn(ctx), "GET", `/${mod}/${input.id}`));
|
|
38
|
+
return data.data;
|
|
39
|
+
} });
|
|
40
|
+
rl.registerAction(`${resource}.list`, { description: `List ${mod}`, inputSchema: { limit: { type: "number", required: false }, fields: { type: "string", required: false, description: "Comma-separated field names" } },
|
|
41
|
+
async execute(input, ctx) {
|
|
42
|
+
const p = (input ?? {});
|
|
43
|
+
const qs = {};
|
|
44
|
+
if (p.limit)
|
|
45
|
+
qs.per_page = p.limit;
|
|
46
|
+
if (p.fields)
|
|
47
|
+
qs.fields = p.fields;
|
|
48
|
+
const data = (await api(conn(ctx), "GET", `/${mod}`, undefined, qs));
|
|
49
|
+
return data.data ?? [];
|
|
50
|
+
} });
|
|
51
|
+
rl.registerAction(`${resource}.update`, { description: `Update a ${resource}`, inputSchema: { id: { type: "string", required: true }, data: { type: "object", required: true } },
|
|
52
|
+
async execute(input, ctx) {
|
|
53
|
+
const p = input;
|
|
54
|
+
const body = { ...p.data, id: p.id };
|
|
55
|
+
const data = (await api(conn(ctx), "PUT", `/${mod}`, body));
|
|
56
|
+
return data.data;
|
|
57
|
+
} });
|
|
58
|
+
rl.registerAction(`${resource}.delete`, { description: `Delete a ${resource}`, inputSchema: { id: { type: "string", required: true } },
|
|
59
|
+
async execute(input, ctx) {
|
|
60
|
+
const data = (await api(conn(ctx), "DELETE", `/${mod}`, undefined, { ids: input.id }));
|
|
61
|
+
return data.data;
|
|
62
|
+
} });
|
|
63
|
+
rl.registerAction(`${resource}.upsert`, { description: `Upsert a ${resource}`, inputSchema: { data: { type: "object", required: true }, duplicateCheckFields: { type: "string", required: false, description: "Comma-separated field names for duplicate check" } },
|
|
64
|
+
async execute(input, ctx) {
|
|
65
|
+
const p = input;
|
|
66
|
+
const body = p.data;
|
|
67
|
+
const qs = {};
|
|
68
|
+
if (p.duplicateCheckFields) {
|
|
69
|
+
body.duplicate_check_fields = p.duplicateCheckFields.split(",").map(f => f.trim());
|
|
70
|
+
}
|
|
71
|
+
const data = (await api(conn(ctx), "POST", `/${mod}/upsert`, body));
|
|
72
|
+
return data.data;
|
|
73
|
+
} });
|
|
74
|
+
}
|
|
75
|
+
export default function zoho(rl) {
|
|
76
|
+
rl.setName("zoho");
|
|
77
|
+
rl.setVersion("0.1.0");
|
|
78
|
+
rl.setConnectionSchema({
|
|
79
|
+
accessToken: { type: "string", required: true, description: "Zoho OAuth2 access token", env: "ZOHO_ACCESS_TOKEN" },
|
|
80
|
+
apiDomain: { type: "string", required: false, description: "API domain (default: https://www.zohoapis.com)", env: "ZOHO_API_DOMAIN" },
|
|
81
|
+
});
|
|
82
|
+
for (const resource of Object.keys(MODULES)) {
|
|
83
|
+
registerCrmResource(rl, resource, getConn);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
const BASE = "https://api.zoom.us/v2";
|
|
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}`, "Content-Type": "application/json" } };
|
|
11
|
+
if (body && Object.keys(body).length > 0)
|
|
12
|
+
init.body = JSON.stringify(body);
|
|
13
|
+
const res = await fetch(url.toString(), init);
|
|
14
|
+
if (res.status === 204)
|
|
15
|
+
return { success: true };
|
|
16
|
+
if (!res.ok)
|
|
17
|
+
throw new Error(`Zoom error ${res.status}: ${await res.text()}`);
|
|
18
|
+
const text = await res.text();
|
|
19
|
+
return text ? JSON.parse(text) : { success: true };
|
|
20
|
+
}
|
|
21
|
+
export default function zoom(rl) {
|
|
22
|
+
rl.setName("zoom");
|
|
23
|
+
rl.setVersion("0.1.0");
|
|
24
|
+
rl.setConnectionSchema({
|
|
25
|
+
accessToken: { type: "string", required: true, description: "Zoom access token (JWT or OAuth2)", env: "ZOOM_ACCESS_TOKEN" },
|
|
26
|
+
});
|
|
27
|
+
const key = (ctx) => ctx.connection.config.accessToken;
|
|
28
|
+
rl.registerAction("meeting.create", {
|
|
29
|
+
description: "Create a Zoom meeting",
|
|
30
|
+
inputSchema: {
|
|
31
|
+
topic: { type: "string", required: true },
|
|
32
|
+
type: { type: "number", required: false, description: "1=Instant, 2=Scheduled, 3=Recurring no fixed, 8=Recurring fixed" },
|
|
33
|
+
startTime: { type: "string", required: false, description: "ISO 8601 datetime" },
|
|
34
|
+
duration: { type: "number", required: false, description: "Duration in minutes" },
|
|
35
|
+
timezone: { type: "string", required: false },
|
|
36
|
+
password: { type: "string", required: false },
|
|
37
|
+
agenda: { type: "string", required: false },
|
|
38
|
+
settings: { type: "object", required: false, description: "Meeting settings object" },
|
|
39
|
+
},
|
|
40
|
+
async execute(input, ctx) {
|
|
41
|
+
const p = input;
|
|
42
|
+
const body = { topic: p.topic };
|
|
43
|
+
if (p.type)
|
|
44
|
+
body.type = p.type;
|
|
45
|
+
if (p.startTime)
|
|
46
|
+
body.start_time = p.startTime;
|
|
47
|
+
if (p.duration)
|
|
48
|
+
body.duration = p.duration;
|
|
49
|
+
if (p.timezone)
|
|
50
|
+
body.timezone = p.timezone;
|
|
51
|
+
if (p.password)
|
|
52
|
+
body.password = p.password;
|
|
53
|
+
if (p.agenda)
|
|
54
|
+
body.agenda = p.agenda;
|
|
55
|
+
if (p.settings)
|
|
56
|
+
body.settings = p.settings;
|
|
57
|
+
return apiRequest(key(ctx), "POST", "/users/me/meetings", body);
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
rl.registerAction("meeting.get", {
|
|
61
|
+
description: "Get a meeting by ID",
|
|
62
|
+
inputSchema: { meetingId: { type: "string", required: true } },
|
|
63
|
+
async execute(input, ctx) {
|
|
64
|
+
return apiRequest(key(ctx), "GET", `/meetings/${input.meetingId}`);
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
rl.registerAction("meeting.list", {
|
|
68
|
+
description: "List meetings for the authenticated user",
|
|
69
|
+
inputSchema: { limit: { type: "number", required: false }, type: { type: "string", required: false, description: "scheduled, live, upcoming" } },
|
|
70
|
+
async execute(input, ctx) {
|
|
71
|
+
const p = (input ?? {});
|
|
72
|
+
const qs = {};
|
|
73
|
+
if (p.limit)
|
|
74
|
+
qs.page_size = p.limit;
|
|
75
|
+
if (p.type)
|
|
76
|
+
qs.type = p.type;
|
|
77
|
+
const data = (await apiRequest(key(ctx), "GET", "/users/me/meetings", undefined, qs));
|
|
78
|
+
return data.meetings;
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
rl.registerAction("meeting.update", {
|
|
82
|
+
description: "Update a meeting",
|
|
83
|
+
inputSchema: {
|
|
84
|
+
meetingId: { type: "string", required: true },
|
|
85
|
+
topic: { type: "string", required: false },
|
|
86
|
+
startTime: { type: "string", required: false },
|
|
87
|
+
duration: { type: "number", required: false },
|
|
88
|
+
timezone: { type: "string", required: false },
|
|
89
|
+
password: { type: "string", required: false },
|
|
90
|
+
agenda: { type: "string", required: false },
|
|
91
|
+
settings: { type: "object", required: false },
|
|
92
|
+
},
|
|
93
|
+
async execute(input, ctx) {
|
|
94
|
+
const { meetingId, ...fields } = input;
|
|
95
|
+
const body = {};
|
|
96
|
+
if (fields.topic)
|
|
97
|
+
body.topic = fields.topic;
|
|
98
|
+
if (fields.startTime)
|
|
99
|
+
body.start_time = fields.startTime;
|
|
100
|
+
if (fields.duration)
|
|
101
|
+
body.duration = fields.duration;
|
|
102
|
+
if (fields.timezone)
|
|
103
|
+
body.timezone = fields.timezone;
|
|
104
|
+
if (fields.password)
|
|
105
|
+
body.password = fields.password;
|
|
106
|
+
if (fields.agenda)
|
|
107
|
+
body.agenda = fields.agenda;
|
|
108
|
+
if (fields.settings)
|
|
109
|
+
body.settings = fields.settings;
|
|
110
|
+
await apiRequest(key(ctx), "PATCH", `/meetings/${meetingId}`, body);
|
|
111
|
+
return { success: true };
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
rl.registerAction("meeting.delete", {
|
|
115
|
+
description: "Delete a meeting",
|
|
116
|
+
inputSchema: { meetingId: { type: "string", required: true } },
|
|
117
|
+
async execute(input, ctx) {
|
|
118
|
+
await apiRequest(key(ctx), "DELETE", `/meetings/${input.meetingId}`);
|
|
119
|
+
return { success: true };
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
function getConn(ctx) {
|
|
2
|
+
const c = ctx.connection.config;
|
|
3
|
+
return { url: c.url.replace(/\/$/, ""), email: c.email, apiKey: c.apiKey };
|
|
4
|
+
}
|
|
5
|
+
async function apiRequest(conn, method, endpoint, body) {
|
|
6
|
+
const url = `${conn.url}/api/v1${endpoint}`;
|
|
7
|
+
const init = {
|
|
8
|
+
method,
|
|
9
|
+
headers: {
|
|
10
|
+
Authorization: `Basic ${btoa(`${conn.email}:${conn.apiKey}`)}`,
|
|
11
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
if (body && Object.keys(body).length > 0) {
|
|
15
|
+
const form = new URLSearchParams();
|
|
16
|
+
for (const [k, v] of Object.entries(body)) {
|
|
17
|
+
if (v !== undefined && v !== null)
|
|
18
|
+
form.set(k, typeof v === "object" ? JSON.stringify(v) : String(v));
|
|
19
|
+
}
|
|
20
|
+
init.body = form;
|
|
21
|
+
}
|
|
22
|
+
const res = await fetch(url, init);
|
|
23
|
+
if (!res.ok)
|
|
24
|
+
throw new Error(`Zulip error ${res.status}: ${await res.text()}`);
|
|
25
|
+
return res.json();
|
|
26
|
+
}
|
|
27
|
+
export default function zulip(rl) {
|
|
28
|
+
rl.setName("zulip");
|
|
29
|
+
rl.setVersion("0.1.0");
|
|
30
|
+
rl.setConnectionSchema({
|
|
31
|
+
url: { type: "string", required: true, description: "Zulip server URL", env: "ZULIP_URL" },
|
|
32
|
+
email: { type: "string", required: true, description: "Bot email", env: "ZULIP_EMAIL" },
|
|
33
|
+
apiKey: { type: "string", required: true, description: "Bot API key", env: "ZULIP_API_KEY" },
|
|
34
|
+
});
|
|
35
|
+
// ── Message ─────────────────────────────────────────
|
|
36
|
+
rl.registerAction("message.sendPrivate", {
|
|
37
|
+
description: "Send a private/direct message",
|
|
38
|
+
inputSchema: { to: { type: "string", required: true, description: "Comma-separated emails" }, content: { type: "string", required: true } },
|
|
39
|
+
async execute(input, ctx) {
|
|
40
|
+
const p = input;
|
|
41
|
+
return apiRequest(getConn(ctx), "POST", "/messages", { type: "private", to: p.to, content: p.content });
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
rl.registerAction("message.sendStream", {
|
|
45
|
+
description: "Send a message to a stream",
|
|
46
|
+
inputSchema: { stream: { type: "string", required: true, description: "Stream name or ID" }, topic: { type: "string", required: true }, content: { type: "string", required: true } },
|
|
47
|
+
async execute(input, ctx) {
|
|
48
|
+
const p = input;
|
|
49
|
+
return apiRequest(getConn(ctx), "POST", "/messages", { type: "stream", to: p.stream, topic: p.topic, content: p.content });
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
rl.registerAction("message.get", {
|
|
53
|
+
description: "Get a message by ID",
|
|
54
|
+
inputSchema: { messageId: { type: "string", required: true } },
|
|
55
|
+
async execute(input, ctx) { return apiRequest(getConn(ctx), "GET", `/messages/${input.messageId}`); },
|
|
56
|
+
});
|
|
57
|
+
rl.registerAction("message.update", {
|
|
58
|
+
description: "Update a message",
|
|
59
|
+
inputSchema: { messageId: { type: "string", required: true }, content: { type: "string", required: false }, topic: { type: "string", required: false } },
|
|
60
|
+
async execute(input, ctx) {
|
|
61
|
+
const { messageId, ...fields } = input;
|
|
62
|
+
return apiRequest(getConn(ctx), "PATCH", `/messages/${messageId}`, fields);
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
rl.registerAction("message.delete", {
|
|
66
|
+
description: "Delete a message",
|
|
67
|
+
inputSchema: { messageId: { type: "string", required: true } },
|
|
68
|
+
async execute(input, ctx) { return apiRequest(getConn(ctx), "DELETE", `/messages/${input.messageId}`); },
|
|
69
|
+
});
|
|
70
|
+
// ── Stream ──────────────────────────────────────────
|
|
71
|
+
rl.registerAction("stream.list", {
|
|
72
|
+
description: "List all streams",
|
|
73
|
+
inputSchema: { includePublic: { type: "boolean", required: false }, includeSubscribed: { type: "boolean", required: false } },
|
|
74
|
+
async execute(input, ctx) {
|
|
75
|
+
const p = (input ?? {});
|
|
76
|
+
const body = {};
|
|
77
|
+
if (p.includePublic !== undefined)
|
|
78
|
+
body.include_public = p.includePublic;
|
|
79
|
+
if (p.includeSubscribed !== undefined)
|
|
80
|
+
body.include_subscribed = p.includeSubscribed;
|
|
81
|
+
const data = (await apiRequest(getConn(ctx), "GET", "/streams", body));
|
|
82
|
+
return data.streams;
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
rl.registerAction("stream.listSubscribed", {
|
|
86
|
+
description: "List subscribed streams",
|
|
87
|
+
inputSchema: {},
|
|
88
|
+
async execute(_input, ctx) {
|
|
89
|
+
const data = (await apiRequest(getConn(ctx), "GET", "/users/me/subscriptions"));
|
|
90
|
+
return data.subscriptions;
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
rl.registerAction("stream.create", {
|
|
94
|
+
description: "Subscribe to / create a stream",
|
|
95
|
+
inputSchema: {
|
|
96
|
+
name: { type: "string", required: true },
|
|
97
|
+
description: { type: "string", required: false },
|
|
98
|
+
inviteOnly: { type: "boolean", required: false },
|
|
99
|
+
},
|
|
100
|
+
async execute(input, ctx) {
|
|
101
|
+
const p = input;
|
|
102
|
+
const body = {
|
|
103
|
+
subscriptions: JSON.stringify([{ name: p.name, description: p.description || "" }]),
|
|
104
|
+
};
|
|
105
|
+
if (p.inviteOnly !== undefined)
|
|
106
|
+
body.invite_only = p.inviteOnly;
|
|
107
|
+
return apiRequest(getConn(ctx), "POST", "/users/me/subscriptions", body);
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
rl.registerAction("stream.update", {
|
|
111
|
+
description: "Update a stream",
|
|
112
|
+
inputSchema: { streamId: { type: "string", required: true }, description: { type: "string", required: false }, newName: { type: "string", required: false }, isPrivate: { type: "boolean", required: false } },
|
|
113
|
+
async execute(input, ctx) {
|
|
114
|
+
const { streamId, ...fields } = input;
|
|
115
|
+
const body = {};
|
|
116
|
+
if (fields.description)
|
|
117
|
+
body.description = JSON.stringify(fields.description);
|
|
118
|
+
if (fields.newName)
|
|
119
|
+
body.new_name = JSON.stringify(fields.newName);
|
|
120
|
+
if (fields.isPrivate !== undefined)
|
|
121
|
+
body.is_private = fields.isPrivate;
|
|
122
|
+
return apiRequest(getConn(ctx), "PATCH", `/streams/${streamId}`, body);
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
rl.registerAction("stream.delete", {
|
|
126
|
+
description: "Delete a stream",
|
|
127
|
+
inputSchema: { streamId: { type: "string", required: true } },
|
|
128
|
+
async execute(input, ctx) { return apiRequest(getConn(ctx), "DELETE", `/streams/${input.streamId}`); },
|
|
129
|
+
});
|
|
130
|
+
// ── User ────────────────────────────────────────────
|
|
131
|
+
rl.registerAction("user.get", {
|
|
132
|
+
description: "Get a user by ID",
|
|
133
|
+
inputSchema: { userId: { type: "string", required: true } },
|
|
134
|
+
async execute(input, ctx) { return apiRequest(getConn(ctx), "GET", `/users/${input.userId}`); },
|
|
135
|
+
});
|
|
136
|
+
rl.registerAction("user.list", {
|
|
137
|
+
description: "List all users",
|
|
138
|
+
inputSchema: {},
|
|
139
|
+
async execute(_input, ctx) {
|
|
140
|
+
const data = (await apiRequest(getConn(ctx), "GET", "/users"));
|
|
141
|
+
return data.members;
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
rl.registerAction("user.create", {
|
|
145
|
+
description: "Create a user",
|
|
146
|
+
inputSchema: { email: { type: "string", required: true }, password: { type: "string", required: true }, fullName: { type: "string", required: true }, shortName: { type: "string", required: true } },
|
|
147
|
+
async execute(input, ctx) {
|
|
148
|
+
const p = input;
|
|
149
|
+
return apiRequest(getConn(ctx), "POST", "/users", { email: p.email, password: p.password, full_name: p.fullName, short_name: p.shortName });
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
rl.registerAction("user.update", {
|
|
153
|
+
description: "Update a user",
|
|
154
|
+
inputSchema: { userId: { type: "string", required: true }, fullName: { type: "string", required: false }, role: { type: "number", required: false } },
|
|
155
|
+
async execute(input, ctx) {
|
|
156
|
+
const { userId, ...fields } = input;
|
|
157
|
+
const body = {};
|
|
158
|
+
if (fields.fullName)
|
|
159
|
+
body.full_name = JSON.stringify(fields.fullName);
|
|
160
|
+
if (fields.role !== undefined)
|
|
161
|
+
body.role = fields.role;
|
|
162
|
+
return apiRequest(getConn(ctx), "PATCH", `/users/${userId}`, body);
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
rl.registerAction("user.deactivate", {
|
|
166
|
+
description: "Deactivate a user",
|
|
167
|
+
inputSchema: { userId: { type: "string", required: true } },
|
|
168
|
+
async execute(input, ctx) { return apiRequest(getConn(ctx), "DELETE", `/users/${input.userId}`); },
|
|
169
|
+
});
|
|
170
|
+
}
|
package/dist/sdk.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type ExecuteResult } from "./core/engine.js";
|
|
2
|
+
import type { PluginFunction } from "./plugin/api.js";
|
|
3
|
+
import type { ConnectionConfig, InputSchema, PluginDef } from "./plugin/types.js";
|
|
4
|
+
export interface RunlineOptions {
|
|
5
|
+
plugins?: Array<PluginDef | PluginFunction>;
|
|
6
|
+
connections?: ConnectionConfig[];
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
memoryLimitBytes?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class Runline {
|
|
11
|
+
private _registry;
|
|
12
|
+
private _config;
|
|
13
|
+
private constructor();
|
|
14
|
+
static create(options?: RunlineOptions): Runline;
|
|
15
|
+
/** Execute JavaScript code in the sandbox. */
|
|
16
|
+
execute(code: string): Promise<ExecuteResult>;
|
|
17
|
+
/** Register an additional plugin after creation. */
|
|
18
|
+
addPlugin(pluginOrFn: PluginDef | PluginFunction, connections?: ConnectionConfig[]): void;
|
|
19
|
+
/** List all available actions across all plugins. */
|
|
20
|
+
actions(): Array<{
|
|
21
|
+
plugin: string;
|
|
22
|
+
action: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
inputSchema?: InputSchema;
|
|
25
|
+
}>;
|
|
26
|
+
/** List registered plugins. */
|
|
27
|
+
plugins(): Array<{
|
|
28
|
+
name: string;
|
|
29
|
+
version: string;
|
|
30
|
+
actions: string[];
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* Load runline from a project directory.
|
|
34
|
+
* Discovers .runline/ config and installed plugins, just like the CLI.
|
|
35
|
+
* Fully self-contained — does not mutate global state.
|
|
36
|
+
*/
|
|
37
|
+
static fromProject(cwd?: string): Promise<Runline | null>;
|
|
38
|
+
}
|