@muxoai/sdk 1.3.0 → 1.4.3
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 +2 -2
- package/.claude-plugin/marketplace.json +19 -4
- package/.codex/config.toml +9 -2
- package/ARCHITECTURE.md +16 -6
- package/README.md +69 -24
- package/dist/clerk.d.ts +35 -0
- package/dist/clerk.js +201 -0
- package/dist/cli.js +1677 -103
- package/dist/composio-catalog.d.ts +234 -0
- package/dist/composio-catalog.js +1894 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.js +27 -1
- package/dist/durable-workflow.d.ts +112 -0
- package/dist/durable-workflow.js +284 -0
- package/dist/engine.d.ts +377 -6
- package/dist/engine.js +1919 -94
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/mcp-schema.d.ts +286 -0
- package/dist/mcp-schema.js +2580 -0
- package/dist/mcp.d.ts +2 -25
- package/dist/mcp.js +1008 -507
- package/dist/memory-graph.d.ts +45 -0
- package/dist/memory-graph.js +293 -0
- package/dist/nl.js +214 -35
- package/dist/oauth.d.ts +32 -0
- package/dist/oauth.js +134 -0
- package/dist/oss-suite.d.ts +217 -0
- package/dist/oss-suite.js +836 -0
- package/dist/policy.d.ts +190 -0
- package/dist/policy.js +1597 -0
- package/dist/providers/composio-instant.d.ts +4 -0
- package/dist/providers/composio-instant.js +890 -535
- package/dist/providers/composio-sdk.d.ts +126 -5
- package/dist/providers/composio-sdk.js +902 -79
- package/dist/providers/microsoft-governance.d.ts +89 -3
- package/dist/providers/microsoft-governance.js +673 -26
- package/dist/providers/stripe-billing.d.ts +42 -0
- package/dist/providers/stripe-billing.js +244 -5
- package/dist/providers/stripe-projects.d.ts +459 -4
- package/dist/providers/stripe-projects.js +2674 -122
- package/dist/providers/supermemory.d.ts +102 -6
- package/dist/providers/supermemory.js +609 -55
- package/dist/provisioning-managed.d.ts +50 -0
- package/dist/provisioning-managed.js +155 -0
- package/dist/sdk.d.ts +728 -7
- package/dist/sdk.js +539 -10
- package/dist/server.js +2744 -321
- package/dist/store.d.ts +138 -6
- package/dist/store.js +932 -58
- package/dist/types.d.ts +330 -4
- package/dist/ui/console-html.d.ts +62 -0
- package/dist/ui/console-html.js +3742 -2228
- package/dist/ui/design-tokens.d.ts +177 -0
- package/dist/ui/design-tokens.js +210 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +1 -0
- package/package.json +6 -5
- package/plugins/muxo/.app.json +1 -1
- package/plugins/muxo/.claude-plugin/plugin.json +3 -3
- package/plugins/muxo/.codex-plugin/plugin.json +19 -10
- package/plugins/muxo/.cursor-plugin/plugin.json +30 -0
- package/plugins/muxo/.mcp.json +1 -33
- package/plugins/muxo/assets/logo.png +0 -0
- package/plugins/muxo/hooks/session-start.sh +16 -4
- package/plugins/muxo/hooks/user-prompt-submit.sh +14 -1
- package/plugins/muxo/mcp.json +0 -10
- package/plugins/muxo/plugin.json +65 -8
- package/plugins/muxo/skills/muxo/SKILL.md +142 -14
- package/plugins/muxo/skills/muxo/agents/openai.yaml +12 -0
- package/plugins/muxo/skills/muxo/references/cli.md +9 -3
- package/plugins/muxo/skills/muxo/references/mcp.md +22 -10
- package/plugins/muxo/skills/muxo-activity-summary/SKILL.md +81 -0
- package/plugins/muxo/skills/setup/SKILL.md +17 -3
- package/plugins/muxo/skills/setup/agents/openai.yaml +12 -0
- package/src/catalogues/stripe-projects-catalog.json +140 -0
package/dist/config.d.ts
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
|
+
import type { ClerkEnv } from "./clerk.js";
|
|
1
2
|
export declare const ROOT_DIR: string;
|
|
2
3
|
export interface MuxoConfig {
|
|
3
4
|
port: number;
|
|
4
5
|
baseUrl: string;
|
|
5
6
|
dbPath: string;
|
|
6
7
|
composioApiKey: string;
|
|
8
|
+
composioInstantApiKey: string;
|
|
7
9
|
composioBaseUrl: string;
|
|
10
|
+
composioWebhookSecret: string;
|
|
11
|
+
composioWebhookSubscriptionId: string;
|
|
12
|
+
composioProjectId: string;
|
|
13
|
+
composioOrgId: string;
|
|
14
|
+
composioUserId: string;
|
|
8
15
|
stripeSecretKey: string;
|
|
16
|
+
stripePublishableKey: string;
|
|
17
|
+
stripeApiBaseUrl: string;
|
|
18
|
+
stripeProvisioningApiVersion: string;
|
|
19
|
+
stripeProjectId: string;
|
|
20
|
+
stripeConnectedAccountId?: string;
|
|
9
21
|
stripeStarterPriceId: string;
|
|
10
22
|
stripeCreditsPriceId: string;
|
|
11
23
|
stripeWebhookSecret: string;
|
|
@@ -16,5 +28,9 @@ export interface MuxoConfig {
|
|
|
16
28
|
publicWebUrl: string;
|
|
17
29
|
docsUrl: string;
|
|
18
30
|
vaultMasterKey: Buffer;
|
|
31
|
+
/** Clerk sign-in settings; sign-in stays password-based unless CLERK_PUBLISHABLE_KEY is set. */
|
|
32
|
+
clerkEnv?: ClerkEnv & {
|
|
33
|
+
MUXO_OWNER_EMAILS?: string;
|
|
34
|
+
};
|
|
19
35
|
}
|
|
20
36
|
export declare function getConfig(): MuxoConfig;
|
package/dist/config.js
CHANGED
|
@@ -65,11 +65,30 @@ export function getConfig() {
|
|
|
65
65
|
dbPath: process.env.MUXO_DB_PATH || path.join(dataDir, "muxo.db"),
|
|
66
66
|
composioApiKey: process.env.MUXO_EXTERNAL_MODE === "1"
|
|
67
67
|
? ""
|
|
68
|
-
: process.env.COMPOSIO_API_KEY || "",
|
|
68
|
+
: process.env.COMPOSIO_API_KEY || process.env.COMPOSIO_INSTANT_API_KEY || "",
|
|
69
|
+
composioInstantApiKey: process.env.MUXO_EXTERNAL_MODE === "1"
|
|
70
|
+
? ""
|
|
71
|
+
: process.env.COMPOSIO_INSTANT_API_KEY || process.env.COMPOSIO_API_KEY || "",
|
|
69
72
|
composioBaseUrl: process.env.COMPOSIO_BASE_URL || "https://backend.composio.dev/api/v3",
|
|
73
|
+
composioWebhookSecret: process.env.MUXO_EXTERNAL_MODE === "1"
|
|
74
|
+
? ""
|
|
75
|
+
: process.env.COMPOSIO_WEBHOOK_SECRET || "",
|
|
76
|
+
composioWebhookSubscriptionId: process.env.COMPOSIO_WEBHOOK_SUBSCRIPTION_ID || "",
|
|
77
|
+
composioProjectId: process.env.COMPOSIO_PROJECT_ID || "",
|
|
78
|
+
composioOrgId: process.env.COMPOSIO_ORG_ID || "",
|
|
79
|
+
composioUserId: process.env.COMPOSIO_USER_ID || "",
|
|
70
80
|
stripeSecretKey: process.env.MUXO_EXTERNAL_MODE === "1"
|
|
71
81
|
? ""
|
|
72
82
|
: process.env.STRIPE_SECRET_KEY || "",
|
|
83
|
+
stripePublishableKey: process.env.MUXO_EXTERNAL_MODE === "1"
|
|
84
|
+
? ""
|
|
85
|
+
: process.env.STRIPE_PUBLISHABLE_KEY || "",
|
|
86
|
+
stripeApiBaseUrl: process.env.STRIPE_API_BASE_URL || "https://api.stripe.com",
|
|
87
|
+
stripeProvisioningApiVersion: process.env.STRIPE_PROVISIONING_API_VERSION || "2026-09-30.preview",
|
|
88
|
+
stripeProjectId: process.env.STRIPE_PROJECT_ID || "",
|
|
89
|
+
stripeConnectedAccountId: process.env.STRIPE_CONNECTED_ACCOUNT_ID ||
|
|
90
|
+
process.env.STRIPE_CONTEXT ||
|
|
91
|
+
"",
|
|
73
92
|
stripeStarterPriceId: process.env.STRIPE_STARTER_PRICE_ID || "",
|
|
74
93
|
stripeCreditsPriceId: process.env.STRIPE_CREDITS_PRICE_ID || "",
|
|
75
94
|
stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET || "",
|
|
@@ -85,5 +104,12 @@ export function getConfig() {
|
|
|
85
104
|
publicWebUrl: process.env.MUXO_PUBLIC_WEB_URL || "https://muxo.ai",
|
|
86
105
|
docsUrl: process.env.MUXO_DOCS_URL || "https://docs.muxo.ai",
|
|
87
106
|
vaultMasterKey: deriveVaultMasterKey(),
|
|
107
|
+
clerkEnv: {
|
|
108
|
+
CLERK_PUBLISHABLE_KEY: process.env.CLERK_PUBLISHABLE_KEY,
|
|
109
|
+
CLERK_SECRET_KEY: process.env.CLERK_SECRET_KEY,
|
|
110
|
+
CLERK_JWT_KEY: process.env.CLERK_JWT_KEY,
|
|
111
|
+
CLERK_AUTHORIZED_PARTIES: process.env.CLERK_AUTHORIZED_PARTIES,
|
|
112
|
+
MUXO_OWNER_EMAILS: process.env.MUXO_OWNER_EMAILS,
|
|
113
|
+
},
|
|
88
114
|
};
|
|
89
115
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temporal-compatible Durable Workflows, Saga Compensations, Signals, and Cloudflare Workflows primitives,
|
|
3
|
+
* shared by the Node engine (src/engine.ts) and the Cloudflare Edge Worker (worker/index.ts).
|
|
4
|
+
*/
|
|
5
|
+
import { MuxoToolError } from "./mcp-schema.js";
|
|
6
|
+
export type DurableWorkflowStepStatus = "completed" | "waiting" | "pending" | "failed" | "compensated";
|
|
7
|
+
export interface DurableWorkflowStep {
|
|
8
|
+
name: string;
|
|
9
|
+
primitive: "step.do" | "step.waitForEvent" | "step.sleep";
|
|
10
|
+
status: DurableWorkflowStepStatus;
|
|
11
|
+
output?: Record<string, unknown>;
|
|
12
|
+
completedAt?: string;
|
|
13
|
+
compensationAction?: string;
|
|
14
|
+
compensatedAt?: string;
|
|
15
|
+
}
|
|
16
|
+
export type TemporalEventType = "EVENT_TYPE_WORKFLOW_EXECUTION_STARTED" | "EVENT_TYPE_ACTIVITY_TASK_SCHEDULED" | "EVENT_TYPE_ACTIVITY_TASK_COMPLETED" | "EVENT_TYPE_ACTIVITY_TASK_FAILED" | "EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED" | "EVENT_TYPE_TIMER_STARTED" | "EVENT_TYPE_TIMER_FIRED" | "EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED" | "EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED" | "EVENT_TYPE_WORKFLOW_EXECUTION_FAILED";
|
|
17
|
+
export interface TemporalHistoryEvent {
|
|
18
|
+
eventId: number;
|
|
19
|
+
eventTime: string;
|
|
20
|
+
eventType: TemporalEventType;
|
|
21
|
+
taskQueue: string;
|
|
22
|
+
attributes: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
export interface SagaCompensationRecord {
|
|
25
|
+
stepName: string;
|
|
26
|
+
compensationAction: string;
|
|
27
|
+
status: "registered" | "executed" | "skipped";
|
|
28
|
+
description: string;
|
|
29
|
+
output?: Record<string, unknown>;
|
|
30
|
+
executedAt?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface DurableWorkflowSignalRecord {
|
|
33
|
+
signalName: string;
|
|
34
|
+
payload: Record<string, unknown>;
|
|
35
|
+
receivedAt: string;
|
|
36
|
+
}
|
|
37
|
+
export interface DurableWorkflow {
|
|
38
|
+
id: string;
|
|
39
|
+
runId?: string;
|
|
40
|
+
workspaceId: string;
|
|
41
|
+
workflowType: "cloud_provisioning_pipeline" | "approval_handoff_pipeline" | "commercial_playbook_saga";
|
|
42
|
+
playbookSlug?: string | null;
|
|
43
|
+
status: "running" | "waiting_for_event" | "completed" | "failed" | "rolled_back";
|
|
44
|
+
provider: string;
|
|
45
|
+
serviceRef: string;
|
|
46
|
+
resourceId: string | null;
|
|
47
|
+
steps: DurableWorkflowStep[];
|
|
48
|
+
compensations?: SagaCompensationRecord[];
|
|
49
|
+
signals?: DurableWorkflowSignalRecord[];
|
|
50
|
+
temporalEventHistory?: TemporalHistoryEvent[];
|
|
51
|
+
rollbackReason?: string | null;
|
|
52
|
+
createdAt: string;
|
|
53
|
+
updatedAt: string;
|
|
54
|
+
}
|
|
55
|
+
export declare const WORKFLOW_RESOURCE_COMPLETED_EVENT = "v2.provisioning.resource.completed";
|
|
56
|
+
export declare function workflowNotFoundError(workflowId: string): MuxoToolError;
|
|
57
|
+
export declare function normalizeWorkflowTarget(params: {
|
|
58
|
+
provider?: string;
|
|
59
|
+
serviceRef?: string;
|
|
60
|
+
}): {
|
|
61
|
+
provider: string;
|
|
62
|
+
serviceRef: string;
|
|
63
|
+
};
|
|
64
|
+
export declare function createCloudProvisioningWorkflow(params: {
|
|
65
|
+
id: string;
|
|
66
|
+
workspaceId: string;
|
|
67
|
+
resourceId: string;
|
|
68
|
+
provider: string;
|
|
69
|
+
serviceRef: string;
|
|
70
|
+
region?: string;
|
|
71
|
+
apiVersion?: string;
|
|
72
|
+
}): DurableWorkflow;
|
|
73
|
+
/** Completes every outstanding step once the resource-completed event (or a manual advance) arrives. */
|
|
74
|
+
export declare function completeCloudProvisioningWorkflow(wf: DurableWorkflow, params: {
|
|
75
|
+
secretKeys: string[];
|
|
76
|
+
triggerEvent?: unknown;
|
|
77
|
+
}): DurableWorkflow;
|
|
78
|
+
/**
|
|
79
|
+
* Executes LIFO Saga Compensations on a DurableWorkflow, rolling back completed steps in reverse order
|
|
80
|
+
* and recording Temporal compensation activity events.
|
|
81
|
+
*/
|
|
82
|
+
export declare function rollbackDurableWorkflow(wf: DurableWorkflow, params?: {
|
|
83
|
+
reason?: string;
|
|
84
|
+
failedStepName?: string;
|
|
85
|
+
failedStep?: string;
|
|
86
|
+
}): DurableWorkflow;
|
|
87
|
+
/**
|
|
88
|
+
* Sends a named Temporal signal to a DurableWorkflow (`human.approval.granted`, `oauth.connection.active`,
|
|
89
|
+
* `saga.abort`, or `v2.provisioning.resource.completed`).
|
|
90
|
+
*/
|
|
91
|
+
export declare function signalDurableWorkflow(wf: DurableWorkflow, params: {
|
|
92
|
+
signalName: string;
|
|
93
|
+
payload?: Record<string, unknown>;
|
|
94
|
+
secretKeys?: string[];
|
|
95
|
+
}): DurableWorkflow;
|
|
96
|
+
/**
|
|
97
|
+
* Exports a DurableWorkflow in Temporal Web UI / `temporal workflow show` compatible EventHistory JSON format.
|
|
98
|
+
*/
|
|
99
|
+
export declare function exportTemporalEventHistory(wf: DurableWorkflow): {
|
|
100
|
+
namespace: string;
|
|
101
|
+
workflowExecution: {
|
|
102
|
+
workflowId: string;
|
|
103
|
+
runId: string;
|
|
104
|
+
};
|
|
105
|
+
workflowType: {
|
|
106
|
+
name: string;
|
|
107
|
+
};
|
|
108
|
+
status: DurableWorkflow["status"];
|
|
109
|
+
eventsCount: number;
|
|
110
|
+
compensationsCount: number;
|
|
111
|
+
events: TemporalHistoryEvent[];
|
|
112
|
+
};
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temporal-compatible Durable Workflows, Saga Compensations, Signals, and Cloudflare Workflows primitives,
|
|
3
|
+
* shared by the Node engine (src/engine.ts) and the Cloudflare Edge Worker (worker/index.ts).
|
|
4
|
+
*/
|
|
5
|
+
import { MuxoToolError } from "./mcp-schema.js";
|
|
6
|
+
export const WORKFLOW_RESOURCE_COMPLETED_EVENT = "v2.provisioning.resource.completed";
|
|
7
|
+
export function workflowNotFoundError(workflowId) {
|
|
8
|
+
return new MuxoToolError(`Durable workflow not found: ${workflowId}`, {
|
|
9
|
+
code: "workflow_not_found",
|
|
10
|
+
statusCode: 404,
|
|
11
|
+
payload: { workflowId },
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export function normalizeWorkflowTarget(params) {
|
|
15
|
+
return {
|
|
16
|
+
provider: (params.provider || "neon").toLowerCase().trim(),
|
|
17
|
+
serviceRef: (params.serviceRef || "postgres").toLowerCase().trim(),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function appendTemporalEvent(history, eventType, attributes, now = new Date().toISOString()) {
|
|
21
|
+
history.push({
|
|
22
|
+
eventId: history.length + 1,
|
|
23
|
+
eventTime: now,
|
|
24
|
+
eventType,
|
|
25
|
+
taskQueue: "muxo-durable-execution-queue",
|
|
26
|
+
attributes,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export function createCloudProvisioningWorkflow(params) {
|
|
30
|
+
const now = new Date().toISOString();
|
|
31
|
+
const region = params.region || "aws-us-east-1";
|
|
32
|
+
const apiVersion = params.apiVersion || "2026-09-30.preview";
|
|
33
|
+
const history = [];
|
|
34
|
+
appendTemporalEvent(history, "EVENT_TYPE_WORKFLOW_EXECUTION_STARTED", {
|
|
35
|
+
workflowType: "cloud_provisioning_pipeline",
|
|
36
|
+
workflowId: params.id,
|
|
37
|
+
workspaceId: params.workspaceId,
|
|
38
|
+
provider: params.provider,
|
|
39
|
+
serviceRef: params.serviceRef,
|
|
40
|
+
region,
|
|
41
|
+
}, now);
|
|
42
|
+
appendTemporalEvent(history, "EVENT_TYPE_ACTIVITY_TASK_COMPLETED", {
|
|
43
|
+
activityName: "check_stripe_v2_eligibility",
|
|
44
|
+
result: { status: "eligible", apiVersion },
|
|
45
|
+
}, now);
|
|
46
|
+
appendTemporalEvent(history, "EVENT_TYPE_ACTIVITY_TASK_COMPLETED", {
|
|
47
|
+
activityName: "ensure_payment_profile_and_provider_connection",
|
|
48
|
+
result: { provider: params.provider, paymentProfileStatus: "active" },
|
|
49
|
+
}, now);
|
|
50
|
+
appendTemporalEvent(history, "EVENT_TYPE_ACTIVITY_TASK_COMPLETED", {
|
|
51
|
+
activityName: "create_v2_provisioning_resource",
|
|
52
|
+
result: {
|
|
53
|
+
resourceId: params.resourceId,
|
|
54
|
+
provider: params.provider,
|
|
55
|
+
service_ref: params.serviceRef,
|
|
56
|
+
region,
|
|
57
|
+
},
|
|
58
|
+
compensationAction: `resource.${params.provider}.remove`,
|
|
59
|
+
}, now);
|
|
60
|
+
appendTemporalEvent(history, "EVENT_TYPE_TIMER_STARTED", {
|
|
61
|
+
waitingForSignal: WORKFLOW_RESOURCE_COMPLETED_EVENT,
|
|
62
|
+
resourceId: params.resourceId,
|
|
63
|
+
}, now);
|
|
64
|
+
const compensations = [
|
|
65
|
+
{
|
|
66
|
+
stepName: "ensure_payment_profile_and_provider_connection",
|
|
67
|
+
compensationAction: `provisioning.provider_connection.unlink`,
|
|
68
|
+
status: "registered",
|
|
69
|
+
description: `Unlink provider connection for ${params.provider} if downstream provisioning aborts`,
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
stepName: "create_v2_provisioning_resource",
|
|
73
|
+
compensationAction: `resource.${params.provider}.remove`,
|
|
74
|
+
status: "registered",
|
|
75
|
+
description: `Deprovision ${params.provider}/${params.serviceRef} (${params.resourceId}) and release reservation`,
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
return {
|
|
79
|
+
id: params.id,
|
|
80
|
+
runId: `run_${params.id}`,
|
|
81
|
+
workspaceId: params.workspaceId,
|
|
82
|
+
workflowType: "cloud_provisioning_pipeline",
|
|
83
|
+
playbookSlug: null,
|
|
84
|
+
status: "waiting_for_event",
|
|
85
|
+
provider: params.provider,
|
|
86
|
+
serviceRef: params.serviceRef,
|
|
87
|
+
resourceId: params.resourceId,
|
|
88
|
+
steps: [
|
|
89
|
+
{
|
|
90
|
+
name: "check_stripe_v2_eligibility",
|
|
91
|
+
primitive: "step.do",
|
|
92
|
+
status: "completed",
|
|
93
|
+
output: { status: "eligible", apiVersion },
|
|
94
|
+
completedAt: now,
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: "ensure_payment_profile_and_provider_connection",
|
|
98
|
+
primitive: "step.do",
|
|
99
|
+
status: "completed",
|
|
100
|
+
output: { provider: params.provider, paymentProfileStatus: "active" },
|
|
101
|
+
completedAt: now,
|
|
102
|
+
compensationAction: "provisioning.provider_connection.unlink",
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: "create_v2_provisioning_resource",
|
|
106
|
+
primitive: "step.do",
|
|
107
|
+
status: "completed",
|
|
108
|
+
output: {
|
|
109
|
+
resourceId: params.resourceId,
|
|
110
|
+
provider: params.provider,
|
|
111
|
+
service_ref: params.serviceRef,
|
|
112
|
+
region,
|
|
113
|
+
},
|
|
114
|
+
completedAt: now,
|
|
115
|
+
compensationAction: `resource.${params.provider}.remove`,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
name: "wait_for_v2_provisioning_resource_completed",
|
|
119
|
+
primitive: "step.waitForEvent",
|
|
120
|
+
status: "waiting",
|
|
121
|
+
output: {
|
|
122
|
+
expectedEvent: WORKFLOW_RESOURCE_COMPLETED_EVENT,
|
|
123
|
+
resourceId: params.resourceId,
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: "reveal_access_configuration_and_seal_vault",
|
|
128
|
+
primitive: "step.do",
|
|
129
|
+
status: "pending",
|
|
130
|
+
compensationAction: "vault.revoke_secrets",
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
compensations,
|
|
134
|
+
signals: [],
|
|
135
|
+
temporalEventHistory: history,
|
|
136
|
+
rollbackReason: null,
|
|
137
|
+
createdAt: now,
|
|
138
|
+
updatedAt: now,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/** Completes every outstanding step once the resource-completed event (or a manual advance) arrives. */
|
|
142
|
+
export function completeCloudProvisioningWorkflow(wf, params) {
|
|
143
|
+
const now = new Date().toISOString();
|
|
144
|
+
const history = wf.temporalEventHistory || [];
|
|
145
|
+
const trigger = String(params.triggerEvent || WORKFLOW_RESOURCE_COMPLETED_EVENT);
|
|
146
|
+
appendTemporalEvent(history, "EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED", {
|
|
147
|
+
signalName: trigger,
|
|
148
|
+
resourceId: wf.resourceId,
|
|
149
|
+
}, now);
|
|
150
|
+
for (const step of wf.steps) {
|
|
151
|
+
if (step.status === "completed")
|
|
152
|
+
continue;
|
|
153
|
+
step.status = "completed";
|
|
154
|
+
step.completedAt = now;
|
|
155
|
+
if (step.name === "reveal_access_configuration_and_seal_vault") {
|
|
156
|
+
step.output = {
|
|
157
|
+
vaultEncrypted: true,
|
|
158
|
+
cipher: "AES-256-GCM",
|
|
159
|
+
secretKeys: params.secretKeys,
|
|
160
|
+
triggerEvent: trigger,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
appendTemporalEvent(history, "EVENT_TYPE_ACTIVITY_TASK_COMPLETED", {
|
|
164
|
+
activityName: step.name,
|
|
165
|
+
result: step.output || { status: "completed" },
|
|
166
|
+
}, now);
|
|
167
|
+
}
|
|
168
|
+
appendTemporalEvent(history, "EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED", {
|
|
169
|
+
workflowId: wf.id,
|
|
170
|
+
status: "completed",
|
|
171
|
+
secretKeysSealed: params.secretKeys,
|
|
172
|
+
}, now);
|
|
173
|
+
wf.temporalEventHistory = history;
|
|
174
|
+
wf.status = "completed";
|
|
175
|
+
wf.updatedAt = now;
|
|
176
|
+
return wf;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Executes LIFO Saga Compensations on a DurableWorkflow, rolling back completed steps in reverse order
|
|
180
|
+
* and recording Temporal compensation activity events.
|
|
181
|
+
*/
|
|
182
|
+
export function rollbackDurableWorkflow(wf, params) {
|
|
183
|
+
const now = new Date().toISOString();
|
|
184
|
+
const failedStepName = params?.failedStepName || params?.failedStep;
|
|
185
|
+
const reason = params?.reason ||
|
|
186
|
+
"Saga rollback requested by operator or downstream step failure";
|
|
187
|
+
const history = wf.temporalEventHistory || [];
|
|
188
|
+
const compensations = wf.compensations || [];
|
|
189
|
+
if (failedStepName) {
|
|
190
|
+
appendTemporalEvent(history, "EVENT_TYPE_ACTIVITY_TASK_FAILED", {
|
|
191
|
+
activityName: failedStepName,
|
|
192
|
+
reason,
|
|
193
|
+
}, now);
|
|
194
|
+
}
|
|
195
|
+
// Execute registered compensations in reverse (LIFO) order
|
|
196
|
+
for (let i = compensations.length - 1; i >= 0; i--) {
|
|
197
|
+
const comp = compensations[i];
|
|
198
|
+
if (comp.status === "executed")
|
|
199
|
+
continue;
|
|
200
|
+
comp.status = "executed";
|
|
201
|
+
comp.executedAt = now;
|
|
202
|
+
comp.output = {
|
|
203
|
+
rolledBack: true,
|
|
204
|
+
action: comp.compensationAction,
|
|
205
|
+
resourceId: wf.resourceId,
|
|
206
|
+
reason,
|
|
207
|
+
};
|
|
208
|
+
appendTemporalEvent(history, "EVENT_TYPE_ACTIVITY_TASK_COMPLETED", {
|
|
209
|
+
activityName: `compensate:${comp.stepName}`,
|
|
210
|
+
compensationAction: comp.compensationAction,
|
|
211
|
+
result: comp.output,
|
|
212
|
+
}, now);
|
|
213
|
+
}
|
|
214
|
+
for (const step of wf.steps) {
|
|
215
|
+
if (step.status === "completed" && step.compensationAction) {
|
|
216
|
+
step.status = "compensated";
|
|
217
|
+
step.compensatedAt = now;
|
|
218
|
+
}
|
|
219
|
+
else if (step.status === "waiting" || step.status === "pending") {
|
|
220
|
+
step.status = "failed";
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
appendTemporalEvent(history, "EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED", {
|
|
224
|
+
workflowId: wf.id,
|
|
225
|
+
status: "rolled_back",
|
|
226
|
+
reason,
|
|
227
|
+
compensatedStepsCount: compensations.filter((c) => c.status === "executed")
|
|
228
|
+
.length,
|
|
229
|
+
}, now);
|
|
230
|
+
wf.compensations = compensations;
|
|
231
|
+
wf.temporalEventHistory = history;
|
|
232
|
+
wf.rollbackReason = reason;
|
|
233
|
+
wf.status = "rolled_back";
|
|
234
|
+
wf.updatedAt = now;
|
|
235
|
+
return wf;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Sends a named Temporal signal to a DurableWorkflow (`human.approval.granted`, `oauth.connection.active`,
|
|
239
|
+
* `saga.abort`, or `v2.provisioning.resource.completed`).
|
|
240
|
+
*/
|
|
241
|
+
export function signalDurableWorkflow(wf, params) {
|
|
242
|
+
const now = new Date().toISOString();
|
|
243
|
+
const signalName = String(params.signalName || WORKFLOW_RESOURCE_COMPLETED_EVENT).trim();
|
|
244
|
+
const payload = params.payload || {};
|
|
245
|
+
wf.signals = wf.signals || [];
|
|
246
|
+
wf.signals.push({
|
|
247
|
+
signalName,
|
|
248
|
+
payload,
|
|
249
|
+
receivedAt: now,
|
|
250
|
+
});
|
|
251
|
+
if (signalName === "saga.abort" ||
|
|
252
|
+
signalName === "human.approval.rejected" ||
|
|
253
|
+
payload.action === "rollback") {
|
|
254
|
+
return rollbackDurableWorkflow(wf, {
|
|
255
|
+
reason: String(payload.reason || `Rolled back via signal ${signalName}`),
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return completeCloudProvisioningWorkflow(wf, {
|
|
259
|
+
secretKeys: params.secretKeys || ["DATABASE_URL"],
|
|
260
|
+
triggerEvent: signalName,
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Exports a DurableWorkflow in Temporal Web UI / `temporal workflow show` compatible EventHistory JSON format.
|
|
265
|
+
*/
|
|
266
|
+
export function exportTemporalEventHistory(wf) {
|
|
267
|
+
const events = wf.temporalEventHistory || [];
|
|
268
|
+
return {
|
|
269
|
+
namespace: `muxo.${wf.workspaceId}`,
|
|
270
|
+
workflowExecution: {
|
|
271
|
+
workflowId: wf.id,
|
|
272
|
+
runId: wf.runId || `run_${wf.id}`,
|
|
273
|
+
},
|
|
274
|
+
workflowType: {
|
|
275
|
+
name: wf.playbookSlug
|
|
276
|
+
? `MuxoPlaybookSaga::${wf.playbookSlug}`
|
|
277
|
+
: `MuxoWorkflow::${wf.workflowType}`,
|
|
278
|
+
},
|
|
279
|
+
status: wf.status,
|
|
280
|
+
eventsCount: events.length,
|
|
281
|
+
compensationsCount: (wf.compensations || []).length,
|
|
282
|
+
events,
|
|
283
|
+
};
|
|
284
|
+
}
|