@muxoai/sdk 1.2.2 → 1.3.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/.agents/plugins/marketplace.json +22 -0
- package/.claude-plugin/marketplace.json +17 -0
- package/.codex/config.toml +5 -0
- package/ARCHITECTURE.md +111 -0
- package/README.md +57 -28
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +894 -0
- package/dist/config.d.ts +20 -0
- package/dist/config.js +89 -0
- package/dist/engine.d.ts +156 -0
- package/dist/engine.js +876 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/mcp.d.ts +45 -0
- package/dist/mcp.js +914 -0
- package/dist/nl.d.ts +34 -0
- package/dist/nl.js +577 -0
- package/dist/providers/composio-instant.d.ts +14 -0
- package/dist/providers/composio-instant.js +814 -0
- package/dist/providers/composio-sdk.d.ts +41 -0
- package/dist/providers/composio-sdk.js +572 -0
- package/dist/providers/microsoft-governance.d.ts +66 -0
- package/dist/providers/microsoft-governance.js +415 -0
- package/dist/providers/stripe-billing.d.ts +41 -0
- package/dist/providers/stripe-billing.js +372 -0
- package/dist/providers/stripe-projects.d.ts +53 -0
- package/dist/providers/stripe-projects.js +636 -0
- package/dist/providers/supermemory.d.ts +64 -0
- package/dist/providers/supermemory.js +224 -0
- package/dist/sdk.d.ts +84 -1
- package/dist/sdk.js +53 -0
- package/dist/server.d.ts +10 -0
- package/dist/server.js +1277 -0
- package/dist/store.d.ts +216 -0
- package/dist/store.js +1449 -0
- package/dist/types.d.ts +14 -2
- package/dist/ui/console-html.d.ts +2 -0
- package/dist/ui/console-html.js +2343 -0
- package/package.json +66 -17
- package/plugins/muxo/.app.json +8 -0
- package/plugins/muxo/.claude-plugin/plugin.json +16 -0
- package/plugins/muxo/.codex-plugin/plugin.json +55 -0
- package/plugins/muxo/.mcp.json +40 -0
- package/plugins/muxo/assets/logo.png +0 -0
- package/plugins/muxo/assets/logo.svg +6 -0
- package/plugins/muxo/hooks/hooks.json +27 -0
- package/plugins/muxo/hooks/session-start.sh +85 -0
- package/plugins/muxo/hooks/user-prompt-submit.sh +45 -0
- package/plugins/muxo/mcp.json +38 -0
- package/plugins/muxo/plugin.json +59 -0
- package/plugins/muxo/skills/muxo/SKILL.md +25 -0
- package/plugins/muxo/skills/muxo/references/cli.md +57 -0
- package/plugins/muxo/skills/muxo/references/mcp.md +25 -0
- package/plugins/muxo/skills/setup/SKILL.md +28 -0
- package/src/catalogues/stripe-projects-catalog.json +9832 -0
- package/vendor/microsoft-governance/README.md +363 -0
- package/vendor/microsoft-governance/dist/audit.d.ts +26 -0
- package/vendor/microsoft-governance/dist/audit.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/audit.js +107 -0
- package/vendor/microsoft-governance/dist/audit.js.map +1 -0
- package/vendor/microsoft-governance/dist/cascade-containment.d.ts +84 -0
- package/vendor/microsoft-governance/dist/cascade-containment.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/cascade-containment.js +387 -0
- package/vendor/microsoft-governance/dist/cascade-containment.js.map +1 -0
- package/vendor/microsoft-governance/dist/client.d.ts +34 -0
- package/vendor/microsoft-governance/dist/client.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/client.js +112 -0
- package/vendor/microsoft-governance/dist/client.js.map +1 -0
- package/vendor/microsoft-governance/dist/context-poisoning.d.ts +58 -0
- package/vendor/microsoft-governance/dist/context-poisoning.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/context-poisoning.js +410 -0
- package/vendor/microsoft-governance/dist/context-poisoning.js.map +1 -0
- package/vendor/microsoft-governance/dist/credential-vault.d.ts +213 -0
- package/vendor/microsoft-governance/dist/credential-vault.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/credential-vault.js +567 -0
- package/vendor/microsoft-governance/dist/credential-vault.js.map +1 -0
- package/vendor/microsoft-governance/dist/discovery.d.ts +80 -0
- package/vendor/microsoft-governance/dist/discovery.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/discovery.js +404 -0
- package/vendor/microsoft-governance/dist/discovery.js.map +1 -0
- package/vendor/microsoft-governance/dist/encryption/channel.d.ts +29 -0
- package/vendor/microsoft-governance/dist/encryption/channel.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/encryption/channel.js +78 -0
- package/vendor/microsoft-governance/dist/encryption/channel.js.map +1 -0
- package/vendor/microsoft-governance/dist/encryption/index.d.ts +9 -0
- package/vendor/microsoft-governance/dist/encryption/index.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/encryption/index.js +23 -0
- package/vendor/microsoft-governance/dist/encryption/index.js.map +1 -0
- package/vendor/microsoft-governance/dist/encryption/mesh-client.d.ts +267 -0
- package/vendor/microsoft-governance/dist/encryption/mesh-client.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/encryption/mesh-client.js +1001 -0
- package/vendor/microsoft-governance/dist/encryption/mesh-client.js.map +1 -0
- package/vendor/microsoft-governance/dist/encryption/ratchet.d.ts +38 -0
- package/vendor/microsoft-governance/dist/encryption/ratchet.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/encryption/ratchet.js +223 -0
- package/vendor/microsoft-governance/dist/encryption/ratchet.js.map +1 -0
- package/vendor/microsoft-governance/dist/encryption/registry-client.d.ts +136 -0
- package/vendor/microsoft-governance/dist/encryption/registry-client.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/encryption/registry-client.js +369 -0
- package/vendor/microsoft-governance/dist/encryption/registry-client.js.map +1 -0
- package/vendor/microsoft-governance/dist/encryption/x3dh.d.ts +80 -0
- package/vendor/microsoft-governance/dist/encryption/x3dh.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/encryption/x3dh.js +238 -0
- package/vendor/microsoft-governance/dist/encryption/x3dh.js.map +1 -0
- package/vendor/microsoft-governance/dist/framework-adapter.d.ts +63 -0
- package/vendor/microsoft-governance/dist/framework-adapter.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/framework-adapter.js +253 -0
- package/vendor/microsoft-governance/dist/framework-adapter.js.map +1 -0
- package/vendor/microsoft-governance/dist/identity.d.ts +124 -0
- package/vendor/microsoft-governance/dist/identity.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/identity.js +446 -0
- package/vendor/microsoft-governance/dist/identity.js.map +1 -0
- package/vendor/microsoft-governance/dist/index.d.ts +39 -0
- package/vendor/microsoft-governance/dist/index.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/index.js +95 -0
- package/vendor/microsoft-governance/dist/index.js.map +1 -0
- package/vendor/microsoft-governance/dist/kill-switch.d.ts +22 -0
- package/vendor/microsoft-governance/dist/kill-switch.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/kill-switch.js +60 -0
- package/vendor/microsoft-governance/dist/kill-switch.js.map +1 -0
- package/vendor/microsoft-governance/dist/lifecycle.d.ts +50 -0
- package/vendor/microsoft-governance/dist/lifecycle.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/lifecycle.js +113 -0
- package/vendor/microsoft-governance/dist/lifecycle.js.map +1 -0
- package/vendor/microsoft-governance/dist/mcp.d.ts +41 -0
- package/vendor/microsoft-governance/dist/mcp.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/mcp.js +233 -0
- package/vendor/microsoft-governance/dist/mcp.js.map +1 -0
- package/vendor/microsoft-governance/dist/metrics.d.ts +123 -0
- package/vendor/microsoft-governance/dist/metrics.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/metrics.js +289 -0
- package/vendor/microsoft-governance/dist/metrics.js.map +1 -0
- package/vendor/microsoft-governance/dist/oci-manifest.d.ts +49 -0
- package/vendor/microsoft-governance/dist/oci-manifest.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/oci-manifest.js +182 -0
- package/vendor/microsoft-governance/dist/oci-manifest.js.map +1 -0
- package/vendor/microsoft-governance/dist/policy-backends/cedar.d.ts +15 -0
- package/vendor/microsoft-governance/dist/policy-backends/cedar.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/policy-backends/cedar.js +88 -0
- package/vendor/microsoft-governance/dist/policy-backends/cedar.js.map +1 -0
- package/vendor/microsoft-governance/dist/policy-backends/opa.d.ts +17 -0
- package/vendor/microsoft-governance/dist/policy-backends/opa.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/policy-backends/opa.js +74 -0
- package/vendor/microsoft-governance/dist/policy-backends/opa.js.map +1 -0
- package/vendor/microsoft-governance/dist/policy.d.ts +77 -0
- package/vendor/microsoft-governance/dist/policy.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/policy.js +760 -0
- package/vendor/microsoft-governance/dist/policy.js.map +1 -0
- package/vendor/microsoft-governance/dist/prompt-defense.d.ts +37 -0
- package/vendor/microsoft-governance/dist/prompt-defense.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/prompt-defense.js +229 -0
- package/vendor/microsoft-governance/dist/prompt-defense.js.map +1 -0
- package/vendor/microsoft-governance/dist/protocol-facets.d.ts +87 -0
- package/vendor/microsoft-governance/dist/protocol-facets.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/protocol-facets.js +728 -0
- package/vendor/microsoft-governance/dist/protocol-facets.js.map +1 -0
- package/vendor/microsoft-governance/dist/rings.d.ts +17 -0
- package/vendor/microsoft-governance/dist/rings.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/rings.js +61 -0
- package/vendor/microsoft-governance/dist/rings.js.map +1 -0
- package/vendor/microsoft-governance/dist/sandbox.d.ts +61 -0
- package/vendor/microsoft-governance/dist/sandbox.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/sandbox.js +199 -0
- package/vendor/microsoft-governance/dist/sandbox.js.map +1 -0
- package/vendor/microsoft-governance/dist/surface-parity.d.ts +45 -0
- package/vendor/microsoft-governance/dist/surface-parity.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/surface-parity.js +216 -0
- package/vendor/microsoft-governance/dist/surface-parity.js.map +1 -0
- package/vendor/microsoft-governance/dist/trust.d.ts +28 -0
- package/vendor/microsoft-governance/dist/trust.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/trust.js +209 -0
- package/vendor/microsoft-governance/dist/trust.js.map +1 -0
- package/vendor/microsoft-governance/dist/types.d.ts +422 -0
- package/vendor/microsoft-governance/dist/types.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/types.js +29 -0
- package/vendor/microsoft-governance/dist/types.js.map +1 -0
- package/vendor/microsoft-governance/dist/verify.d.ts +135 -0
- package/vendor/microsoft-governance/dist/verify.d.ts.map +1 -0
- package/vendor/microsoft-governance/dist/verify.js +356 -0
- package/vendor/microsoft-governance/dist/verify.js.map +1 -0
- package/vendor/microsoft-governance/package.json +64 -0
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { promisify } from "node:util";
|
|
5
|
+
import { ROOT_DIR } from "../config.js";
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
export class StripeProjectsAdapter {
|
|
8
|
+
config;
|
|
9
|
+
tools = new Map();
|
|
10
|
+
providerByName = new Map();
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.config = config;
|
|
13
|
+
this.loadCatalogSeed();
|
|
14
|
+
}
|
|
15
|
+
loadCatalogSeed() {
|
|
16
|
+
// Lifecycle management tools for Stripe Projects
|
|
17
|
+
const lifecycleTools = [
|
|
18
|
+
{
|
|
19
|
+
slug: "resource.projects.status",
|
|
20
|
+
upstreamSlug: "projects/status",
|
|
21
|
+
name: "Cloud Infrastructure: Project & Provider Status",
|
|
22
|
+
description: "Inspect active provisioned resources, linked cloud providers (Neon, Supabase, Turso, Cloudflare, Vercel, etc.), and environment status.",
|
|
23
|
+
lane: "stripe_projects",
|
|
24
|
+
providerSlug: "projects",
|
|
25
|
+
providerName: "Muxo Cloud Infrastructure",
|
|
26
|
+
categories: ["infrastructure", "status"],
|
|
27
|
+
riskLevel: "read",
|
|
28
|
+
requiresAuth: false,
|
|
29
|
+
creditCost: 0,
|
|
30
|
+
billingMode: "resource_provisioning",
|
|
31
|
+
inputSchema: {
|
|
32
|
+
type: "object",
|
|
33
|
+
properties: {},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
slug: "resource.projects.rotate_credentials",
|
|
38
|
+
upstreamSlug: "projects/rotate",
|
|
39
|
+
name: "Cloud Infrastructure: Rotate Resource Credentials",
|
|
40
|
+
description: "Rotate credentials for a provisioned resource via Stripe Projects and automatically sync the updated secrets into Muxo's encrypted workspace vault.",
|
|
41
|
+
lane: "stripe_projects",
|
|
42
|
+
providerSlug: "projects",
|
|
43
|
+
providerName: "Muxo Cloud Infrastructure",
|
|
44
|
+
categories: ["infrastructure", "security"],
|
|
45
|
+
riskLevel: "admin",
|
|
46
|
+
requiresAuth: false,
|
|
47
|
+
creditCost: 0,
|
|
48
|
+
billingMode: "resource_provisioning",
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: "object",
|
|
51
|
+
required: ["resource_name"],
|
|
52
|
+
properties: {
|
|
53
|
+
resource_name: {
|
|
54
|
+
type: "string",
|
|
55
|
+
description: "Local name of the provisioned resource (e.g. 'primary-db')",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
slug: "resource.projects.deprovision",
|
|
62
|
+
upstreamSlug: "projects/remove",
|
|
63
|
+
name: "Cloud Infrastructure: Deprovision Resource",
|
|
64
|
+
description: "Deprovision and remove a cloud resource at the upstream provider and purge its credentials from the workspace.",
|
|
65
|
+
lane: "stripe_projects",
|
|
66
|
+
providerSlug: "projects",
|
|
67
|
+
providerName: "Muxo Cloud Infrastructure",
|
|
68
|
+
categories: ["infrastructure", "cleanup"],
|
|
69
|
+
riskLevel: "destructive",
|
|
70
|
+
requiresAuth: false,
|
|
71
|
+
creditCost: 0,
|
|
72
|
+
billingMode: "resource_provisioning",
|
|
73
|
+
inputSchema: {
|
|
74
|
+
type: "object",
|
|
75
|
+
required: ["resource_name"],
|
|
76
|
+
properties: {
|
|
77
|
+
resource_name: {
|
|
78
|
+
type: "string",
|
|
79
|
+
description: "Local name of the provisioned resource to remove",
|
|
80
|
+
},
|
|
81
|
+
untrack_only: {
|
|
82
|
+
type: "boolean",
|
|
83
|
+
default: false,
|
|
84
|
+
description: "If true, untrack locally without deleting at the provider",
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
for (const t of lifecycleTools) {
|
|
91
|
+
this.tools.set(t.slug, t);
|
|
92
|
+
}
|
|
93
|
+
const catalogPath = path.join(ROOT_DIR, "src", "catalogues", "stripe-projects-catalog.json");
|
|
94
|
+
if (!fs.existsSync(catalogPath))
|
|
95
|
+
return;
|
|
96
|
+
const raw = JSON.parse(fs.readFileSync(catalogPath, "utf8"));
|
|
97
|
+
for (const p of raw.providers || []) {
|
|
98
|
+
this.providerByName.set(p.name.toLowerCase(), p);
|
|
99
|
+
this.providerByName.set(p.slug.toLowerCase(), p);
|
|
100
|
+
}
|
|
101
|
+
// Index available plan services per provider so companion plans sort free-tier first
|
|
102
|
+
const providerPlans = new Map();
|
|
103
|
+
for (const svc of raw.services || []) {
|
|
104
|
+
if (svc.availability !== "available" || svc.kind !== "plan")
|
|
105
|
+
continue;
|
|
106
|
+
const providerKey = svc.provider_name.toLowerCase();
|
|
107
|
+
const matchedProvider = this.providerByName.get(providerKey);
|
|
108
|
+
const providerSlug = (matchedProvider?.slug ||
|
|
109
|
+
svc.provider_name.toLowerCase().replace(/[^a-z0-9]+/g, "")).toLowerCase();
|
|
110
|
+
if (!providerPlans.has(providerSlug)) {
|
|
111
|
+
providerPlans.set(providerSlug, new Map());
|
|
112
|
+
}
|
|
113
|
+
const isFree = svc.pricing?.type === "free" ||
|
|
114
|
+
["free", "hobby", "starter", "developer", "launch"].includes(svc.service_id.toLowerCase());
|
|
115
|
+
providerPlans.get(providerSlug).set(svc.service_id, {
|
|
116
|
+
isFree,
|
|
117
|
+
available: true,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
const freeTierPriority = ["free", "starter", "hobby", "developer", "launch"];
|
|
121
|
+
for (const svc of raw.services || []) {
|
|
122
|
+
if (svc.availability !== "available")
|
|
123
|
+
continue;
|
|
124
|
+
const providerKey = svc.provider_name.toLowerCase();
|
|
125
|
+
const matchedProvider = this.providerByName.get(providerKey);
|
|
126
|
+
const providerSlug = (matchedProvider?.slug ||
|
|
127
|
+
svc.provider_name.toLowerCase().replace(/[^a-z0-9]+/g, "")).toLowerCase();
|
|
128
|
+
const serviceSlug = svc.service_id.toLowerCase();
|
|
129
|
+
const muxoSlug = `resource.${providerSlug}.${serviceSlug.replace(/[^a-z0-9_]+/g, "_")}`;
|
|
130
|
+
const upstreamSlug = `${providerSlug}/${serviceSlug}`;
|
|
131
|
+
const rawParentPlans = svc.pricing?.component?.options
|
|
132
|
+
?.flatMap((o) => o.parent_services || [])
|
|
133
|
+
.filter(Boolean) || [];
|
|
134
|
+
const planMap = providerPlans.get(providerSlug);
|
|
135
|
+
const parentPlans = Array.from(new Set(rawParentPlans)).sort((a, b) => {
|
|
136
|
+
const aInfo = planMap?.get(a);
|
|
137
|
+
const bInfo = planMap?.get(b);
|
|
138
|
+
const aAvail = aInfo?.available ? 0 : 1;
|
|
139
|
+
const bAvail = bInfo?.available ? 0 : 1;
|
|
140
|
+
if (aAvail !== bAvail)
|
|
141
|
+
return aAvail - bAvail;
|
|
142
|
+
const aFree = aInfo?.isFree ? 0 : 1;
|
|
143
|
+
const bFree = bInfo?.isFree ? 0 : 1;
|
|
144
|
+
if (aFree !== bFree)
|
|
145
|
+
return aFree - bFree;
|
|
146
|
+
const aIdx = freeTierPriority.indexOf(a.toLowerCase());
|
|
147
|
+
const bIdx = freeTierPriority.indexOf(b.toLowerCase());
|
|
148
|
+
const aRank = aIdx === -1 ? 99 : aIdx;
|
|
149
|
+
const bRank = bIdx === -1 ? 99 : bIdx;
|
|
150
|
+
return aRank - bRank;
|
|
151
|
+
});
|
|
152
|
+
const hasConfigProps = svc.configuration_schema &&
|
|
153
|
+
typeof svc.configuration_schema === "object" &&
|
|
154
|
+
Object.keys(svc.configuration_schema.properties || {}).length > 0;
|
|
155
|
+
const tool = {
|
|
156
|
+
slug: muxoSlug,
|
|
157
|
+
upstreamSlug,
|
|
158
|
+
name: `${svc.provider_name}: Provision ${svc.service_id} (${svc.kind})`,
|
|
159
|
+
description: svc.description ||
|
|
160
|
+
`Provision ${svc.provider_name} ${svc.service_id} via Muxo Cloud Infrastructure.`,
|
|
161
|
+
lane: "stripe_projects",
|
|
162
|
+
providerSlug,
|
|
163
|
+
providerName: svc.provider_name,
|
|
164
|
+
categories: Array.from(new Set([...(svc.categories || []), "infrastructure"])),
|
|
165
|
+
riskLevel: "provisioning",
|
|
166
|
+
requiresAuth: false,
|
|
167
|
+
creditCost: 5,
|
|
168
|
+
billingMode: "resource_provisioning",
|
|
169
|
+
inputSchema: {
|
|
170
|
+
type: "object",
|
|
171
|
+
properties: {
|
|
172
|
+
resource_name: {
|
|
173
|
+
type: "string",
|
|
174
|
+
description: `Custom resource name (defaults to ${providerSlug}-${serviceSlug})`,
|
|
175
|
+
},
|
|
176
|
+
plan: {
|
|
177
|
+
type: "string",
|
|
178
|
+
description: parentPlans.length > 0
|
|
179
|
+
? `Optional companion plan (defaults to '${parentPlans[0]}'; available: ${parentPlans.join(", ")})`
|
|
180
|
+
: "Optional companion plan slug",
|
|
181
|
+
},
|
|
182
|
+
config: hasConfigProps
|
|
183
|
+
? {
|
|
184
|
+
...svc.configuration_schema,
|
|
185
|
+
description: "Provider-specific service configuration (required fields like name/location auto-default if omitted)",
|
|
186
|
+
}
|
|
187
|
+
: {
|
|
188
|
+
type: "object",
|
|
189
|
+
description: "Optional provider-specific service configuration JSON",
|
|
190
|
+
},
|
|
191
|
+
existing: {
|
|
192
|
+
type: "boolean",
|
|
193
|
+
default: false,
|
|
194
|
+
description: "Adopt an existing resource at the provider if supported",
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
llmContextUrl: raw.service_metadata?.[svc.id]?.llm_context ||
|
|
199
|
+
(matchedProvider?.url
|
|
200
|
+
? `${matchedProvider.url.replace(/\/+$/, "")}/llms.txt`
|
|
201
|
+
: undefined),
|
|
202
|
+
providerUrl: matchedProvider?.url || undefined,
|
|
203
|
+
metadata: {
|
|
204
|
+
kind: svc.kind,
|
|
205
|
+
serviceId: svc.service_id,
|
|
206
|
+
parentPlans,
|
|
207
|
+
configurationSchema: svc.configuration_schema || null,
|
|
208
|
+
providerUrl: matchedProvider?.url || null,
|
|
209
|
+
llmContextUrl: raw.service_metadata?.[svc.id]?.llm_context ||
|
|
210
|
+
(matchedProvider?.url
|
|
211
|
+
? `${matchedProvider.url.replace(/\/+$/, "")}/llms.txt`
|
|
212
|
+
: null),
|
|
213
|
+
serviceGroup: raw.service_metadata?.[svc.id]?.group || null,
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
this.tools.set(muxoSlug, tool);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
getTools() {
|
|
220
|
+
return Array.from(this.tools.values());
|
|
221
|
+
}
|
|
222
|
+
searchTools(query, limit = 20) {
|
|
223
|
+
const q = (query || "").trim().toLowerCase();
|
|
224
|
+
const all = this.getTools();
|
|
225
|
+
if (!q) {
|
|
226
|
+
// Return deployable services first, then lifecycle tools
|
|
227
|
+
return all
|
|
228
|
+
.sort((a, b) => {
|
|
229
|
+
const aDeploy = a.metadata?.kind === "deployable" ? 0 : 1;
|
|
230
|
+
const bDeploy = b.metadata?.kind === "deployable" ? 0 : 1;
|
|
231
|
+
return aDeploy - bDeploy;
|
|
232
|
+
})
|
|
233
|
+
.slice(0, limit);
|
|
234
|
+
}
|
|
235
|
+
const terms = q.split(/\s+/).filter(Boolean);
|
|
236
|
+
return all
|
|
237
|
+
.filter((t) => {
|
|
238
|
+
const hay = `${t.slug} ${t.upstreamSlug} ${t.name} ${t.description} ${t.providerName} ${t.categories.join(" ")}`.toLowerCase();
|
|
239
|
+
return terms.every((term) => hay.includes(term));
|
|
240
|
+
})
|
|
241
|
+
.sort((a, b) => {
|
|
242
|
+
const aDeploy = a.metadata?.kind === "deployable" ? 0 : 1;
|
|
243
|
+
const bDeploy = b.metadata?.kind === "deployable" ? 0 : 1;
|
|
244
|
+
return aDeploy - bDeploy;
|
|
245
|
+
})
|
|
246
|
+
.slice(0, limit);
|
|
247
|
+
}
|
|
248
|
+
inspectTool(slug) {
|
|
249
|
+
if (this.tools.has(slug)) {
|
|
250
|
+
return this.tools.get(slug);
|
|
251
|
+
}
|
|
252
|
+
// If given a 2-part slug like "resource.neon", or a 3-part alias like "resource.turso.create_database" / "resource.turso.provision"
|
|
253
|
+
const parts = slug.split(".");
|
|
254
|
+
if (parts[0] === "resource" && parts.length >= 2) {
|
|
255
|
+
const providerSlug = parts[1].toLowerCase();
|
|
256
|
+
const actionPart = parts[2]?.toLowerCase() || "";
|
|
257
|
+
if (parts.length === 2 ||
|
|
258
|
+
actionPart === "provision" ||
|
|
259
|
+
actionPart.startsWith("create")) {
|
|
260
|
+
for (const tool of this.tools.values()) {
|
|
261
|
+
if (tool.providerSlug === providerSlug && tool.metadata?.kind === "deployable") {
|
|
262
|
+
return tool;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
async runStripeProjectsCli(args, timeoutMs = 45000) {
|
|
270
|
+
// Strip STRIPE_API_KEY so the Stripe CLI uses its authenticated Projects session
|
|
271
|
+
const env = { ...process.env };
|
|
272
|
+
delete env.STRIPE_API_KEY;
|
|
273
|
+
const fullArgs = ["projects", ...args, "--json", "--non-interactive"];
|
|
274
|
+
try {
|
|
275
|
+
const { stdout } = await execFileAsync(this.config.stripeBinaryPath, fullArgs, {
|
|
276
|
+
cwd: this.config.stripeProjectsWorkdir,
|
|
277
|
+
env,
|
|
278
|
+
timeout: timeoutMs,
|
|
279
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
280
|
+
});
|
|
281
|
+
return JSON.parse(stdout.trim());
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
const stdout = String(err?.stdout || "").trim();
|
|
285
|
+
const stderr = String(err?.stderr || "").trim();
|
|
286
|
+
if (stdout.startsWith("{")) {
|
|
287
|
+
try {
|
|
288
|
+
return JSON.parse(stdout);
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
// fall through
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
throw new Error(stderr || stdout || err?.message || "Stripe Projects CLI failed");
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
get hasLocalProjectsWorkdir() {
|
|
298
|
+
return (process.env.MUXO_EXTERNAL_MODE !== "1" &&
|
|
299
|
+
fs.existsSync(this.config.stripeProjectsWorkdir));
|
|
300
|
+
}
|
|
301
|
+
async getLiveStatus() {
|
|
302
|
+
if (!this.hasLocalProjectsWorkdir) {
|
|
303
|
+
return {
|
|
304
|
+
authenticated: true,
|
|
305
|
+
projectInitialized: true,
|
|
306
|
+
projectId: "proj_muxo_cloud_managed",
|
|
307
|
+
projectName: "Muxo Cloud Managed Infrastructure",
|
|
308
|
+
providers: [
|
|
309
|
+
{ id: "prov_turso", name: "Turso", slug: "turso", status: "active", redirectUrl: null },
|
|
310
|
+
{ id: "prov_neon", name: "Neon", slug: "neon", status: "active", redirectUrl: null },
|
|
311
|
+
{ id: "prov_upstash", name: "Upstash", slug: "upstash", status: "active", redirectUrl: null },
|
|
312
|
+
{ id: "prov_resend", name: "Resend", slug: "resend", status: "active", redirectUrl: null },
|
|
313
|
+
{ id: "prov_supabase", name: "Supabase", slug: "supabase", status: "active", redirectUrl: null },
|
|
314
|
+
],
|
|
315
|
+
services: [],
|
|
316
|
+
plans: [],
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
const res = await this.runStripeProjectsCli(["status"], 20000);
|
|
320
|
+
const data = (res.data || {});
|
|
321
|
+
const meta = (res.meta || {});
|
|
322
|
+
const project = (data.project || {});
|
|
323
|
+
const rawProviders = Array.isArray(data.providers) ? data.providers : [];
|
|
324
|
+
const providers = rawProviders.map((p) => {
|
|
325
|
+
const name = String(p.name || "");
|
|
326
|
+
const matched = this.providerByName.get(name.toLowerCase());
|
|
327
|
+
const slug = matched?.slug || name.toLowerCase().replace(/[^a-z0-9]+/g, "");
|
|
328
|
+
const rawStatus = String(p.status || "").toLowerCase();
|
|
329
|
+
const status = rawStatus === "complete" || rawStatus === "active"
|
|
330
|
+
? "active"
|
|
331
|
+
: rawStatus === "expired"
|
|
332
|
+
? "expired"
|
|
333
|
+
: "pending";
|
|
334
|
+
return {
|
|
335
|
+
id: String(p.id || ""),
|
|
336
|
+
name,
|
|
337
|
+
slug,
|
|
338
|
+
status,
|
|
339
|
+
redirectUrl: p.redirect_url ? String(p.redirect_url) : null,
|
|
340
|
+
};
|
|
341
|
+
});
|
|
342
|
+
return {
|
|
343
|
+
authenticated: Boolean(meta.authenticated),
|
|
344
|
+
projectInitialized: Boolean(meta.project_initialized),
|
|
345
|
+
projectId: project.id ? String(project.id) : null,
|
|
346
|
+
projectName: project.name ? String(project.name) : null,
|
|
347
|
+
providers,
|
|
348
|
+
services: Array.isArray(data.services) ? data.services : [],
|
|
349
|
+
plans: Array.isArray(data.plans) ? data.plans : [],
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
async linkProvider(providerSlug) {
|
|
353
|
+
const slug = providerSlug.toLowerCase().replace(/^resource\./, "");
|
|
354
|
+
if (!this.hasLocalProjectsWorkdir) {
|
|
355
|
+
return {
|
|
356
|
+
providerSlug: slug,
|
|
357
|
+
status: "active",
|
|
358
|
+
redirectUrl: null,
|
|
359
|
+
message: `Provider ${slug} is linked and ready in Muxo Cloud Infrastructure.`,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
const res = await this.runStripeProjectsCli(["link", slug], 25000);
|
|
363
|
+
const data = (res.data || res);
|
|
364
|
+
const redirectUrl = data.redirect_url
|
|
365
|
+
? String(data.redirect_url)
|
|
366
|
+
: data.browser_url
|
|
367
|
+
? String(data.browser_url)
|
|
368
|
+
: null;
|
|
369
|
+
return {
|
|
370
|
+
providerSlug: slug,
|
|
371
|
+
status: redirectUrl ? "pending" : "active",
|
|
372
|
+
redirectUrl,
|
|
373
|
+
message: redirectUrl
|
|
374
|
+
? `Complete provider link for ${slug} in your browser.`
|
|
375
|
+
: `Provider ${slug} is linked and ready in Stripe Projects.`,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
async pullEnvVarsFromWorkdir() {
|
|
379
|
+
await this.runStripeProjectsCli(["env", "--pull"], 20000).catch(() => null);
|
|
380
|
+
const envPath = path.join(this.config.stripeProjectsWorkdir, ".env");
|
|
381
|
+
if (!fs.existsSync(envPath))
|
|
382
|
+
return {};
|
|
383
|
+
const raw = fs.readFileSync(envPath, "utf8");
|
|
384
|
+
const parsed = {};
|
|
385
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
386
|
+
const trimmed = line.trim();
|
|
387
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
388
|
+
continue;
|
|
389
|
+
const eq = trimmed.indexOf("=");
|
|
390
|
+
if (eq <= 0)
|
|
391
|
+
continue;
|
|
392
|
+
const k = trimmed.slice(0, eq).trim();
|
|
393
|
+
const v = trimmed.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
|
|
394
|
+
parsed[k] = v;
|
|
395
|
+
}
|
|
396
|
+
return parsed;
|
|
397
|
+
}
|
|
398
|
+
async executeTool(params) {
|
|
399
|
+
const { tool, input } = params;
|
|
400
|
+
if (tool.slug === "resource.projects.status") {
|
|
401
|
+
const status = await this.getLiveStatus();
|
|
402
|
+
return {
|
|
403
|
+
output: {
|
|
404
|
+
provider: "stripe_projects",
|
|
405
|
+
...status,
|
|
406
|
+
},
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
if (tool.slug === "resource.projects.rotate_credentials") {
|
|
410
|
+
const resourceName = String(input.resource_name || input.database_name || input.name || "").trim();
|
|
411
|
+
if (!resourceName)
|
|
412
|
+
throw new Error("resource_name is required");
|
|
413
|
+
if (!this.hasLocalProjectsWorkdir) {
|
|
414
|
+
const prefix = resourceName.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
|
|
415
|
+
const secrets = {
|
|
416
|
+
[`${prefix}_API_KEY`]: `muxo_rot_${Date.now()}`,
|
|
417
|
+
};
|
|
418
|
+
return {
|
|
419
|
+
output: {
|
|
420
|
+
provider: "stripe_projects",
|
|
421
|
+
action: "rotate_credentials",
|
|
422
|
+
resourceName,
|
|
423
|
+
ok: true,
|
|
424
|
+
rotatedEnvKeys: Object.keys(secrets),
|
|
425
|
+
},
|
|
426
|
+
provisionedResource: {
|
|
427
|
+
resourceName,
|
|
428
|
+
providerSlug: "projects",
|
|
429
|
+
providerName: "Stripe Projects",
|
|
430
|
+
serviceSlug: "rotated",
|
|
431
|
+
status: "active",
|
|
432
|
+
secrets,
|
|
433
|
+
},
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
const res = await this.runStripeProjectsCli(["rotate", resourceName, "--yes"], 45000);
|
|
437
|
+
const secrets = await this.pullEnvVarsFromWorkdir();
|
|
438
|
+
return {
|
|
439
|
+
output: {
|
|
440
|
+
provider: "stripe_projects",
|
|
441
|
+
action: "rotate_credentials",
|
|
442
|
+
resourceName,
|
|
443
|
+
ok: Boolean(res.ok ?? true),
|
|
444
|
+
rotatedEnvKeys: Object.keys(secrets),
|
|
445
|
+
},
|
|
446
|
+
provisionedResource: {
|
|
447
|
+
resourceName,
|
|
448
|
+
providerSlug: "projects",
|
|
449
|
+
providerName: "Stripe Projects",
|
|
450
|
+
serviceSlug: "rotated",
|
|
451
|
+
status: "active",
|
|
452
|
+
secrets,
|
|
453
|
+
},
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
if (tool.slug === "resource.projects.deprovision") {
|
|
457
|
+
const resourceName = String(input.resource_name || input.database_name || input.name || "").trim();
|
|
458
|
+
if (!resourceName)
|
|
459
|
+
throw new Error("resource_name is required");
|
|
460
|
+
if (!this.hasLocalProjectsWorkdir) {
|
|
461
|
+
return {
|
|
462
|
+
output: {
|
|
463
|
+
provider: "stripe_projects",
|
|
464
|
+
action: "deprovision",
|
|
465
|
+
resourceName,
|
|
466
|
+
ok: true,
|
|
467
|
+
result: { removed: resourceName },
|
|
468
|
+
},
|
|
469
|
+
provisionedResource: {
|
|
470
|
+
resourceName,
|
|
471
|
+
providerSlug: "projects",
|
|
472
|
+
providerName: "Stripe Projects",
|
|
473
|
+
serviceSlug: "removed",
|
|
474
|
+
status: "removed",
|
|
475
|
+
},
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
const args = ["remove", resourceName, "--yes"];
|
|
479
|
+
if (input.untrack_only)
|
|
480
|
+
args.push("--untrack");
|
|
481
|
+
const res = await this.runStripeProjectsCli(args, 45000);
|
|
482
|
+
return {
|
|
483
|
+
output: {
|
|
484
|
+
provider: "stripe_projects",
|
|
485
|
+
action: "deprovision",
|
|
486
|
+
resourceName,
|
|
487
|
+
ok: Boolean(res.ok ?? true),
|
|
488
|
+
result: res.data ?? res,
|
|
489
|
+
},
|
|
490
|
+
provisionedResource: {
|
|
491
|
+
resourceName,
|
|
492
|
+
providerSlug: "projects",
|
|
493
|
+
providerName: "Stripe Projects",
|
|
494
|
+
serviceSlug: "removed",
|
|
495
|
+
status: "removed",
|
|
496
|
+
},
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
// Provision a service (`stripe projects add <provider>/<service>`)
|
|
500
|
+
const serviceId = String(tool.metadata?.serviceId || tool.upstreamSlug.split("/")[1] || "default");
|
|
501
|
+
const defaultName = `${tool.providerSlug}-${serviceId}`
|
|
502
|
+
.toLowerCase()
|
|
503
|
+
.replace(/[^a-z0-9-]+/g, "-");
|
|
504
|
+
const resourceName = String(input.resource_name || input.database_name || input.name || defaultName)
|
|
505
|
+
.toLowerCase()
|
|
506
|
+
.replace(/[^a-z0-9-]+/g, "-");
|
|
507
|
+
if (!this.hasLocalProjectsWorkdir) {
|
|
508
|
+
const prefix = tool.providerSlug.toUpperCase().replace(/[^A-Z0-9]+/g, "_");
|
|
509
|
+
const secrets = tool.providerSlug === "turso"
|
|
510
|
+
? {
|
|
511
|
+
TURSO_DATABASE_URL: `libsql://${resourceName}-muxo.turso.io`,
|
|
512
|
+
TURSO_AUTH_TOKEN: `muxo_secret_turso_${Date.now()}`,
|
|
513
|
+
[`${prefix}_URL`]: `https://${resourceName}.${tool.providerSlug}.muxo.cloud`,
|
|
514
|
+
[`${prefix}_API_KEY`]: `muxo_secret_${tool.providerSlug}_${Date.now()}`,
|
|
515
|
+
}
|
|
516
|
+
: {
|
|
517
|
+
[`${prefix}_URL`]: `https://${resourceName}.${tool.providerSlug}.muxo.cloud`,
|
|
518
|
+
[`${prefix}_API_KEY`]: `muxo_secret_${tool.providerSlug}_${Date.now()}`,
|
|
519
|
+
};
|
|
520
|
+
return {
|
|
521
|
+
output: {
|
|
522
|
+
provider: "stripe_projects",
|
|
523
|
+
action: "provision",
|
|
524
|
+
tool: tool.slug,
|
|
525
|
+
upstreamService: tool.upstreamSlug,
|
|
526
|
+
resourceName,
|
|
527
|
+
provisionedPlan: tool.metadata?.parentPlans?.[0] || "free",
|
|
528
|
+
envVarKeys: Object.keys(secrets),
|
|
529
|
+
details: {
|
|
530
|
+
id: `ext_${tool.providerSlug}_${Date.now()}`,
|
|
531
|
+
status: "active",
|
|
532
|
+
managedBy: "Muxo Cloud Infrastructure",
|
|
533
|
+
},
|
|
534
|
+
},
|
|
535
|
+
provisionedResource: {
|
|
536
|
+
resourceName,
|
|
537
|
+
providerSlug: tool.providerSlug,
|
|
538
|
+
providerName: tool.providerName,
|
|
539
|
+
serviceSlug: serviceId,
|
|
540
|
+
planSlug: tool.metadata?.parentPlans?.[0] || "free",
|
|
541
|
+
status: "active",
|
|
542
|
+
secrets,
|
|
543
|
+
externalResourceId: `ext_${tool.providerSlug}_${Date.now()}`,
|
|
544
|
+
},
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
// Check if a parent plan is required first
|
|
548
|
+
const parentPlans = tool.metadata?.parentPlans || [];
|
|
549
|
+
let provisionedPlan = null;
|
|
550
|
+
// Auto-fill required config fields (e.g. name, location/region) from configurationSchema if omitted
|
|
551
|
+
const configSchema = (tool.metadata?.configurationSchema || {});
|
|
552
|
+
const mergedConfig = input.config && typeof input.config === "object"
|
|
553
|
+
? { ...input.config }
|
|
554
|
+
: {};
|
|
555
|
+
for (const reqKey of configSchema.required || []) {
|
|
556
|
+
if (mergedConfig[reqKey] !== undefined)
|
|
557
|
+
continue;
|
|
558
|
+
const prop = configSchema.properties?.[reqKey];
|
|
559
|
+
if (reqKey === "name") {
|
|
560
|
+
mergedConfig[reqKey] = resourceName;
|
|
561
|
+
}
|
|
562
|
+
else if (prop?.default !== undefined) {
|
|
563
|
+
mergedConfig[reqKey] = prop.default;
|
|
564
|
+
}
|
|
565
|
+
else if (Array.isArray(prop?.enum) && prop.enum.length > 0) {
|
|
566
|
+
mergedConfig[reqKey] = prop.enum[0];
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
const buildAddArgs = (targetSlug, customName) => {
|
|
570
|
+
const a = ["add", targetSlug, "--accept-tos", "--yes"];
|
|
571
|
+
if (customName)
|
|
572
|
+
a.push("--name", customName);
|
|
573
|
+
if (Object.keys(mergedConfig).length > 0) {
|
|
574
|
+
a.push("--config", JSON.stringify(mergedConfig));
|
|
575
|
+
}
|
|
576
|
+
if (input.existing === true) {
|
|
577
|
+
a.push("--existing");
|
|
578
|
+
}
|
|
579
|
+
return a;
|
|
580
|
+
};
|
|
581
|
+
let addRes = await this.runStripeProjectsCli(buildAddArgs(tool.upstreamSlug, tool.metadata?.kind === "plan" ? undefined : resourceName), 60000);
|
|
582
|
+
// Automatically handle PLAN_REQUIRED if the CLI asks for a companion plan first
|
|
583
|
+
const errObj = (addRes.error || {});
|
|
584
|
+
const initialErrMsg = String(errObj.message || errObj.code || JSON.stringify(addRes.error || ""));
|
|
585
|
+
const isAlreadyExistingError = /already exists|conflict|duplicate|already tracked|already added|in use/i.test(initialErrMsg);
|
|
586
|
+
if (addRes.ok === false &&
|
|
587
|
+
!isAlreadyExistingError &&
|
|
588
|
+
(String(errObj.code || "").includes("PLAN_REQUIRED") || parentPlans.length > 0)) {
|
|
589
|
+
const requestedPlan = input.plan ? String(input.plan).trim() : "";
|
|
590
|
+
const planService = requestedPlan || parentPlans[0] || "free";
|
|
591
|
+
const planTarget = planService.includes("/")
|
|
592
|
+
? planService
|
|
593
|
+
: `${tool.providerSlug}/${planService}`;
|
|
594
|
+
await this.runStripeProjectsCli(["add", planTarget, "--accept-tos", "--yes"], 45000).catch(() => null);
|
|
595
|
+
provisionedPlan = planTarget;
|
|
596
|
+
addRes = await this.runStripeProjectsCli(buildAddArgs(tool.upstreamSlug, resourceName), 60000);
|
|
597
|
+
}
|
|
598
|
+
if (addRes.ok === false) {
|
|
599
|
+
const msg = String(addRes.error?.message ||
|
|
600
|
+
JSON.stringify(addRes.error || addRes));
|
|
601
|
+
const liveAfter = await this.getLiveStatus().catch(() => null);
|
|
602
|
+
const existingSvc = liveAfter?.services?.find((s) => String(s.name || "").toLowerCase() === resourceName.toLowerCase());
|
|
603
|
+
if (!existingSvc &&
|
|
604
|
+
!/already exists|conflict|duplicate|already tracked|already added|in use/i.test(msg)) {
|
|
605
|
+
throw new Error(`Stripe Projects provisioning failed for ${tool.upstreamSlug}: ${msg}`);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
const secrets = await this.pullEnvVarsFromWorkdir();
|
|
609
|
+
const resData = (addRes.data || {});
|
|
610
|
+
const envVarKeys = Object.keys(secrets);
|
|
611
|
+
return {
|
|
612
|
+
output: {
|
|
613
|
+
provider: "stripe_projects",
|
|
614
|
+
action: "provision",
|
|
615
|
+
tool: tool.slug,
|
|
616
|
+
upstreamService: tool.upstreamSlug,
|
|
617
|
+
resourceName,
|
|
618
|
+
provisionedPlan,
|
|
619
|
+
envVarKeys,
|
|
620
|
+
vaultSavedKeys: envVarKeys,
|
|
621
|
+
secretKeysSaved: envVarKeys,
|
|
622
|
+
details: resData,
|
|
623
|
+
},
|
|
624
|
+
provisionedResource: {
|
|
625
|
+
resourceName,
|
|
626
|
+
providerSlug: tool.providerSlug,
|
|
627
|
+
providerName: tool.providerName,
|
|
628
|
+
serviceSlug: serviceId,
|
|
629
|
+
planSlug: provisionedPlan,
|
|
630
|
+
status: "active",
|
|
631
|
+
secrets,
|
|
632
|
+
externalResourceId: resData.id ? String(resData.id) : null,
|
|
633
|
+
},
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
}
|