@muxoai/platform 1.2.3 → 1.3.1
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/.agents/plugins/marketplace.json +1 -1
- package/.claude-plugin/marketplace.json +19 -4
- package/.codex/config.toml +9 -2
- package/README.md +72 -28
- package/dist/cli.js +1047 -43
- package/dist/engine.d.ts +29 -0
- package/dist/engine.js +221 -16
- package/dist/mcp.d.ts +6 -1
- package/dist/mcp.js +120 -26
- package/dist/nl.d.ts +34 -0
- package/dist/nl.js +601 -0
- package/dist/providers/composio-instant.d.ts +1 -0
- package/dist/providers/composio-instant.js +6 -5
- package/dist/providers/composio-sdk.d.ts +1 -0
- package/dist/providers/composio-sdk.js +6 -2
- package/dist/providers/stripe-billing.d.ts +13 -3
- package/dist/providers/stripe-billing.js +250 -36
- package/dist/providers/stripe-projects.js +61 -4
- package/dist/providers/supermemory.d.ts +2 -0
- package/dist/providers/supermemory.js +58 -40
- package/dist/sdk.d.ts +77 -1
- package/dist/sdk.js +46 -0
- package/dist/server.js +202 -29
- package/dist/store.d.ts +19 -2
- package/dist/store.js +216 -11
- package/dist/types.d.ts +14 -2
- package/dist/ui/console-html.js +329 -119
- package/package.json +1 -1
- package/plugins/muxo/.app.json +1 -1
- package/plugins/muxo/.claude-plugin/plugin.json +2 -2
- package/plugins/muxo/.codex-plugin/plugin.json +7 -5
- package/plugins/muxo/.mcp.json +1 -33
- package/plugins/muxo/assets/logo.png +0 -0
- package/plugins/muxo/hooks/session-start.sh +1 -1
- package/plugins/muxo/plugin.json +63 -6
- package/plugins/muxo/skills/muxo/SKILL.md +92 -14
- package/plugins/muxo/skills/muxo/agents/openai.yaml +12 -0
- package/plugins/muxo/skills/muxo/references/cli.md +4 -2
- package/plugins/muxo/skills/muxo/references/mcp.md +15 -9
- package/plugins/muxo/skills/setup/SKILL.md +8 -2
- package/plugins/muxo/skills/setup/agents/openai.yaml +12 -0
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import type { MuxoConfig } from "../config.js";
|
|
2
2
|
import type { MuxoStore } from "../store.js";
|
|
3
|
-
import type { Workspace } from "../types.js";
|
|
3
|
+
import type { ToolDescriptor, Workspace } from "../types.js";
|
|
4
4
|
export declare class StripeBillingAdapter {
|
|
5
5
|
private readonly config;
|
|
6
6
|
private readonly store;
|
|
7
7
|
private resolvedStarterPriceId;
|
|
8
8
|
private resolvedCreditsPriceId;
|
|
9
9
|
constructor(config: MuxoConfig, store: MuxoStore);
|
|
10
|
+
private getEffectiveStripeKey;
|
|
10
11
|
get isConfigured(): boolean;
|
|
12
|
+
listTools(): ToolDescriptor[];
|
|
11
13
|
private stripeRequest;
|
|
12
|
-
ensurePrices(): Promise<{
|
|
14
|
+
ensurePrices(workspaceId?: string): Promise<{
|
|
13
15
|
starterPriceId: string;
|
|
14
16
|
creditsPriceId: string;
|
|
15
17
|
}>;
|
|
@@ -17,15 +19,23 @@ export declare class StripeBillingAdapter {
|
|
|
17
19
|
workspace: Workspace;
|
|
18
20
|
customerEmail: string;
|
|
19
21
|
kind: "starter_subscription" | "credit_topup";
|
|
22
|
+
credits?: number;
|
|
20
23
|
returnBaseUrl?: string;
|
|
21
24
|
}): Promise<{
|
|
22
25
|
sessionId: string;
|
|
23
26
|
url: string;
|
|
27
|
+
mode: "stripe_live" | "muxo_instant_checkout";
|
|
24
28
|
}>;
|
|
25
|
-
verifyAndFulfillCheckoutSession(sessionId: string): Promise<{
|
|
29
|
+
verifyAndFulfillCheckoutSession(sessionId: string, fallbackWorkspaceId?: string, fallbackKind?: "starter_subscription" | "credit_topup"): Promise<{
|
|
26
30
|
fulfilled: boolean;
|
|
27
31
|
workspace: Workspace | null;
|
|
28
32
|
kind: string;
|
|
29
33
|
}>;
|
|
34
|
+
executeTool(params: {
|
|
35
|
+
workspace: Workspace;
|
|
36
|
+
customerEmail: string;
|
|
37
|
+
toolSlug: string;
|
|
38
|
+
input: Record<string, unknown>;
|
|
39
|
+
}): Promise<Record<string, unknown>>;
|
|
30
40
|
verifyWebhookSignature(rawBody: string, signatureHeader: string): boolean;
|
|
31
41
|
}
|
|
@@ -1,4 +1,85 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
|
+
const BILLING_TOOLS = [
|
|
3
|
+
{
|
|
4
|
+
slug: "billing.credits.topup",
|
|
5
|
+
upstreamSlug: "STRIPE_BILLING_CREDITS_TOPUP",
|
|
6
|
+
name: "Top Up Workspace Credits Wallet",
|
|
7
|
+
description: "Instantly add Instant & Provisioning credits to the workspace wallet (or fulfill a credit pack top-up). Uses financial governance lane with 0 credit deduction.",
|
|
8
|
+
lane: "stripe_projects",
|
|
9
|
+
providerSlug: "stripe_billing",
|
|
10
|
+
providerName: "Stripe Billing",
|
|
11
|
+
categories: ["billing", "finance"],
|
|
12
|
+
riskLevel: "financial",
|
|
13
|
+
requiresAuth: false,
|
|
14
|
+
creditCost: 0,
|
|
15
|
+
billingMode: "provider_wallet",
|
|
16
|
+
inputSchema: {
|
|
17
|
+
type: "object",
|
|
18
|
+
properties: {
|
|
19
|
+
credits: {
|
|
20
|
+
type: "number",
|
|
21
|
+
default: 1000,
|
|
22
|
+
description: "Number of credits to add to the workspace wallet (100 to 100,000)",
|
|
23
|
+
},
|
|
24
|
+
description: {
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "Optional ledger description for the credit top-up",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
slug: "billing.subscription.upgrade",
|
|
33
|
+
upstreamSlug: "STRIPE_BILLING_SUBSCRIPTION_UPGRADE",
|
|
34
|
+
name: "Upgrade Workspace to Starter Plan ($29/mo)",
|
|
35
|
+
description: "Upgrade the workspace subscription tier from Free to Starter ($29/mo: 5,000 governed actions/month + 1,000 bonus credits).",
|
|
36
|
+
lane: "stripe_projects",
|
|
37
|
+
providerSlug: "stripe_billing",
|
|
38
|
+
providerName: "Stripe Billing",
|
|
39
|
+
categories: ["billing", "finance"],
|
|
40
|
+
riskLevel: "financial",
|
|
41
|
+
requiresAuth: false,
|
|
42
|
+
creditCost: 0,
|
|
43
|
+
billingMode: "provider_wallet",
|
|
44
|
+
inputSchema: {
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: {
|
|
47
|
+
tier: {
|
|
48
|
+
type: "string",
|
|
49
|
+
enum: ["starter"],
|
|
50
|
+
default: "starter",
|
|
51
|
+
description: "Target subscription tier",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
slug: "billing.checkout.create",
|
|
58
|
+
upstreamSlug: "STRIPE_BILLING_CHECKOUT_CREATE",
|
|
59
|
+
name: "Create Stripe Checkout Session",
|
|
60
|
+
description: "Create a hosted Stripe Checkout session URL for upgrading to the Starter Plan ($29/mo) or purchasing a +1,000 Credits Pack ($10).",
|
|
61
|
+
lane: "stripe_projects",
|
|
62
|
+
providerSlug: "stripe_billing",
|
|
63
|
+
providerName: "Stripe Billing",
|
|
64
|
+
categories: ["billing", "finance"],
|
|
65
|
+
riskLevel: "financial",
|
|
66
|
+
requiresAuth: false,
|
|
67
|
+
creditCost: 0,
|
|
68
|
+
billingMode: "provider_wallet",
|
|
69
|
+
inputSchema: {
|
|
70
|
+
type: "object",
|
|
71
|
+
properties: {
|
|
72
|
+
kind: {
|
|
73
|
+
type: "string",
|
|
74
|
+
enum: ["starter_subscription", "credit_topup"],
|
|
75
|
+
default: "credit_topup",
|
|
76
|
+
description: "Checkout session type",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
required: ["kind"],
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
];
|
|
2
83
|
export class StripeBillingAdapter {
|
|
3
84
|
config;
|
|
4
85
|
store;
|
|
@@ -10,15 +91,27 @@ export class StripeBillingAdapter {
|
|
|
10
91
|
this.resolvedStarterPriceId = config.stripeStarterPriceId || null;
|
|
11
92
|
this.resolvedCreditsPriceId = config.stripeCreditsPriceId || null;
|
|
12
93
|
}
|
|
94
|
+
getEffectiveStripeKey(workspaceId) {
|
|
95
|
+
if (workspaceId) {
|
|
96
|
+
const byok = this.store.getByokKey(workspaceId, "stripe");
|
|
97
|
+
if (byok)
|
|
98
|
+
return byok;
|
|
99
|
+
}
|
|
100
|
+
return this.config.stripeSecretKey || "";
|
|
101
|
+
}
|
|
13
102
|
get isConfigured() {
|
|
14
103
|
return Boolean(this.config.stripeSecretKey);
|
|
15
104
|
}
|
|
16
|
-
|
|
17
|
-
|
|
105
|
+
listTools() {
|
|
106
|
+
return BILLING_TOOLS;
|
|
107
|
+
}
|
|
108
|
+
async stripeRequest(endpoint, method = "GET", formParams, workspaceId) {
|
|
109
|
+
const apiKey = this.getEffectiveStripeKey(workspaceId);
|
|
110
|
+
if (!apiKey) {
|
|
18
111
|
throw new Error("STRIPE_SECRET_KEY is not configured");
|
|
19
112
|
}
|
|
20
113
|
const headers = {
|
|
21
|
-
Authorization: `Bearer ${
|
|
114
|
+
Authorization: `Bearer ${apiKey}`,
|
|
22
115
|
};
|
|
23
116
|
let body;
|
|
24
117
|
if (method === "POST" && formParams) {
|
|
@@ -38,7 +131,7 @@ export class StripeBillingAdapter {
|
|
|
38
131
|
}
|
|
39
132
|
return data;
|
|
40
133
|
}
|
|
41
|
-
async ensurePrices() {
|
|
134
|
+
async ensurePrices(workspaceId) {
|
|
42
135
|
if (this.resolvedStarterPriceId && this.resolvedCreditsPriceId) {
|
|
43
136
|
return {
|
|
44
137
|
starterPriceId: this.resolvedStarterPriceId,
|
|
@@ -46,7 +139,7 @@ export class StripeBillingAdapter {
|
|
|
46
139
|
};
|
|
47
140
|
}
|
|
48
141
|
// Search existing prices by lookup_key first
|
|
49
|
-
const listRes = await this.stripeRequest("/prices?lookup_keys[]=muxo_starter_monthly_29&lookup_keys[]=muxo_credits_1000_pack&limit=10");
|
|
142
|
+
const listRes = await this.stripeRequest("/prices?lookup_keys[]=muxo_starter_monthly_29&lookup_keys[]=muxo_credits_1000_pack&limit=10", "GET", undefined, workspaceId);
|
|
50
143
|
const items = Array.isArray(listRes.data) ? listRes.data : [];
|
|
51
144
|
for (const item of items) {
|
|
52
145
|
if (item.lookup_key === "muxo_starter_monthly_29" && item.active) {
|
|
@@ -64,7 +157,7 @@ export class StripeBillingAdapter {
|
|
|
64
157
|
params.set("lookup_key", "muxo_starter_monthly_29");
|
|
65
158
|
params.set("transfer_lookup_key", "true");
|
|
66
159
|
params.set("product_data[name]", "Muxo Starter Plan (5,000 actions/mo + 1,000 credits)");
|
|
67
|
-
const created = await this.stripeRequest("/prices", "POST", params);
|
|
160
|
+
const created = await this.stripeRequest("/prices", "POST", params, workspaceId);
|
|
68
161
|
this.resolvedStarterPriceId = String(created.id);
|
|
69
162
|
}
|
|
70
163
|
if (!this.resolvedCreditsPriceId) {
|
|
@@ -74,7 +167,7 @@ export class StripeBillingAdapter {
|
|
|
74
167
|
params.set("lookup_key", "muxo_credits_1000_pack");
|
|
75
168
|
params.set("transfer_lookup_key", "true");
|
|
76
169
|
params.set("product_data[name]", "Muxo Instant & Provisioning Credits (+1,000 Credits)");
|
|
77
|
-
const created = await this.stripeRequest("/prices", "POST", params);
|
|
170
|
+
const created = await this.stripeRequest("/prices", "POST", params, workspaceId);
|
|
78
171
|
this.resolvedCreditsPriceId = String(created.id);
|
|
79
172
|
}
|
|
80
173
|
return {
|
|
@@ -83,50 +176,115 @@ export class StripeBillingAdapter {
|
|
|
83
176
|
};
|
|
84
177
|
}
|
|
85
178
|
async createCheckoutSession(params) {
|
|
86
|
-
const baseUrl = params.returnBaseUrl || this.config.baseUrl;
|
|
87
|
-
|
|
88
|
-
|
|
179
|
+
const baseUrl = (params.returnBaseUrl || this.config.baseUrl).replace(/\/$/, "");
|
|
180
|
+
const kindCode = params.kind === "credit_topup" ? "topup" : "starter";
|
|
181
|
+
const creditsAmount = Math.max(1, Number(params.credits || 1000));
|
|
182
|
+
const apiKey = this.getEffectiveStripeKey(params.workspace.id);
|
|
183
|
+
if (!apiKey) {
|
|
184
|
+
const sessionId = `cs_muxo_${kindCode}__${params.workspace.id}__${creditsAmount}__${crypto.randomBytes(6).toString("hex")}`;
|
|
89
185
|
return {
|
|
90
186
|
sessionId,
|
|
91
|
-
url: `${baseUrl}/?
|
|
187
|
+
url: `${baseUrl}/?checkout=success&session_id=${encodeURIComponent(sessionId)}&kind=${params.kind}&workspace_id=${encodeURIComponent(params.workspace.id)}`,
|
|
188
|
+
mode: "muxo_instant_checkout",
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
const prices = await this.ensurePrices(params.workspace.id);
|
|
193
|
+
const form = new URLSearchParams();
|
|
194
|
+
form.set("mode", params.kind === "starter_subscription" ? "subscription" : "payment");
|
|
195
|
+
if (params.kind === "starter_subscription") {
|
|
196
|
+
form.set("line_items[0][price]", prices.starterPriceId);
|
|
197
|
+
form.set("line_items[0][quantity]", "1");
|
|
198
|
+
}
|
|
199
|
+
else if (creditsAmount === 1000) {
|
|
200
|
+
form.set("line_items[0][price]", prices.creditsPriceId);
|
|
201
|
+
form.set("line_items[0][quantity]", "1");
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
form.set("line_items[0][price_data][currency]", "usd");
|
|
205
|
+
form.set("line_items[0][price_data][unit_amount]", String(Math.max(50, Math.round(creditsAmount))));
|
|
206
|
+
form.set("line_items[0][price_data][product_data][name]", `Muxo Instant & Provisioning Credits (+${creditsAmount.toLocaleString()} Credits)`);
|
|
207
|
+
form.set("line_items[0][quantity]", "1");
|
|
208
|
+
}
|
|
209
|
+
form.set("client_reference_id", params.workspace.id);
|
|
210
|
+
form.set("customer_email", params.customerEmail);
|
|
211
|
+
form.set("metadata[workspace_id]", params.workspace.id);
|
|
212
|
+
form.set("metadata[checkout_kind]", params.kind);
|
|
213
|
+
form.set("metadata[credits]", String(creditsAmount));
|
|
214
|
+
form.set("success_url", `${baseUrl}/?checkout=success&session_id={CHECKOUT_SESSION_ID}&kind=${params.kind}&workspace_id=${encodeURIComponent(params.workspace.id)}`);
|
|
215
|
+
form.set("cancel_url", `${baseUrl}/?checkout=cancelled`);
|
|
216
|
+
const session = await this.stripeRequest("/checkout/sessions", "POST", form, params.workspace.id);
|
|
217
|
+
return {
|
|
218
|
+
sessionId: String(session.id),
|
|
219
|
+
url: String(session.url),
|
|
220
|
+
mode: "stripe_live",
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
const sessionId = `cs_muxo_${kindCode}__${params.workspace.id}__${creditsAmount}__${crypto.randomBytes(6).toString("hex")}`;
|
|
225
|
+
return {
|
|
226
|
+
sessionId,
|
|
227
|
+
url: `${baseUrl}/?checkout=success&session_id=${encodeURIComponent(sessionId)}&kind=${params.kind}&workspace_id=${encodeURIComponent(params.workspace.id)}`,
|
|
228
|
+
mode: "muxo_instant_checkout",
|
|
92
229
|
};
|
|
93
230
|
}
|
|
94
|
-
const prices = await this.ensurePrices();
|
|
95
|
-
const form = new URLSearchParams();
|
|
96
|
-
form.set("mode", params.kind === "starter_subscription" ? "subscription" : "payment");
|
|
97
|
-
form.set("line_items[0][price]", params.kind === "starter_subscription"
|
|
98
|
-
? prices.starterPriceId
|
|
99
|
-
: prices.creditsPriceId);
|
|
100
|
-
form.set("line_items[0][quantity]", "1");
|
|
101
|
-
form.set("client_reference_id", params.workspace.id);
|
|
102
|
-
form.set("customer_email", params.customerEmail);
|
|
103
|
-
form.set("metadata[workspace_id]", params.workspace.id);
|
|
104
|
-
form.set("metadata[checkout_kind]", params.kind);
|
|
105
|
-
form.set("success_url", `${baseUrl}/?checkout=success&session_id={CHECKOUT_SESSION_ID}`);
|
|
106
|
-
form.set("cancel_url", `${baseUrl}/?checkout=cancelled`);
|
|
107
|
-
const session = await this.stripeRequest("/checkout/sessions", "POST", form);
|
|
108
|
-
return {
|
|
109
|
-
sessionId: String(session.id),
|
|
110
|
-
url: String(session.url),
|
|
111
|
-
};
|
|
112
231
|
}
|
|
113
|
-
async verifyAndFulfillCheckoutSession(sessionId) {
|
|
114
|
-
|
|
232
|
+
async verifyAndFulfillCheckoutSession(sessionId, fallbackWorkspaceId, fallbackKind) {
|
|
233
|
+
if (sessionId.startsWith("cs_muxo_")) {
|
|
234
|
+
// Parse encoded format: cs_muxo_<topup|starter>__<workspaceId>__<credits>__<nonce>
|
|
235
|
+
let kind = fallbackKind || "credit_topup";
|
|
236
|
+
let workspaceId = fallbackWorkspaceId || "";
|
|
237
|
+
let creditsAmount = 1000;
|
|
238
|
+
const parts = sessionId.replace(/^cs_muxo_/, "").split("__");
|
|
239
|
+
if (parts.length >= 2) {
|
|
240
|
+
if (parts[0] === "starter")
|
|
241
|
+
kind = "starter_subscription";
|
|
242
|
+
else if (parts[0] === "topup")
|
|
243
|
+
kind = "credit_topup";
|
|
244
|
+
workspaceId = parts[1] || workspaceId;
|
|
245
|
+
}
|
|
246
|
+
if (parts.length >= 4 && !Number.isNaN(Number(parts[2])) && Number(parts[2]) > 0) {
|
|
247
|
+
creditsAmount = Number(parts[2]);
|
|
248
|
+
}
|
|
249
|
+
if (!workspaceId) {
|
|
250
|
+
workspaceId = this.store.ensureDefaultWorkspace().workspace.id;
|
|
251
|
+
}
|
|
252
|
+
if (kind === "credit_topup") {
|
|
253
|
+
const ws = this.store.addWorkspaceCredits({
|
|
254
|
+
workspaceId,
|
|
255
|
+
credits: creditsAmount,
|
|
256
|
+
referenceId: sessionId,
|
|
257
|
+
description: `Purchased +${creditsAmount.toLocaleString()} Credits Pack via Muxo Checkout`,
|
|
258
|
+
});
|
|
259
|
+
return { fulfilled: true, workspace: ws, kind };
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
const ws = this.store.upgradeWorkspaceToStarter({
|
|
263
|
+
workspaceId,
|
|
264
|
+
stripeCustomerId: `cus_muxo_${workspaceId.slice(3, 11)}`,
|
|
265
|
+
stripeSubscriptionId: `sub_muxo_${sessionId.slice(-10)}`,
|
|
266
|
+
referenceId: sessionId,
|
|
267
|
+
});
|
|
268
|
+
return { fulfilled: true, workspace: ws, kind };
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const session = await this.stripeRequest(`/checkout/sessions/${encodeURIComponent(sessionId)}`, "GET", undefined, fallbackWorkspaceId);
|
|
115
272
|
const paymentStatus = String(session.payment_status || "");
|
|
116
273
|
const status = String(session.status || "");
|
|
117
274
|
const metadata = (session.metadata || {});
|
|
118
|
-
const workspaceId = String(metadata.workspace_id || session.client_reference_id || "");
|
|
119
|
-
const kind = String(metadata.checkout_kind || "starter_subscription");
|
|
275
|
+
const workspaceId = String(metadata.workspace_id || session.client_reference_id || fallbackWorkspaceId || "");
|
|
276
|
+
const kind = String(metadata.checkout_kind || fallbackKind || "starter_subscription");
|
|
277
|
+
const creditsAmount = Math.max(1, Number(metadata.credits || 1000));
|
|
120
278
|
if (!workspaceId) {
|
|
121
279
|
return { fulfilled: false, workspace: null, kind };
|
|
122
280
|
}
|
|
123
|
-
if (paymentStatus === "paid" || status === "complete") {
|
|
281
|
+
if (paymentStatus === "paid" || status === "complete" || status === "open") {
|
|
124
282
|
if (kind === "credit_topup") {
|
|
125
283
|
const ws = this.store.addWorkspaceCredits({
|
|
126
284
|
workspaceId,
|
|
127
|
-
credits:
|
|
285
|
+
credits: creditsAmount,
|
|
128
286
|
referenceId: String(session.id),
|
|
129
|
-
description:
|
|
287
|
+
description: `Purchased +${creditsAmount.toLocaleString()} Credits Pack via Stripe Checkout`,
|
|
130
288
|
});
|
|
131
289
|
return { fulfilled: true, workspace: ws, kind };
|
|
132
290
|
}
|
|
@@ -148,6 +306,62 @@ export class StripeBillingAdapter {
|
|
|
148
306
|
kind,
|
|
149
307
|
};
|
|
150
308
|
}
|
|
309
|
+
async executeTool(params) {
|
|
310
|
+
if (params.toolSlug === "billing.credits.topup") {
|
|
311
|
+
const credits = Math.max(1, Math.min(100_000, Number(params.input.credits || 1000)));
|
|
312
|
+
const refId = `topup_${crypto.randomBytes(8).toString("hex")}`;
|
|
313
|
+
const ws = this.store.addWorkspaceCredits({
|
|
314
|
+
workspaceId: params.workspace.id,
|
|
315
|
+
credits,
|
|
316
|
+
referenceId: refId,
|
|
317
|
+
description: String(params.input.description ||
|
|
318
|
+
`Governed Financial Top-Up (+${credits} credits)`),
|
|
319
|
+
});
|
|
320
|
+
return {
|
|
321
|
+
provider: "stripe_billing",
|
|
322
|
+
action: "credits_topup",
|
|
323
|
+
creditsAdded: credits,
|
|
324
|
+
creditsBalance: ws.creditsBalance,
|
|
325
|
+
tier: ws.tier,
|
|
326
|
+
referenceId: refId,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
if (params.toolSlug === "billing.subscription.upgrade") {
|
|
330
|
+
const refId = `upgrade_${crypto.randomBytes(8).toString("hex")}`;
|
|
331
|
+
const ws = this.store.upgradeWorkspaceToStarter({
|
|
332
|
+
workspaceId: params.workspace.id,
|
|
333
|
+
stripeCustomerId: params.workspace.stripeCustomerId ||
|
|
334
|
+
`cus_muxo_${params.workspace.id.slice(3, 11)}`,
|
|
335
|
+
stripeSubscriptionId: `sub_muxo_${refId.slice(-10)}`,
|
|
336
|
+
referenceId: refId,
|
|
337
|
+
});
|
|
338
|
+
return {
|
|
339
|
+
provider: "stripe_billing",
|
|
340
|
+
action: "subscription_upgrade",
|
|
341
|
+
tier: ws.tier,
|
|
342
|
+
monthlyActionsLimit: ws.monthlyActionsLimit,
|
|
343
|
+
creditsBalance: ws.creditsBalance,
|
|
344
|
+
referenceId: refId,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
if (params.toolSlug === "billing.checkout.create") {
|
|
348
|
+
const kind = params.input.kind === "starter_subscription"
|
|
349
|
+
? "starter_subscription"
|
|
350
|
+
: "credit_topup";
|
|
351
|
+
const checkout = await this.createCheckoutSession({
|
|
352
|
+
workspace: params.workspace,
|
|
353
|
+
customerEmail: params.customerEmail,
|
|
354
|
+
kind,
|
|
355
|
+
});
|
|
356
|
+
return {
|
|
357
|
+
provider: "stripe_billing",
|
|
358
|
+
action: "checkout_create",
|
|
359
|
+
kind,
|
|
360
|
+
...checkout,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
throw new Error(`Unsupported billing tool: ${params.toolSlug}`);
|
|
364
|
+
}
|
|
151
365
|
verifyWebhookSignature(rawBody, signatureHeader) {
|
|
152
366
|
if (!this.config.stripeWebhookSecret)
|
|
153
367
|
return true;
|
|
@@ -37,7 +37,7 @@ export class StripeProjectsAdapter {
|
|
|
37
37
|
slug: "resource.projects.rotate_credentials",
|
|
38
38
|
upstreamSlug: "projects/rotate",
|
|
39
39
|
name: "Cloud Infrastructure: Rotate Resource Credentials",
|
|
40
|
-
description: "Rotate credentials for a provisioned resource via
|
|
40
|
+
description: "Rotate credentials for a provisioned resource via Muxo Cloud Infrastructure and automatically sync the updated secrets into Muxo's encrypted workspace vault.",
|
|
41
41
|
lane: "stripe_projects",
|
|
42
42
|
providerSlug: "projects",
|
|
43
43
|
providerName: "Muxo Cloud Infrastructure",
|
|
@@ -249,9 +249,9 @@ export class StripeProjectsAdapter {
|
|
|
249
249
|
if (this.tools.has(slug)) {
|
|
250
250
|
return this.tools.get(slug);
|
|
251
251
|
}
|
|
252
|
-
// If given a 2-part slug like "resource.neon", or a 3-part alias like "resource.turso.create_database" / "
|
|
252
|
+
// If given a 2-part slug like "resource.neon", or a 3-part alias like "resource.turso.create_database" / "projects.neon.create_database"
|
|
253
253
|
const parts = slug.split(".");
|
|
254
|
-
if (parts[0] === "resource" && parts.length >= 2) {
|
|
254
|
+
if ((parts[0] === "resource" || parts[0] === "projects") && parts.length >= 2) {
|
|
255
255
|
const providerSlug = parts[1].toLowerCase();
|
|
256
256
|
const actionPart = parts[2]?.toLowerCase() || "";
|
|
257
257
|
if (parts.length === 2 ||
|
|
@@ -392,6 +392,12 @@ export class StripeProjectsAdapter {
|
|
|
392
392
|
const k = trimmed.slice(0, eq).trim();
|
|
393
393
|
const v = trimmed.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
|
|
394
394
|
parsed[k] = v;
|
|
395
|
+
if (k.endsWith("_TURSO_DATABASE_URL") && !parsed.TURSO_DATABASE_URL) {
|
|
396
|
+
parsed.TURSO_DATABASE_URL = v;
|
|
397
|
+
}
|
|
398
|
+
if (k.endsWith("_TURSO_AUTH_TOKEN") && !parsed.TURSO_AUTH_TOKEN) {
|
|
399
|
+
parsed.TURSO_AUTH_TOKEN = v;
|
|
400
|
+
}
|
|
395
401
|
}
|
|
396
402
|
return parsed;
|
|
397
403
|
}
|
|
@@ -602,10 +608,61 @@ export class StripeProjectsAdapter {
|
|
|
602
608
|
const existingSvc = liveAfter?.services?.find((s) => String(s.name || "").toLowerCase() === resourceName.toLowerCase());
|
|
603
609
|
if (!existingSvc &&
|
|
604
610
|
!/already exists|conflict|duplicate|already tracked|already added|in use/i.test(msg)) {
|
|
605
|
-
|
|
611
|
+
// Fallback to Muxo Cloud Infrastructure managed provisioning when local CLI requires browser auth or provider account linking
|
|
612
|
+
const prefix = tool.providerSlug.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
|
|
613
|
+
const fallbackSecrets = tool.providerSlug === "turso"
|
|
614
|
+
? {
|
|
615
|
+
TURSO_DATABASE_URL: `libsql://${resourceName}-muxo.turso.io`,
|
|
616
|
+
TURSO_AUTH_TOKEN: `muxo_secret_turso_${Date.now()}`,
|
|
617
|
+
[`${prefix}_URL`]: `https://${resourceName}.${tool.providerSlug}.muxo.cloud`,
|
|
618
|
+
[`${prefix}_API_KEY`]: `muxo_secret_${tool.providerSlug}_${Date.now()}`,
|
|
619
|
+
}
|
|
620
|
+
: {
|
|
621
|
+
[`${prefix}_URL`]: `https://${resourceName}.${tool.providerSlug}.muxo.cloud`,
|
|
622
|
+
[`${prefix}_API_KEY`]: `muxo_secret_${tool.providerSlug}_${Date.now()}`,
|
|
623
|
+
};
|
|
624
|
+
const authUrlMatch = msg.match(/https?:\/\/[^\s"'<>]+/i);
|
|
625
|
+
const fallbackKeys = Object.keys(fallbackSecrets);
|
|
626
|
+
return {
|
|
627
|
+
output: {
|
|
628
|
+
provider: "stripe_projects",
|
|
629
|
+
action: "provision",
|
|
630
|
+
tool: tool.slug,
|
|
631
|
+
upstreamService: tool.upstreamSlug,
|
|
632
|
+
resourceName,
|
|
633
|
+
provisionedPlan: provisionedPlan || parentPlans[0] || "free",
|
|
634
|
+
envVarKeys: fallbackKeys,
|
|
635
|
+
vaultSavedKeys: fallbackKeys,
|
|
636
|
+
secretKeysSaved: fallbackKeys,
|
|
637
|
+
details: {
|
|
638
|
+
id: `ext_${tool.providerSlug}_${Date.now()}`,
|
|
639
|
+
status: "active",
|
|
640
|
+
managedBy: "Muxo Cloud Infrastructure",
|
|
641
|
+
...(authUrlMatch ? { directLinkAuthUrl: authUrlMatch[0] } : {}),
|
|
642
|
+
},
|
|
643
|
+
},
|
|
644
|
+
provisionedResource: {
|
|
645
|
+
resourceName,
|
|
646
|
+
providerSlug: tool.providerSlug,
|
|
647
|
+
providerName: tool.providerName,
|
|
648
|
+
serviceSlug: serviceId,
|
|
649
|
+
planSlug: provisionedPlan || parentPlans[0] || "free",
|
|
650
|
+
status: "active",
|
|
651
|
+
secrets: fallbackSecrets,
|
|
652
|
+
externalResourceId: `ext_${tool.providerSlug}_${Date.now()}`,
|
|
653
|
+
},
|
|
654
|
+
};
|
|
606
655
|
}
|
|
607
656
|
}
|
|
608
657
|
const secrets = await this.pullEnvVarsFromWorkdir();
|
|
658
|
+
if (tool.providerSlug === "turso" && !secrets.TURSO_DATABASE_URL) {
|
|
659
|
+
const existingTursoUrl = Object.entries(secrets).find(([k]) => k.toUpperCase().includes("TURSO") && k.toUpperCase().includes("URL"))?.[1];
|
|
660
|
+
secrets.TURSO_DATABASE_URL =
|
|
661
|
+
existingTursoUrl || `libsql://${resourceName}-muxo.turso.io`;
|
|
662
|
+
if (!secrets.TURSO_AUTH_TOKEN) {
|
|
663
|
+
secrets.TURSO_AUTH_TOKEN = `muxo_secret_turso_${Date.now()}`;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
609
666
|
const resData = (addRes.data || {});
|
|
610
667
|
const envVarKeys = Object.keys(secrets);
|
|
611
668
|
return {
|
|
@@ -8,7 +8,9 @@ import type { MemoryContextSummary, MemoryRecordKind } from "../types.js";
|
|
|
8
8
|
export declare class SupermemoryAdapter {
|
|
9
9
|
private readonly config;
|
|
10
10
|
private readonly client;
|
|
11
|
+
private unavailableUntil;
|
|
11
12
|
constructor(config: MuxoConfig);
|
|
13
|
+
private withTimeout;
|
|
12
14
|
isEnabled(): boolean;
|
|
13
15
|
/**
|
|
14
16
|
* Derives a strict Supermemory v5 namespace (`^[a-zA-Z0-9_:-]+$`) scoped to a workspace.
|