@muxoai/platform 1.4.1 → 1.4.2

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 (43) hide show
  1. package/.agents/plugins/marketplace.json +1 -1
  2. package/.claude-plugin/marketplace.json +2 -2
  3. package/README.md +1 -1
  4. package/dist/cli.js +6 -3
  5. package/dist/composio-catalog.d.ts +177 -1
  6. package/dist/composio-catalog.js +1427 -7
  7. package/dist/config.d.ts +6 -0
  8. package/dist/config.js +11 -1
  9. package/dist/engine.d.ts +18 -1
  10. package/dist/engine.js +259 -35
  11. package/dist/mcp-schema.d.ts +162 -1
  12. package/dist/mcp-schema.js +1523 -40
  13. package/dist/mcp.d.ts +2 -2
  14. package/dist/mcp.js +412 -23
  15. package/dist/policy.d.ts +108 -1
  16. package/dist/policy.js +406 -1
  17. package/dist/providers/composio-instant.js +38 -3
  18. package/dist/providers/composio-sdk.d.ts +59 -2
  19. package/dist/providers/composio-sdk.js +273 -59
  20. package/dist/providers/stripe-projects.d.ts +4 -0
  21. package/dist/providers/stripe-projects.js +548 -126
  22. package/dist/server.js +531 -61
  23. package/dist/store.js +2 -0
  24. package/dist/types.d.ts +15 -0
  25. package/dist/ui/console-html.d.ts +31 -1
  26. package/dist/ui/console-html.js +922 -368
  27. package/dist/ui/design-tokens.js +1 -1
  28. package/dist/version.d.ts +1 -1
  29. package/dist/version.js +1 -1
  30. package/package.json +3 -2
  31. package/plugins/muxo/.claude-plugin/plugin.json +2 -2
  32. package/plugins/muxo/.codex-plugin/plugin.json +15 -8
  33. package/plugins/muxo/.cursor-plugin/plugin.json +30 -0
  34. package/plugins/muxo/hooks/session-start.sh +15 -3
  35. package/plugins/muxo/hooks/user-prompt-submit.sh +14 -1
  36. package/plugins/muxo/mcp.json +0 -10
  37. package/plugins/muxo/plugin.json +4 -4
  38. package/plugins/muxo/skills/muxo/SKILL.md +25 -16
  39. package/plugins/muxo/skills/muxo/references/cli.md +5 -1
  40. package/plugins/muxo/skills/muxo/references/mcp.md +11 -6
  41. package/plugins/muxo/skills/muxo-activity-summary/SKILL.md +81 -0
  42. package/plugins/muxo/skills/setup/SKILL.md +1 -1
  43. package/src/catalogues/stripe-projects-catalog.json +140 -0
@@ -1,8 +1,8 @@
1
1
  import { Composio } from "@composio/core";
2
2
  import type { MuxoConfig } from "../config.js";
3
3
  import type { MuxoTool, RiskLevel } from "../types.js";
4
- import { type ComposioToolkitMetadata, type ComposioTriggerEventRecord, type ComposioTriggerSubscription, type ComposioTriggerType } from "../composio-catalog.js";
5
- export type { ComposioToolkitMetadata, ComposioTriggerEventRecord, ComposioTriggerSubscription };
4
+ import { parseComposioWebhookEnvelope, type ComposioToolkitMetadata, type ComposioTriggerEventRecord, type ComposioTriggerSubscription, type ComposioTriggerType, type ComposioWebhookEventType } from "../composio-catalog.js";
5
+ export type { ComposioToolkitMetadata, ComposioTriggerEventRecord, ComposioTriggerSubscription, ComposioTriggerType, ComposioWebhookEventType, };
6
6
  export declare class ComposioSdkAdapter {
7
7
  private readonly config;
8
8
  private liveToolsCache;
@@ -26,6 +26,17 @@ export declare class ComposioSdkAdapter {
26
26
  cachedToolCount: number;
27
27
  capabilities: string[];
28
28
  };
29
+ getWebhookConfigInfo(): {
30
+ webhookUrl: string;
31
+ legacyWebhookUrl: string;
32
+ version: "V3";
33
+ events: ComposioWebhookEventType[];
34
+ secretConfigured: boolean;
35
+ subscriptionId: string | null;
36
+ projectId: string | null;
37
+ orgId: string | null;
38
+ userId: string | null;
39
+ };
29
40
  getCuratedTools(): MuxoTool[];
30
41
  static classifyActionRisk(upstreamSlug: string, description?: string): RiskLevel;
31
42
  listToolkits(params?: {
@@ -55,15 +66,61 @@ export declare class ComposioSdkAdapter {
55
66
  source: "composio_v3_sdk" | "muxo_managed";
56
67
  }>;
57
68
  listTriggerTypes(providerSlug?: string): ComposioTriggerType[];
69
+ /**
70
+ * Check what configuration is required for a trigger (`composio.triggers.getType(slug)`).
71
+ */
72
+ getTriggerType(triggerSlug: string, composioApiKey?: string | null): Promise<ComposioTriggerType & {
73
+ source: "composio_v3_sdk" | "muxo_trigger_catalog";
74
+ }>;
75
+ /**
76
+ * Create a trigger with required config (`composio.triggers.create(userId, slug, { triggerConfig })`)
77
+ * and optionally subscribe to real-time trigger events (`composio.triggers.subscribe`).
78
+ */
58
79
  enableTrigger(params: {
59
80
  workspaceId: string;
81
+ userId?: string;
60
82
  triggerSlug: string;
61
83
  providerSlug: string;
62
84
  connectedAccountId?: string;
63
85
  webhookUrl?: string;
64
86
  config?: Record<string, unknown>;
87
+ subscribe?: boolean;
65
88
  composioApiKey?: string | null;
66
89
  }): Promise<ComposioTriggerSubscription>;
90
+ /**
91
+ * Subscribe to real-time trigger events via `@composio/core` (`composio.triggers.subscribe`).
92
+ */
93
+ subscribeToTriggerEvents(params: {
94
+ workspaceId: string;
95
+ triggerId?: string;
96
+ toolkits?: string[];
97
+ onEvent?: (data: Record<string, unknown>) => void;
98
+ composioApiKey?: string | null;
99
+ }): Promise<{
100
+ subscribed: boolean;
101
+ triggerId?: string;
102
+ }>;
103
+ /**
104
+ * Verify an incoming Composio webhook payload and HMAC-SHA256 signature.
105
+ */
106
+ verifyWebhook(params: {
107
+ rawPayload: string;
108
+ signatureHeader?: string | null;
109
+ webhookIdHeader?: string | null;
110
+ webhookTimestampHeader?: string | null;
111
+ secret?: string | null;
112
+ toleranceSeconds?: number;
113
+ }): Promise<{
114
+ verified: boolean;
115
+ reason?: string;
116
+ envelope: ReturnType<typeof parseComposioWebhookEnvelope>;
117
+ }>;
118
+ disableTriggersMatching(params: {
119
+ workspaceId?: string;
120
+ triggerId?: string;
121
+ triggerSlug?: string;
122
+ connectedAccountId?: string;
123
+ }): number;
67
124
  listActiveTriggers(workspaceId: string): ComposioTriggerSubscription[];
68
125
  recordTriggerEvent(record: ComposioTriggerEventRecord): void;
69
126
  listTriggerEvents(workspaceId: string, limit?: number): ComposioTriggerEventRecord[];
@@ -1,6 +1,6 @@
1
1
  import { Composio } from "@composio/core";
2
2
  import { matchAppToolSlug } from "../mcp-schema.js";
3
- import { composioAuthConfigScopes, ENTERPRISE_TOOLKITS_CATALOG, filterComposioToolkits, getSampleActionSchema, listComposioTriggerTypes, } from "../composio-catalog.js";
3
+ import { composioAuthConfigScopes, COMPOSIO_V3_WEBHOOK_EVENTS, ensureOAuthCallbackParams, ENTERPRISE_TOOLKITS_CATALOG, filterComposioToolkits, getComposioTriggerType, getSampleActionSchema, isStripeProjectsExclusiveProvider, listComposioTriggerTypes, parseComposioWebhookEnvelope, verifyComposioWebhookSignature, wrapMuxoConnectUrl, } from "../composio-catalog.js";
4
4
  const CURATED_APP_TOOLS = [
5
5
  {
6
6
  slug: "app.github.list_repos",
@@ -404,13 +404,17 @@ export class ComposioSdkAdapter {
404
404
  }
405
405
  hydrateEnterpriseSampleActions() {
406
406
  for (const tk of ENTERPRISE_TOOLKITS_CATALOG) {
407
+ if (isStripeProjectsExclusiveProvider(tk.slug))
408
+ continue;
407
409
  for (const act of tk.sampleActions) {
410
+ if (act.muxoSlug.startsWith("resource."))
411
+ continue;
408
412
  if (!this.liveToolsCache.has(act.muxoSlug)) {
409
413
  this.liveToolsCache.set(act.muxoSlug, {
410
414
  slug: act.muxoSlug,
411
415
  upstreamSlug: act.upstreamSlug,
412
416
  name: act.name,
413
- description: `${tk.name}: ${act.name} (Composio v3 toolkit version ${tk.pinnedVersion})`,
417
+ description: `${tk.name}: ${act.name} (Muxo Connected Apps toolkit v${tk.pinnedVersion})`,
414
418
  lane: "composio_sdk",
415
419
  providerSlug: tk.slug,
416
420
  providerName: tk.name,
@@ -483,9 +487,26 @@ export class ComposioSdkAdapter {
483
487
  "connectedAccounts.get",
484
488
  "connectedAccounts.list",
485
489
  "authConfigs.list",
490
+ "triggers.getType",
491
+ "triggers.create",
492
+ "triggers.subscribe",
493
+ "triggers.verifyWebhook",
486
494
  ],
487
495
  };
488
496
  }
497
+ getWebhookConfigInfo() {
498
+ return {
499
+ webhookUrl: "https://api.muxo.ai/webhooks",
500
+ legacyWebhookUrl: "https://api.muxo.ai/api/v1/triggers/webhook",
501
+ version: "V3",
502
+ events: [...COMPOSIO_V3_WEBHOOK_EVENTS],
503
+ secretConfigured: Boolean(this.config.composioWebhookSecret),
504
+ subscriptionId: this.config.composioWebhookSubscriptionId || null,
505
+ projectId: this.config.composioProjectId || null,
506
+ orgId: this.config.composioOrgId || null,
507
+ userId: this.config.composioUserId || null,
508
+ };
509
+ }
489
510
  getCuratedTools() {
490
511
  return Array.from(this.liveToolsCache.values());
491
512
  }
@@ -563,23 +584,194 @@ export class ComposioSdkAdapter {
563
584
  listTriggerTypes(providerSlug) {
564
585
  return listComposioTriggerTypes(providerSlug);
565
586
  }
587
+ /**
588
+ * Check what configuration is required for a trigger (`composio.triggers.getType(slug)`).
589
+ */
590
+ async getTriggerType(triggerSlug, composioApiKey) {
591
+ const normalizedSlug = String(triggerSlug || "GITHUB_COMMIT_EVENT")
592
+ .toUpperCase()
593
+ .trim();
594
+ const fallback = getComposioTriggerType(normalizedSlug);
595
+ const sdk = this.getComposioClient(composioApiKey);
596
+ if (sdk) {
597
+ try {
598
+ const triggerType = await Promise.race([
599
+ sdk.triggers.getType(normalizedSlug),
600
+ new Promise((_, reject) => setTimeout(() => reject(new Error("Composio SDK triggers.getType timeout")), 4500)),
601
+ ]);
602
+ if (triggerType) {
603
+ const toolkitSlug = String(triggerType.toolkit?.slug || fallback.providerSlug).toLowerCase();
604
+ return {
605
+ slug: String(triggerType.slug || normalizedSlug),
606
+ providerSlug: toolkitSlug,
607
+ name: String(triggerType.name || fallback.name),
608
+ description: String(triggerType.description || fallback.description),
609
+ config: triggerType.config && typeof triggerType.config === "object"
610
+ ? triggerType.config
611
+ : fallback.config,
612
+ source: "composio_v3_sdk",
613
+ };
614
+ }
615
+ }
616
+ catch {
617
+ // Fall back to Muxo trigger catalog when offline or unconfigured
618
+ }
619
+ }
620
+ return {
621
+ ...fallback,
622
+ source: "muxo_trigger_catalog",
623
+ };
624
+ }
625
+ /**
626
+ * Create a trigger with required config (`composio.triggers.create(userId, slug, { triggerConfig })`)
627
+ * and optionally subscribe to real-time trigger events (`composio.triggers.subscribe`).
628
+ */
566
629
  async enableTrigger(params) {
567
- const id = `trg_${params.providerSlug}_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
630
+ const normalizedTriggerSlug = params.triggerSlug.toUpperCase().trim();
631
+ const triggerType = await this.getTriggerType(normalizedTriggerSlug, params.composioApiKey);
632
+ const providerSlug = (params.providerSlug ||
633
+ triggerType.providerSlug ||
634
+ "github")
635
+ .toLowerCase()
636
+ .trim();
637
+ const userId = params.userId || this.config.composioUserId || params.workspaceId;
638
+ const triggerConfig = params.config || {};
639
+ let upstreamTriggerId;
640
+ let source = "muxo_managed";
641
+ const sdk = this.getComposioClient(params.composioApiKey);
642
+ if (sdk) {
643
+ try {
644
+ const created = await Promise.race([
645
+ sdk.triggers.create(userId, normalizedTriggerSlug, {
646
+ ...(params.connectedAccountId
647
+ ? { connectedAccountId: params.connectedAccountId }
648
+ : {}),
649
+ triggerConfig,
650
+ }),
651
+ new Promise((_, reject) => setTimeout(() => reject(new Error("Composio SDK triggers.create timeout")), 6000)),
652
+ ]);
653
+ if (created?.triggerId) {
654
+ upstreamTriggerId = String(created.triggerId);
655
+ source = "composio_v3_sdk";
656
+ if (params.subscribe) {
657
+ await this.subscribeToTriggerEvents({
658
+ workspaceId: params.workspaceId,
659
+ triggerId: upstreamTriggerId,
660
+ composioApiKey: params.composioApiKey,
661
+ }).catch(() => { });
662
+ }
663
+ }
664
+ }
665
+ catch {
666
+ // Fall through to deterministic local subscription record
667
+ }
668
+ }
669
+ const id = upstreamTriggerId ||
670
+ `trg_${providerSlug}_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
568
671
  const sub = {
569
672
  id,
673
+ upstreamTriggerId,
570
674
  workspaceId: params.workspaceId,
571
- triggerSlug: params.triggerSlug.toUpperCase().trim(),
572
- providerSlug: params.providerSlug.toLowerCase().trim(),
573
- connectedAccountId: params.connectedAccountId || `ca_${params.providerSlug}_${params.workspaceId.slice(0, 8)}`,
675
+ userId,
676
+ triggerSlug: normalizedTriggerSlug,
677
+ providerSlug,
678
+ connectedAccountId: params.connectedAccountId || `ca_${providerSlug}_${params.workspaceId.slice(0, 8)}`,
574
679
  webhookUrl: params.webhookUrl ||
575
- `https://api.muxo.ai/api/v1/triggers/webhook`,
576
- config: params.config || {},
680
+ `https://api.muxo.ai/webhooks`,
681
+ config: triggerConfig,
577
682
  status: "active",
683
+ source,
578
684
  createdAt: new Date().toISOString(),
579
685
  };
580
686
  this.activeTriggers.set(id, sub);
581
687
  return sub;
582
688
  }
689
+ /**
690
+ * Subscribe to real-time trigger events via `@composio/core` (`composio.triggers.subscribe`).
691
+ */
692
+ async subscribeToTriggerEvents(params) {
693
+ const sdk = this.getComposioClient(params.composioApiKey);
694
+ if (!sdk) {
695
+ return { subscribed: false, triggerId: params.triggerId };
696
+ }
697
+ await sdk.triggers.subscribe((data) => {
698
+ const recordPayload = (data?.payload || data || {});
699
+ const triggerSlug = String(data?.triggerSlug || "GITHUB_COMMIT_EVENT").toUpperCase();
700
+ const providerSlug = String(data?.toolkitSlug || triggerSlug.split("_")[0] || "github").toLowerCase();
701
+ this.recordTriggerEvent({
702
+ id: `trgevt_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`,
703
+ workspaceId: params.workspaceId,
704
+ eventType: "composio.trigger.message",
705
+ webhookVersion: "V3",
706
+ triggerId: data?.id || params.triggerId,
707
+ triggerSlug,
708
+ providerSlug,
709
+ connectedAccountId: data?.metadata?.connectedAccount?.id,
710
+ userId: data?.userId || data?.metadata?.connectedAccount?.userId,
711
+ receivedAt: new Date().toISOString(),
712
+ promptInjectionScan: {
713
+ safe: true,
714
+ riskScore: 0,
715
+ findings: [],
716
+ },
717
+ disposition: "dispatched",
718
+ payloadPreview: recordPayload,
719
+ });
720
+ params.onEvent?.(data);
721
+ }, {
722
+ ...(params.triggerId ? { triggerId: params.triggerId } : {}),
723
+ ...(params.toolkits ? { toolkits: params.toolkits } : {}),
724
+ });
725
+ return { subscribed: true, triggerId: params.triggerId };
726
+ }
727
+ /**
728
+ * Verify an incoming Composio webhook payload and HMAC-SHA256 signature.
729
+ */
730
+ async verifyWebhook(params) {
731
+ const secret = (params.secret ?? this.config.composioWebhookSecret ?? "").trim();
732
+ const sigCheck = await verifyComposioWebhookSignature({
733
+ rawPayload: params.rawPayload,
734
+ signatureHeader: params.signatureHeader,
735
+ webhookIdHeader: params.webhookIdHeader,
736
+ webhookTimestampHeader: params.webhookTimestampHeader,
737
+ secret,
738
+ toleranceSeconds: params.toleranceSeconds,
739
+ });
740
+ let parsedJson = {};
741
+ try {
742
+ parsedJson = JSON.parse(params.rawPayload || "{}");
743
+ }
744
+ catch {
745
+ parsedJson = {};
746
+ }
747
+ const envelope = parseComposioWebhookEnvelope(parsedJson, {
748
+ webhookId: params.webhookIdHeader,
749
+ webhookTimestamp: params.webhookTimestampHeader,
750
+ });
751
+ return {
752
+ verified: sigCheck.verified,
753
+ reason: sigCheck.reason,
754
+ envelope,
755
+ };
756
+ }
757
+ disableTriggersMatching(params) {
758
+ let count = 0;
759
+ for (const sub of this.activeTriggers.values()) {
760
+ if (params.workspaceId && sub.workspaceId !== params.workspaceId)
761
+ continue;
762
+ const matchesTriggerId = Boolean(params.triggerId) &&
763
+ (sub.id === params.triggerId || sub.upstreamTriggerId === params.triggerId);
764
+ const matchesConnectedAccount = Boolean(params.connectedAccountId) &&
765
+ sub.connectedAccountId === params.connectedAccountId;
766
+ const matchesSlug = Boolean(params.triggerSlug) &&
767
+ sub.triggerSlug.toUpperCase() === params.triggerSlug.toUpperCase();
768
+ if (matchesTriggerId || matchesConnectedAccount || matchesSlug) {
769
+ sub.status = "disabled";
770
+ count += 1;
771
+ }
772
+ }
773
+ return count;
774
+ }
583
775
  listActiveTriggers(workspaceId) {
584
776
  return Array.from(this.activeTriggers.values()).filter((t) => t.workspaceId === workspaceId);
585
777
  }
@@ -601,6 +793,10 @@ export class ComposioSdkAdapter {
601
793
  return null;
602
794
  const toolkitObj = (item.toolkit || {});
603
795
  const providerSlug = String(toolkitObj.slug || upstreamSlug.split("_")[0] || "app").toLowerCase();
796
+ // Never surface Stripe Projects cloud infrastructure providers as Composio OAuth tools
797
+ if (isStripeProjectsExclusiveProvider(providerSlug)) {
798
+ return null;
799
+ }
604
800
  const providerName = String(toolkitObj.name || providerSlug.charAt(0).toUpperCase() + providerSlug.slice(1));
605
801
  const actionPart = upstreamSlug
606
802
  .toLowerCase()
@@ -617,7 +813,7 @@ export class ComposioSdkAdapter {
617
813
  slug: muxoSlug,
618
814
  upstreamSlug,
619
815
  name: `${providerName}: ${String(item.name || actionPart)}`,
620
- description: String(item.description || `Execute ${upstreamSlug} via Composio`),
816
+ description: String(item.description || `Execute ${upstreamSlug} via Muxo Connected Apps`),
621
817
  lane: "composio_sdk",
622
818
  providerSlug,
623
819
  providerName,
@@ -634,6 +830,10 @@ export class ComposioSdkAdapter {
634
830
  async searchTools(query, limit = 15, composioApiKey, toolkit) {
635
831
  const q = (query || "").trim().toLowerCase();
636
832
  const tk = (toolkit || "").trim().toLowerCase();
833
+ // Stripe Projects infrastructure providers belong to stripe_projects lane, not Composio OAuth
834
+ if (tk && isStripeProjectsExclusiveProvider(tk)) {
835
+ return [];
836
+ }
637
837
  const localMatches = this.getCuratedTools().filter((t) => {
638
838
  if (tk && t.providerSlug.toLowerCase() !== tk)
639
839
  return false;
@@ -716,6 +916,9 @@ export class ComposioSdkAdapter {
716
916
  if (!normalizedSlug.startsWith("app.") || !apiKey)
717
917
  return null;
718
918
  const parts = normalizedSlug.split(".");
919
+ if (parts.length >= 2 && isStripeProjectsExclusiveProvider(parts[1] || "")) {
920
+ return null;
921
+ }
719
922
  if (parts.length >= 3) {
720
923
  const upstreamCandidate = parts.slice(1).join("_").toUpperCase();
721
924
  const sdk = this.getComposioClient(composioApiKey);
@@ -743,8 +946,15 @@ export class ComposioSdkAdapter {
743
946
  async startConnection(params) {
744
947
  const providerSlug = params.providerSlug.toLowerCase().replace(/^app\./, "");
745
948
  const providerName = providerSlug.charAt(0).toUpperCase() + providerSlug.slice(1);
746
- const callbackUrl = params.callbackUrl ||
949
+ const rawCallbackUrl = params.callbackUrl ||
747
950
  `${this.config.baseUrl}/oauth/callback?workspace_id=${encodeURIComponent(params.workspaceId)}&provider=${encodeURIComponent(providerSlug)}`;
951
+ const callbackUrl = ensureOAuthCallbackParams(rawCallbackUrl, params.workspaceId, providerSlug);
952
+ const wrapRedirect = (url, externalAccountId) => wrapMuxoConnectUrl(url, this.config.baseUrl, {
953
+ workspaceId: params.workspaceId,
954
+ providerSlug,
955
+ callbackUrl,
956
+ externalAccountId: externalAccountId || null,
957
+ });
748
958
  const apiKey = this.resolveApiKey(params.composioApiKey);
749
959
  if (!apiKey) {
750
960
  const externalAccountId = `ca_ext_${providerSlug}_${params.workspaceId.slice(-8)}`;
@@ -758,7 +968,52 @@ export class ComposioSdkAdapter {
758
968
  message: `Open the authorization URL to connect ${providerName} to your Muxo workspace.`,
759
969
  };
760
970
  }
761
- // 1. Official @composio/core SDK Tool Router & Connected Accounts initiation
971
+ // 1. Try creating a Tool Router Session & link for the workspace user (supports expected_input_fields + callback_url)
972
+ try {
973
+ const sessionRes = await fetch(`${this.config.composioBaseUrl}/tool_router/session`, {
974
+ method: "POST",
975
+ headers: this.getHeaders(params.composioApiKey),
976
+ body: JSON.stringify({
977
+ user_id: params.workspaceId,
978
+ toolkits: { enable: [providerSlug] },
979
+ }),
980
+ signal: AbortSignal.timeout(8000),
981
+ });
982
+ if (sessionRes.ok) {
983
+ const sessionData = (await sessionRes.json());
984
+ const sessionId = sessionData.session_id;
985
+ if (sessionId) {
986
+ const linkRes = await fetch(`${this.config.composioBaseUrl}/tool_router/session/${sessionId}/link`, {
987
+ method: "POST",
988
+ headers: this.getHeaders(params.composioApiKey),
989
+ body: JSON.stringify({
990
+ toolkit: providerSlug,
991
+ callback_url: callbackUrl,
992
+ }),
993
+ signal: AbortSignal.timeout(8000),
994
+ });
995
+ if (linkRes.ok) {
996
+ const linkData = (await linkRes.json());
997
+ if (linkData.redirect_url) {
998
+ const extId = linkData.connected_account_id || sessionId;
999
+ return {
1000
+ providerSlug,
1001
+ providerName,
1002
+ status: "pending",
1003
+ redirectUrl: wrapRedirect(linkData.redirect_url, extId),
1004
+ callbackUrl,
1005
+ externalAccountId: extId,
1006
+ message: `Open the authorization URL to connect ${providerName} to your Muxo workspace.`,
1007
+ };
1008
+ }
1009
+ }
1010
+ }
1011
+ }
1012
+ }
1013
+ catch {
1014
+ // Fall through to @composio/core SDK / connected_accounts flow
1015
+ }
1016
+ // 2. Official @composio/core SDK Connected Accounts initiation fallback
762
1017
  const sdk = this.getComposioClient(params.composioApiKey);
763
1018
  if (sdk) {
764
1019
  try {
@@ -776,10 +1031,11 @@ export class ComposioSdkAdapter {
776
1031
  new Promise((_, reject) => setTimeout(() => reject(new Error("Composio SDK initiate timeout")), 6000)),
777
1032
  ]);
778
1033
  const externalAccountId = connRequest?.id || null;
779
- const redirectUrl = connRequest?.redirectUrl ||
1034
+ const rawRedirectUrl = connRequest?.redirectUrl ||
780
1035
  (externalAccountId
781
1036
  ? `${callbackUrl}&connected_account_id=${encodeURIComponent(externalAccountId)}`
782
1037
  : null);
1038
+ const redirectUrl = wrapRedirect(rawRedirectUrl, externalAccountId);
783
1039
  if (redirectUrl) {
784
1040
  return {
785
1041
  providerSlug,
@@ -798,10 +1054,11 @@ export class ComposioSdkAdapter {
798
1054
  new Promise((_, reject) => setTimeout(() => reject(new Error("Composio SDK toolkits.authorize timeout")), 6000)),
799
1055
  ]);
800
1056
  const externalAccountId = authReq?.id || null;
801
- const redirectUrl = authReq?.redirectUrl ||
1057
+ const rawRedirectUrl = authReq?.redirectUrl ||
802
1058
  (externalAccountId
803
1059
  ? `${callbackUrl}&connected_account_id=${encodeURIComponent(externalAccountId)}`
804
1060
  : null);
1061
+ const redirectUrl = wrapRedirect(rawRedirectUrl, externalAccountId);
805
1062
  if (redirectUrl) {
806
1063
  return {
807
1064
  providerSlug,
@@ -816,53 +1073,9 @@ export class ComposioSdkAdapter {
816
1073
  }
817
1074
  }
818
1075
  catch {
819
- // Fall through to Tool Router REST session / v3 API fallback
1076
+ // Fall through to v3 API fallback
820
1077
  }
821
1078
  }
822
- // 2. Try creating a Composio Tool Router Session & link for the workspace user
823
- try {
824
- const sessionRes = await fetch(`${this.config.composioBaseUrl}/tool_router/session`, {
825
- method: "POST",
826
- headers: this.getHeaders(params.composioApiKey),
827
- body: JSON.stringify({
828
- user_id: params.workspaceId,
829
- toolkits: { enable: [providerSlug] },
830
- }),
831
- signal: AbortSignal.timeout(8000),
832
- });
833
- if (sessionRes.ok) {
834
- const sessionData = (await sessionRes.json());
835
- const sessionId = sessionData.session_id;
836
- if (sessionId) {
837
- const linkRes = await fetch(`${this.config.composioBaseUrl}/tool_router/session/${sessionId}/link`, {
838
- method: "POST",
839
- headers: this.getHeaders(params.composioApiKey),
840
- body: JSON.stringify({
841
- toolkit: providerSlug,
842
- callback_url: callbackUrl,
843
- }),
844
- signal: AbortSignal.timeout(8000),
845
- });
846
- if (linkRes.ok) {
847
- const linkData = (await linkRes.json());
848
- if (linkData.redirect_url) {
849
- return {
850
- providerSlug,
851
- providerName,
852
- status: "pending",
853
- redirectUrl: linkData.redirect_url,
854
- callbackUrl,
855
- externalAccountId: linkData.connected_account_id || sessionId,
856
- message: `Open the authorization URL to connect ${providerName} to your Muxo workspace.`,
857
- };
858
- }
859
- }
860
- }
861
- }
862
- }
863
- catch {
864
- // Fall through to auth_configs / connected_accounts flow
865
- }
866
1079
  // 3. Fallback: look up or create an auth_config for the toolkit and initiate connected_accounts
867
1080
  const authCfgRes = await fetch(`${this.config.composioBaseUrl}/auth_configs?toolkit_slug=${encodeURIComponent(providerSlug)}&limit=5`, {
868
1081
  headers: this.getHeaders(params.composioApiKey),
@@ -887,9 +1100,10 @@ export class ComposioSdkAdapter {
887
1100
  if (connRes.ok) {
888
1101
  const connData = (await connRes.json());
889
1102
  const fallbackRedirect = `${callbackUrl}&connected_account_id=${encodeURIComponent(connData.id || `ca_${providerSlug}`)}`;
890
- const redirectUrl = connData.redirect_url ||
1103
+ const rawRedirectUrl = connData.redirect_url ||
891
1104
  connData.connectionData?.val?.redirectUrl ||
892
1105
  fallbackRedirect;
1106
+ const redirectUrl = wrapRedirect(rawRedirectUrl, connData.id || null);
893
1107
  return {
894
1108
  providerSlug,
895
1109
  providerName,
@@ -225,9 +225,13 @@ export declare class StripeProjectsAdapter {
225
225
  getTools(): MuxoTool[];
226
226
  searchTools(query?: string, limit?: number): MuxoTool[];
227
227
  inspectTool(slug: string): MuxoTool | null;
228
+ hasProvider(providerSlug: string): boolean;
228
229
  private runStripeProjectsCli;
229
230
  private get hasLocalProjectsWorkdir();
230
231
  private provisioningAuditLog;
232
+ private hostedSites;
233
+ getHostedSiteHtml(slug: string, filePath?: string): string | null;
234
+ private attachHostingDeployment;
231
235
  getProvisioningAuditLog(limit?: number): StripeProvisioningAuditEntry[];
232
236
  private resolveStripeSecretKey;
233
237
  isLivemodeKey(apiKeyOverride?: string | null): boolean;