calabasas 0.20.1 → 0.21.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 (2) hide show
  1. package/dist/index.js +126 -32
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2587,42 +2587,72 @@ async function generate(options) {
2587
2587
  fs4.writeFileSync(testingPath, files["testing.ts"]);
2588
2588
  generated.push("convex/calabasas/_generated/testing.ts");
2589
2589
  }
2590
+ if (files["oauth.ts"]) {
2591
+ const oauthPath = path4.join(generatedDir, "oauth.ts");
2592
+ fs4.writeFileSync(oauthPath, files["oauth.ts"]);
2593
+ generated.push("convex/calabasas/_generated/oauth.ts");
2594
+ }
2590
2595
  s.stop(`Generated ${generated.length} file${generated.length > 1 ? "s" : ""}`);
2591
2596
  p5.note(generated.join(`
2592
2597
  `), "Generated files");
2593
- const hasSyncEnabled = !!files["schema.ts"];
2594
- if (hasSyncEnabled) {
2595
- const syncExports = [];
2596
- const text = configText.toLowerCase();
2597
- if (text.includes("guilds") && text.includes("true")) {
2598
- syncExports.push("syncGuild");
2599
- syncExports.push("syncGuildAdmins");
2600
- }
2601
- if (text.includes("channels") && text.includes("true"))
2602
- syncExports.push("syncChannel", "syncChannelBatch");
2603
- if (text.includes("roles") && text.includes("true"))
2604
- syncExports.push("syncRole", "syncRoleBatch");
2605
- if (text.includes("members") && text.includes("true"))
2606
- syncExports.push("syncMember", "syncMemberBatch");
2607
- if (text.includes("presence") && text.includes("true"))
2608
- syncExports.push("syncPresence", "syncPresenceBatch");
2609
- if (syncExports.length === 0) {
2610
- syncExports.push("syncGuild", "syncChannel", "syncChannelBatch", "syncRole", "syncRoleBatch", "syncMember", "syncMemberBatch", "syncPresence", "syncPresenceBatch");
2611
- }
2612
- syncExports.push("updateSyncState");
2613
- p5.note(`1. Add tables to your convex/schema.ts:
2598
+ const hasSyncEnabled = !!files["sync.ts"];
2599
+ const hasOAuthEnabled = !!files["oauth.ts"];
2600
+ if (hasSyncEnabled || hasOAuthEnabled) {
2601
+ const steps = [];
2602
+ let stepNum = 1;
2603
+ if (hasSyncEnabled || hasOAuthEnabled) {
2604
+ steps.push(`${stepNum}. Add tables to your convex/schema.ts:
2614
2605
  import { calabasasTables } from "./calabasas/_generated/schema";
2615
2606
 
2616
2607
  export default defineSchema({
2617
2608
  ...calabasasTables,
2618
- });
2619
-
2620
- 2. Re-export sync mutations in convex/discord.ts:
2621
- export { ${syncExports.join(", ")} } from "./calabasas/_generated/sync";
2609
+ });`);
2610
+ stepNum++;
2611
+ }
2612
+ if (hasSyncEnabled) {
2613
+ const syncExports = [];
2614
+ const text = configText.toLowerCase();
2615
+ if (text.includes("guilds") && text.includes("true")) {
2616
+ syncExports.push("syncGuild");
2617
+ syncExports.push("syncGuildAdmins");
2618
+ }
2619
+ if (text.includes("channels") && text.includes("true"))
2620
+ syncExports.push("syncChannel", "syncChannelBatch");
2621
+ if (text.includes("roles") && text.includes("true"))
2622
+ syncExports.push("syncRole", "syncRoleBatch");
2623
+ if (text.includes("members") && text.includes("true"))
2624
+ syncExports.push("syncMember", "syncMemberBatch");
2625
+ if (text.includes("presence") && text.includes("true"))
2626
+ syncExports.push("syncPresence", "syncPresenceBatch");
2627
+ if (syncExports.length === 0) {
2628
+ syncExports.push("syncGuild", "syncChannel", "syncChannelBatch", "syncRole", "syncRoleBatch", "syncMember", "syncMemberBatch", "syncPresence", "syncPresenceBatch");
2629
+ }
2630
+ syncExports.push("updateSyncState");
2631
+ steps.push(`${stepNum}. Re-export sync mutations in convex/discord.ts:
2632
+ export { ${syncExports.join(", ")} } from "./calabasas/_generated/sync";`);
2633
+ stepNum++;
2634
+ }
2635
+ if (hasOAuthEnabled) {
2636
+ steps.push(`${stepNum}. Re-export OAuth mutations in convex/discord.ts:
2637
+ export { syncOAuthToken } from "./calabasas/_generated/oauth";`);
2638
+ stepNum++;
2639
+ steps.push(`${stepNum}. Create your verification handler in convex/calabasas/discord.ts:
2640
+
2641
+ import { handleOAuthVerification } from "./_generated/oauth";
2642
+
2643
+ export const verify = handleOAuthVerification({
2644
+ onVerify: async (ctx, { user, guildId, tokens }, bot) => {
2645
+ console.log("User verified:", user.username);
2646
+ },
2647
+ });`);
2648
+ stepNum++;
2649
+ }
2650
+ steps.push(`${stepNum}. Add CALABASAS_SECRET to your Convex environment variables`);
2651
+ stepNum++;
2652
+ steps.push(`${stepNum}. Run \`calabasas push\` to sync config with Calabasas`);
2653
+ p5.note(steps.join(`
2622
2654
 
2623
- 3. Add CALABASAS_SECRET to your Convex environment variables
2624
- 4. Create your event handler in convex/calabasas/discord.ts
2625
- 5. Run \`calabasas push\` to sync config with Calabasas`, "Next steps");
2655
+ `), "Next steps");
2626
2656
  } else {
2627
2657
  p5.note(`1. Add CALABASAS_SECRET to your Convex environment variables
2628
2658
  2. Create your handler in convex/calabasas/discord.ts:
@@ -4686,6 +4716,7 @@ type EmojiData = {
4686
4716
 
4687
4717
  type EmojiPickerProps = {
4688
4718
  guildDiscordId?: string;
4719
+ discordAppId?: string;
4689
4720
  source?: "all" | "guild" | "application" | "default";
4690
4721
  mode?: "single" | "multi";
4691
4722
  maxCount?: number;
@@ -5247,6 +5278,7 @@ function LazyEmoji({
5247
5278
 
5248
5279
  export function EmojiPicker({
5249
5280
  guildDiscordId,
5281
+ discordAppId,
5250
5282
  source = "all",
5251
5283
  mode = "single",
5252
5284
  maxCount,
@@ -5280,7 +5312,7 @@ export function EmojiPicker({
5280
5312
  );
5281
5313
  const appEmojis = useQuery(
5282
5314
  api.calabasas.queries.listAppEmojis,
5283
- needsApp ? {} : "skip"
5315
+ needsApp && discordAppId ? { discordAppId } : "skip"
5284
5316
  );
5285
5317
 
5286
5318
  // Build sections
@@ -5644,7 +5676,7 @@ export function EmojiPicker({
5644
5676
  });
5645
5677
 
5646
5678
  export const listAppEmojis = query({
5647
- args: {},
5679
+ args: { discordAppId: v.string() },
5648
5680
  returns: v.array(
5649
5681
  v.object({
5650
5682
  discordId: v.string(),
@@ -5653,9 +5685,10 @@ export const listAppEmojis = query({
5653
5685
  available: v.boolean(),
5654
5686
  })
5655
5687
  ),
5656
- handler: async (ctx) => {
5688
+ handler: async (ctx, { discordAppId }) => {
5657
5689
  const emojis = await ctx.db
5658
5690
  .query("calabasasAppEmojis")
5691
+ .withIndex("by_application", (q) => q.eq("discordAppId", discordAppId))
5659
5692
  .collect();
5660
5693
  return emojis
5661
5694
  .filter((e) => e.available)
@@ -6852,6 +6885,10 @@ async function botAdd(options) {
6852
6885
  }
6853
6886
  intents = selectedIntents.reduce((sum, i) => sum + INTENT_ENTRIES[i].value, 0);
6854
6887
  }
6888
+ let clientSecret;
6889
+ if (options.clientSecret) {
6890
+ clientSecret = options.clientSecret;
6891
+ }
6855
6892
  const s = p10.spinner();
6856
6893
  s.start("Creating bot...");
6857
6894
  let ok;
@@ -6862,6 +6899,7 @@ async function botAdd(options) {
6862
6899
  name: name.trim(),
6863
6900
  discordAppId: discordAppId.trim(),
6864
6901
  token,
6902
+ clientSecret,
6865
6903
  intents
6866
6904
  }));
6867
6905
  } else {
@@ -6881,6 +6919,7 @@ async function botAdd(options) {
6881
6919
  name: name.trim(),
6882
6920
  discordAppId: discordAppId.trim(),
6883
6921
  token,
6922
+ clientSecret,
6884
6923
  intents
6885
6924
  }));
6886
6925
  }
@@ -7054,6 +7093,44 @@ async function botEdit(botId, options) {
7054
7093
  p10.note("The Gateway will automatically reconnect with the new settings.", "Note");
7055
7094
  p10.outro("Bot updated successfully!");
7056
7095
  }
7096
+ async function botSetClientSecret(botId, options) {
7097
+ const auth = resolveAuth();
7098
+ if (!auth) {
7099
+ console.log("Not logged in. Run `calabasas login` first.");
7100
+ return;
7101
+ }
7102
+ p10.intro("calabasas bot set-client-secret");
7103
+ await showPlatformContext(auth.key);
7104
+ let secret;
7105
+ if (options.secret) {
7106
+ secret = options.secret;
7107
+ } else {
7108
+ secret = await p10.password({
7109
+ message: "Discord OAuth2 client secret",
7110
+ validate: (v) => v.trim() ? undefined : "Client secret is required"
7111
+ });
7112
+ if (p10.isCancel(secret)) {
7113
+ p10.cancel("Cancelled.");
7114
+ return;
7115
+ }
7116
+ }
7117
+ const s = p10.spinner();
7118
+ s.start("Setting client secret...");
7119
+ const { ok, data, status } = auth.isPlatformKey ? await platformApiRequest("PATCH", "/api/cli/bots", auth.key, {
7120
+ botId,
7121
+ clientSecret: secret
7122
+ }) : await apiRequest("PATCH", "/api/cli/bots", {
7123
+ botId,
7124
+ clientSecret: secret
7125
+ });
7126
+ if (!ok) {
7127
+ s.stop("Failed to set client secret");
7128
+ p10.cancel(`${data.error || `HTTP ${status}`}`);
7129
+ return;
7130
+ }
7131
+ s.stop("Done");
7132
+ p10.outro("Client secret set successfully!");
7133
+ }
7057
7134
 
7058
7135
  // src/commands/platform.ts
7059
7136
  import * as p11 from "@clack/prompts";
@@ -7469,6 +7546,22 @@ ${commandLines.join(`
7469
7546
  });
7470
7547
  sections.push(` contextMenus: {
7471
7548
  ${menuLines.join(`
7549
+ `)}
7550
+ },`);
7551
+ }
7552
+ }
7553
+ if (config.oauth) {
7554
+ const oauthLines = [];
7555
+ if (config.oauth.scopes && config.oauth.scopes.length > 0) {
7556
+ const items = config.oauth.scopes.map((s) => JSON.stringify(s)).join(", ");
7557
+ oauthLines.push(` scopes: [${items}],`);
7558
+ }
7559
+ if (config.oauth.redirectUrl) {
7560
+ oauthLines.push(` redirectUrl: ${JSON.stringify(config.oauth.redirectUrl)},`);
7561
+ }
7562
+ if (oauthLines.length > 0) {
7563
+ sections.push(` oauth: {
7564
+ ${oauthLines.join(`
7472
7565
  `)}
7473
7566
  },`);
7474
7567
  }
@@ -7764,10 +7857,11 @@ program2.command("config").description("View and modify your Calabasas config").
7764
7857
  program2.command("status").alias("dashboard").description("Real-time dashboard showing bot status, events, and stats").action(dashboard);
7765
7858
  program2.command("logs").description("Event log viewer (live by default, or one-shot with --once)").option("-b, --bot <id>", "Bot ID (omit for all bots in platform)").option("-n, --limit <number>", "Number of log entries to show", "50").option("--once", "One-shot output instead of real-time view").option("--errors", "Show only failed events").option("--success", "Show only successful events").action(logs);
7766
7859
  var bot = program2.command("bot").description("Manage Discord bots");
7767
- bot.command("add").description("Add a new Discord bot").option("-n, --name <name>", "Bot name").option("-a, --app-id <id>", "Discord Application ID").option("-t, --token <token>", "Bot token").option("-i, --intents <intents>", "Intents value (number)").action(botAdd);
7860
+ bot.command("add").description("Add a new Discord bot").option("-n, --name <name>", "Bot name").option("-a, --app-id <id>", "Discord Application ID").option("-t, --token <token>", "Bot token").option("-i, --intents <intents>", "Intents value (number)").option("--client-secret <secret>", "Discord OAuth2 client secret (optional)").action(botAdd);
7768
7861
  bot.command("list").alias("ls").description("List your Discord bots (real-time by default)").option("--once", "One-shot output instead of real-time view").action(botList);
7769
7862
  bot.command("remove <botId>").alias("rm").description("Remove a Discord bot").option("-y, --yes", "Skip confirmation prompt").action(botRemove);
7770
7863
  bot.command("edit <botId>").description("Edit a Discord bot").option("-n, --name <name>", "New bot name").option("-t, --token <token>", "New bot token").option("-i, --intents <intents>", "New intents value").action(botEdit);
7864
+ bot.command("set-client-secret <botId>").description("Set or update a bot's Discord OAuth2 client secret").option("-s, --secret <secret>", "Client secret value").action(botSetClientSecret);
7771
7865
  var platformCmd = program2.command("platform").description("Manage your Calabasas platform");
7772
7866
  platformCmd.command("create").description("Create a new platform with Convex project configuration").option("-n, --name <name>", "Platform name").option("-p, --project <project>", "Convex project name (e.g. diligent-swordfish-752)").action(platformCreate);
7773
7867
  platformCmd.command("connect").description("Connect this project to an existing platform (saves API key to .env.local)").action(platformConnect);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "calabasas",
3
- "version": "0.20.1",
3
+ "version": "0.21.0",
4
4
  "description": "CLI for Calabasas - Discord Gateway as a Service for Convex",
5
5
  "type": "module",
6
6
  "bin": {