calabasas 0.22.0 → 0.23.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/dist/index.js +162 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7834,6 +7834,164 @@ Run ${pc3.cyan("`calabasas init`")} first.`);
|
|
|
7834
7834
|
await interactiveConfig(currentConfig, configPath);
|
|
7835
7835
|
}
|
|
7836
7836
|
|
|
7837
|
+
// src/commands/webhook.ts
|
|
7838
|
+
import pc4 from "picocolors";
|
|
7839
|
+
function resolveAuthOrExit() {
|
|
7840
|
+
const resolved = resolvePlatformApiKey({});
|
|
7841
|
+
if (!resolved) {
|
|
7842
|
+
console.error(pc4.red("Error:") + ` no Calabasas credentials found.
|
|
7843
|
+
` + " Run `calabasas login` (user key) or set CALABASAS_PLATFORM_API_KEY in .env.local.");
|
|
7844
|
+
process.exit(1);
|
|
7845
|
+
}
|
|
7846
|
+
return resolved.key;
|
|
7847
|
+
}
|
|
7848
|
+
function parseDuration(input) {
|
|
7849
|
+
const match = /^(\d+)(s|m|h|d)$/.exec(input.trim());
|
|
7850
|
+
if (!match)
|
|
7851
|
+
return null;
|
|
7852
|
+
const value = Number(match[1]);
|
|
7853
|
+
const unit = match[2];
|
|
7854
|
+
const multipliers = {
|
|
7855
|
+
s: 1000,
|
|
7856
|
+
m: 60000,
|
|
7857
|
+
h: 3600000,
|
|
7858
|
+
d: 86400000
|
|
7859
|
+
};
|
|
7860
|
+
return value * multipliers[unit];
|
|
7861
|
+
}
|
|
7862
|
+
function normalizeCreateInput(options, now = Date.now()) {
|
|
7863
|
+
if (!options.bot) {
|
|
7864
|
+
return { ok: false, error: "--bot <botId> is required" };
|
|
7865
|
+
}
|
|
7866
|
+
if (options.action !== "sendDM" && options.action !== "sendChannelMessage") {
|
|
7867
|
+
return {
|
|
7868
|
+
ok: false,
|
|
7869
|
+
error: `invalid --action: ${options.action ?? "(missing)"}. Must be one of: sendDM, sendChannelMessage`
|
|
7870
|
+
};
|
|
7871
|
+
}
|
|
7872
|
+
let params;
|
|
7873
|
+
if (options.action === "sendDM") {
|
|
7874
|
+
if (!options.userId) {
|
|
7875
|
+
return { ok: false, error: "--user-id <discordUserId> is required for sendDM" };
|
|
7876
|
+
}
|
|
7877
|
+
params = { userId: options.userId };
|
|
7878
|
+
} else {
|
|
7879
|
+
if (!options.channelId) {
|
|
7880
|
+
return {
|
|
7881
|
+
ok: false,
|
|
7882
|
+
error: "--channel-id <discordChannelId> is required for sendChannelMessage"
|
|
7883
|
+
};
|
|
7884
|
+
}
|
|
7885
|
+
params = { channelId: options.channelId };
|
|
7886
|
+
}
|
|
7887
|
+
let maxUses;
|
|
7888
|
+
if (options.maxUses !== undefined) {
|
|
7889
|
+
const parsed = Number(options.maxUses);
|
|
7890
|
+
if (!Number.isFinite(parsed) || parsed <= 0 || !Number.isInteger(parsed)) {
|
|
7891
|
+
return {
|
|
7892
|
+
ok: false,
|
|
7893
|
+
error: `invalid --max-uses: ${options.maxUses}. Must be a positive integer.`
|
|
7894
|
+
};
|
|
7895
|
+
}
|
|
7896
|
+
maxUses = parsed;
|
|
7897
|
+
}
|
|
7898
|
+
let expiresAt;
|
|
7899
|
+
if (options.expires !== undefined) {
|
|
7900
|
+
const ms = parseDuration(options.expires);
|
|
7901
|
+
if (ms === null) {
|
|
7902
|
+
return {
|
|
7903
|
+
ok: false,
|
|
7904
|
+
error: `invalid --expires: ${options.expires}. Format: <number><unit> where unit is s|m|h|d (e.g. 30m, 24h, 7d).`
|
|
7905
|
+
};
|
|
7906
|
+
}
|
|
7907
|
+
expiresAt = now + ms;
|
|
7908
|
+
}
|
|
7909
|
+
return {
|
|
7910
|
+
ok: true,
|
|
7911
|
+
payload: {
|
|
7912
|
+
botId: options.bot,
|
|
7913
|
+
action: options.action,
|
|
7914
|
+
params,
|
|
7915
|
+
label: options.label,
|
|
7916
|
+
maxUses,
|
|
7917
|
+
expiresAt,
|
|
7918
|
+
platformId: options.platformId
|
|
7919
|
+
}
|
|
7920
|
+
};
|
|
7921
|
+
}
|
|
7922
|
+
async function webhookCreate(options) {
|
|
7923
|
+
const apiKey = resolveAuthOrExit();
|
|
7924
|
+
const result = normalizeCreateInput(options);
|
|
7925
|
+
if (!result.ok) {
|
|
7926
|
+
console.error(pc4.red("Error:") + " " + result.error);
|
|
7927
|
+
process.exit(1);
|
|
7928
|
+
}
|
|
7929
|
+
const { payload } = result;
|
|
7930
|
+
const { ok, data, status } = await platformApiRequest("POST", "/api/cli/webhooks", apiKey, payload);
|
|
7931
|
+
if (!ok) {
|
|
7932
|
+
const errMsg = data?.error ?? `HTTP ${status}`;
|
|
7933
|
+
console.error(pc4.red("Error:") + " " + errMsg);
|
|
7934
|
+
process.exit(1);
|
|
7935
|
+
}
|
|
7936
|
+
const created = data;
|
|
7937
|
+
console.log(pc4.green("Webhook created."));
|
|
7938
|
+
console.log("");
|
|
7939
|
+
console.log(`URL: ${pc4.cyan(created.url)}`);
|
|
7940
|
+
console.log(`token: ${created.token}`);
|
|
7941
|
+
console.log(`webhookId: ${created.webhookId}`);
|
|
7942
|
+
console.log(`action: ${created.action}`);
|
|
7943
|
+
console.log(`params: ${JSON.stringify(created.params)}`);
|
|
7944
|
+
if (payload.label)
|
|
7945
|
+
console.log(`label: ${payload.label}`);
|
|
7946
|
+
if (payload.maxUses !== undefined)
|
|
7947
|
+
console.log(`maxUses: ${payload.maxUses}`);
|
|
7948
|
+
if (payload.expiresAt !== undefined) {
|
|
7949
|
+
console.log(`expiresAt: ${new Date(payload.expiresAt).toISOString()}`);
|
|
7950
|
+
}
|
|
7951
|
+
console.log("");
|
|
7952
|
+
console.log(pc4.dim(`Fire it with: curl -X POST -H 'Content-Type: application/json' -d '{"content":"hi"}' ` + created.url));
|
|
7953
|
+
}
|
|
7954
|
+
async function webhookList(options) {
|
|
7955
|
+
const apiKey = resolveAuthOrExit();
|
|
7956
|
+
const { ok, data, status } = await platformApiRequest("GET", "/api/cli/webhooks", apiKey);
|
|
7957
|
+
if (!ok) {
|
|
7958
|
+
const errMsg = data?.error ?? `HTTP ${status}`;
|
|
7959
|
+
console.error(pc4.red("Error:") + " " + errMsg);
|
|
7960
|
+
process.exit(1);
|
|
7961
|
+
}
|
|
7962
|
+
const webhooks = data.webhooks;
|
|
7963
|
+
if (options.json) {
|
|
7964
|
+
console.log(JSON.stringify(webhooks, null, 2));
|
|
7965
|
+
return;
|
|
7966
|
+
}
|
|
7967
|
+
if (webhooks.length === 0) {
|
|
7968
|
+
console.log("No webhooks found.");
|
|
7969
|
+
console.log(pc4.dim("Create one with: calabasas webhook create --bot <id> --action sendDM --user-id <id>"));
|
|
7970
|
+
return;
|
|
7971
|
+
}
|
|
7972
|
+
for (const w of webhooks) {
|
|
7973
|
+
const target = w.params.userId ? `user ${w.params.userId}` : `channel ${w.params.channelId}`;
|
|
7974
|
+
const uses = w.maxUses !== undefined ? `${w.usageCount}/${w.maxUses}` : `${w.usageCount}/—`;
|
|
7975
|
+
const statusColor = w.status === "active" ? pc4.green : w.status === "expired" ? pc4.yellow : pc4.red;
|
|
7976
|
+
console.log(`${pc4.cyan(w.token)} ${w.action} ${target} uses=${uses} ${statusColor(w.status)}` + (w.label ? ` label=${w.label}` : ""));
|
|
7977
|
+
console.log(` ${pc4.dim(w.url)}`);
|
|
7978
|
+
}
|
|
7979
|
+
}
|
|
7980
|
+
async function webhookRevoke(token, _options) {
|
|
7981
|
+
if (!token) {
|
|
7982
|
+
console.error(pc4.red("Error:") + " token argument is required.");
|
|
7983
|
+
process.exit(1);
|
|
7984
|
+
}
|
|
7985
|
+
const apiKey = resolveAuthOrExit();
|
|
7986
|
+
const { ok, data, status } = await platformApiRequest("DELETE", `/api/cli/webhooks?token=${encodeURIComponent(token)}`, apiKey);
|
|
7987
|
+
if (!ok) {
|
|
7988
|
+
const errMsg = data?.error ?? `HTTP ${status}`;
|
|
7989
|
+
console.error(pc4.red("Error:") + " " + errMsg);
|
|
7990
|
+
process.exit(1);
|
|
7991
|
+
}
|
|
7992
|
+
console.log(pc4.green("Webhook revoked."));
|
|
7993
|
+
}
|
|
7994
|
+
|
|
7837
7995
|
// src/index.ts
|
|
7838
7996
|
var dashboard = async () => {
|
|
7839
7997
|
const mod = await import("./dashboard-a862sabz.js");
|
|
@@ -7870,4 +8028,8 @@ platformCmd.command("info").description("Show platform info (secret, URL, API ke
|
|
|
7870
8028
|
platformCmd.command("set-url").description("Set Convex URL for your platform").action(platformSetUrl);
|
|
7871
8029
|
platformCmd.command("rotate-key").description("Rotate your platform API key (for SDK access)").action(platformRotateKey);
|
|
7872
8030
|
platformCmd.command("rotate-secret").description("Rotate the platform secret (invalidates CALABASAS_SECRET)").action(platformRotateSecret);
|
|
8031
|
+
var webhookCmd = program2.command("webhook").description("Manage one-off webhook URLs that fire pre-bound Discord actions");
|
|
8032
|
+
webhookCmd.command("create").description("Create a webhook URL bound to a single bot, action, and target").requiredOption("-b, --bot <botId>", "Bot ID that will perform the action").requiredOption("-a, --action <action>", "Action to fire: sendDM | sendChannelMessage").option("--user-id <discordUserId>", "Target user ID (required for sendDM)").option("--channel-id <discordChannelId>", "Target channel ID (required for sendChannelMessage)").option("--label <label>", "Human-readable label for listing").option("--max-uses <number>", "Max times this URL can be fired before it stops working").option("--expires <duration>", "Auto-expire after duration: e.g. 30m, 24h, 7d").option("--platform-id <id>", "Platform ID (only needed with user key + multiple platforms)").action(webhookCreate);
|
|
8033
|
+
webhookCmd.command("list").alias("ls").description("List all non-revoked webhooks for the current platform").option("--json", "Output raw JSON instead of a table").action(webhookList);
|
|
8034
|
+
webhookCmd.command("revoke <token>").description("Revoke a webhook by token (soft delete)").option("-y, --yes", "Skip confirmation prompt (currently a no-op)").action(webhookRevoke);
|
|
7873
8035
|
program2.parse();
|