@agent-relay/cloud 0.1.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/dist/api/admin.d.ts +8 -0
- package/dist/api/admin.d.ts.map +1 -0
- package/dist/api/admin.js +225 -0
- package/dist/api/admin.js.map +1 -0
- package/dist/api/auth.d.ts +20 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +136 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/billing.d.ts +7 -0
- package/dist/api/billing.d.ts.map +1 -0
- package/dist/api/billing.js +564 -0
- package/dist/api/billing.js.map +1 -0
- package/dist/api/cli-pty-runner.d.ts +53 -0
- package/dist/api/cli-pty-runner.d.ts.map +1 -0
- package/dist/api/cli-pty-runner.js +193 -0
- package/dist/api/cli-pty-runner.js.map +1 -0
- package/dist/api/codex-auth-helper.d.ts +21 -0
- package/dist/api/codex-auth-helper.d.ts.map +1 -0
- package/dist/api/codex-auth-helper.js +327 -0
- package/dist/api/codex-auth-helper.js.map +1 -0
- package/dist/api/consensus.d.ts +13 -0
- package/dist/api/consensus.d.ts.map +1 -0
- package/dist/api/consensus.js +261 -0
- package/dist/api/consensus.js.map +1 -0
- package/dist/api/coordinators.d.ts +8 -0
- package/dist/api/coordinators.d.ts.map +1 -0
- package/dist/api/coordinators.js +750 -0
- package/dist/api/coordinators.js.map +1 -0
- package/dist/api/daemons.d.ts +12 -0
- package/dist/api/daemons.d.ts.map +1 -0
- package/dist/api/daemons.js +535 -0
- package/dist/api/daemons.js.map +1 -0
- package/dist/api/generic-webhooks.d.ts +8 -0
- package/dist/api/generic-webhooks.d.ts.map +1 -0
- package/dist/api/generic-webhooks.js +129 -0
- package/dist/api/generic-webhooks.js.map +1 -0
- package/dist/api/git.d.ts +8 -0
- package/dist/api/git.d.ts.map +1 -0
- package/dist/api/git.js +269 -0
- package/dist/api/git.js.map +1 -0
- package/dist/api/github-app.d.ts +11 -0
- package/dist/api/github-app.d.ts.map +1 -0
- package/dist/api/github-app.js +223 -0
- package/dist/api/github-app.js.map +1 -0
- package/dist/api/middleware/planLimits.d.ts +43 -0
- package/dist/api/middleware/planLimits.d.ts.map +1 -0
- package/dist/api/middleware/planLimits.js +202 -0
- package/dist/api/middleware/planLimits.js.map +1 -0
- package/dist/api/monitoring.d.ts +11 -0
- package/dist/api/monitoring.d.ts.map +1 -0
- package/dist/api/monitoring.js +578 -0
- package/dist/api/monitoring.js.map +1 -0
- package/dist/api/nango-auth.d.ts +9 -0
- package/dist/api/nango-auth.d.ts.map +1 -0
- package/dist/api/nango-auth.js +674 -0
- package/dist/api/nango-auth.js.map +1 -0
- package/dist/api/onboarding.d.ts +15 -0
- package/dist/api/onboarding.d.ts.map +1 -0
- package/dist/api/onboarding.js +679 -0
- package/dist/api/onboarding.js.map +1 -0
- package/dist/api/policy.d.ts +8 -0
- package/dist/api/policy.d.ts.map +1 -0
- package/dist/api/policy.js +229 -0
- package/dist/api/policy.js.map +1 -0
- package/dist/api/provider-env.d.ts +14 -0
- package/dist/api/provider-env.d.ts.map +1 -0
- package/dist/api/provider-env.js +75 -0
- package/dist/api/provider-env.js.map +1 -0
- package/dist/api/providers.d.ts +7 -0
- package/dist/api/providers.d.ts.map +1 -0
- package/dist/api/providers.js +564 -0
- package/dist/api/providers.js.map +1 -0
- package/dist/api/repos.d.ts +8 -0
- package/dist/api/repos.d.ts.map +1 -0
- package/dist/api/repos.js +577 -0
- package/dist/api/repos.js.map +1 -0
- package/dist/api/sessions.d.ts +11 -0
- package/dist/api/sessions.d.ts.map +1 -0
- package/dist/api/sessions.js +302 -0
- package/dist/api/sessions.js.map +1 -0
- package/dist/api/teams.d.ts +7 -0
- package/dist/api/teams.d.ts.map +1 -0
- package/dist/api/teams.js +281 -0
- package/dist/api/teams.js.map +1 -0
- package/dist/api/test-helpers.d.ts +10 -0
- package/dist/api/test-helpers.d.ts.map +1 -0
- package/dist/api/test-helpers.js +745 -0
- package/dist/api/test-helpers.js.map +1 -0
- package/dist/api/usage.d.ts +7 -0
- package/dist/api/usage.d.ts.map +1 -0
- package/dist/api/usage.js +111 -0
- package/dist/api/usage.js.map +1 -0
- package/dist/api/webhooks.d.ts +8 -0
- package/dist/api/webhooks.d.ts.map +1 -0
- package/dist/api/webhooks.js +645 -0
- package/dist/api/webhooks.js.map +1 -0
- package/dist/api/workspaces.d.ts +25 -0
- package/dist/api/workspaces.d.ts.map +1 -0
- package/dist/api/workspaces.js +1799 -0
- package/dist/api/workspaces.js.map +1 -0
- package/dist/billing/index.d.ts +9 -0
- package/dist/billing/index.d.ts.map +1 -0
- package/dist/billing/index.js +9 -0
- package/dist/billing/index.js.map +1 -0
- package/dist/billing/plans.d.ts +39 -0
- package/dist/billing/plans.d.ts.map +1 -0
- package/dist/billing/plans.js +245 -0
- package/dist/billing/plans.js.map +1 -0
- package/dist/billing/service.d.ts +80 -0
- package/dist/billing/service.d.ts.map +1 -0
- package/dist/billing/service.js +388 -0
- package/dist/billing/service.js.map +1 -0
- package/dist/billing/types.d.ts +141 -0
- package/dist/billing/types.d.ts.map +1 -0
- package/dist/billing/types.js +7 -0
- package/dist/billing/types.js.map +1 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -0
- package/dist/db/bulk-ingest.d.ts +89 -0
- package/dist/db/bulk-ingest.d.ts.map +1 -0
- package/dist/db/bulk-ingest.js +268 -0
- package/dist/db/bulk-ingest.js.map +1 -0
- package/dist/db/drizzle.d.ts +256 -0
- package/dist/db/drizzle.d.ts.map +1 -0
- package/dist/db/drizzle.js +1286 -0
- package/dist/db/drizzle.js.map +1 -0
- package/dist/db/index.d.ts +55 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +68 -0
- package/dist/db/index.js.map +1 -0
- package/dist/db/schema.d.ts +4873 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +620 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/provisioner/index.d.ts +207 -0
- package/dist/provisioner/index.d.ts.map +1 -0
- package/dist/provisioner/index.js +2114 -0
- package/dist/provisioner/index.js.map +1 -0
- package/dist/server.d.ts +17 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +1924 -0
- package/dist/server.js.map +1 -0
- package/dist/services/auto-scaler.d.ts +152 -0
- package/dist/services/auto-scaler.d.ts.map +1 -0
- package/dist/services/auto-scaler.js +439 -0
- package/dist/services/auto-scaler.js.map +1 -0
- package/dist/services/capacity-manager.d.ts +148 -0
- package/dist/services/capacity-manager.d.ts.map +1 -0
- package/dist/services/capacity-manager.js +449 -0
- package/dist/services/capacity-manager.js.map +1 -0
- package/dist/services/ci-agent-spawner.d.ts +49 -0
- package/dist/services/ci-agent-spawner.d.ts.map +1 -0
- package/dist/services/ci-agent-spawner.js +373 -0
- package/dist/services/ci-agent-spawner.js.map +1 -0
- package/dist/services/cloud-message-bus.d.ts +28 -0
- package/dist/services/cloud-message-bus.d.ts.map +1 -0
- package/dist/services/cloud-message-bus.js +19 -0
- package/dist/services/cloud-message-bus.js.map +1 -0
- package/dist/services/compute-enforcement.d.ts +57 -0
- package/dist/services/compute-enforcement.d.ts.map +1 -0
- package/dist/services/compute-enforcement.js +175 -0
- package/dist/services/compute-enforcement.js.map +1 -0
- package/dist/services/coordinator.d.ts +62 -0
- package/dist/services/coordinator.d.ts.map +1 -0
- package/dist/services/coordinator.js +389 -0
- package/dist/services/coordinator.js.map +1 -0
- package/dist/services/index.d.ts +17 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +25 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/intro-expiration.d.ts +60 -0
- package/dist/services/intro-expiration.d.ts.map +1 -0
- package/dist/services/intro-expiration.js +252 -0
- package/dist/services/intro-expiration.js.map +1 -0
- package/dist/services/mention-handler.d.ts +65 -0
- package/dist/services/mention-handler.d.ts.map +1 -0
- package/dist/services/mention-handler.js +405 -0
- package/dist/services/mention-handler.js.map +1 -0
- package/dist/services/nango.d.ts +201 -0
- package/dist/services/nango.d.ts.map +1 -0
- package/dist/services/nango.js +392 -0
- package/dist/services/nango.js.map +1 -0
- package/dist/services/persistence.d.ts +131 -0
- package/dist/services/persistence.d.ts.map +1 -0
- package/dist/services/persistence.js +200 -0
- package/dist/services/persistence.js.map +1 -0
- package/dist/services/planLimits.d.ts +147 -0
- package/dist/services/planLimits.d.ts.map +1 -0
- package/dist/services/planLimits.js +335 -0
- package/dist/services/planLimits.js.map +1 -0
- package/dist/services/presence-registry.d.ts +56 -0
- package/dist/services/presence-registry.d.ts.map +1 -0
- package/dist/services/presence-registry.js +91 -0
- package/dist/services/presence-registry.js.map +1 -0
- package/dist/services/scaling-orchestrator.d.ts +159 -0
- package/dist/services/scaling-orchestrator.d.ts.map +1 -0
- package/dist/services/scaling-orchestrator.js +502 -0
- package/dist/services/scaling-orchestrator.js.map +1 -0
- package/dist/services/scaling-policy.d.ts +121 -0
- package/dist/services/scaling-policy.d.ts.map +1 -0
- package/dist/services/scaling-policy.js +415 -0
- package/dist/services/scaling-policy.js.map +1 -0
- package/dist/services/ssh-security.d.ts +31 -0
- package/dist/services/ssh-security.d.ts.map +1 -0
- package/dist/services/ssh-security.js +63 -0
- package/dist/services/ssh-security.js.map +1 -0
- package/dist/services/workspace-keepalive.d.ts +76 -0
- package/dist/services/workspace-keepalive.d.ts.map +1 -0
- package/dist/services/workspace-keepalive.js +234 -0
- package/dist/services/workspace-keepalive.js.map +1 -0
- package/dist/shims/consensus.d.ts +23 -0
- package/dist/shims/consensus.d.ts.map +1 -0
- package/dist/shims/consensus.js +5 -0
- package/dist/shims/consensus.js.map +1 -0
- package/dist/webhooks/index.d.ts +24 -0
- package/dist/webhooks/index.d.ts.map +1 -0
- package/dist/webhooks/index.js +29 -0
- package/dist/webhooks/index.js.map +1 -0
- package/dist/webhooks/parsers/github.d.ts +8 -0
- package/dist/webhooks/parsers/github.d.ts.map +1 -0
- package/dist/webhooks/parsers/github.js +234 -0
- package/dist/webhooks/parsers/github.js.map +1 -0
- package/dist/webhooks/parsers/index.d.ts +23 -0
- package/dist/webhooks/parsers/index.d.ts.map +1 -0
- package/dist/webhooks/parsers/index.js +30 -0
- package/dist/webhooks/parsers/index.js.map +1 -0
- package/dist/webhooks/parsers/linear.d.ts +9 -0
- package/dist/webhooks/parsers/linear.d.ts.map +1 -0
- package/dist/webhooks/parsers/linear.js +258 -0
- package/dist/webhooks/parsers/linear.js.map +1 -0
- package/dist/webhooks/parsers/slack.d.ts +9 -0
- package/dist/webhooks/parsers/slack.d.ts.map +1 -0
- package/dist/webhooks/parsers/slack.js +214 -0
- package/dist/webhooks/parsers/slack.js.map +1 -0
- package/dist/webhooks/responders/github.d.ts +8 -0
- package/dist/webhooks/responders/github.d.ts.map +1 -0
- package/dist/webhooks/responders/github.js +73 -0
- package/dist/webhooks/responders/github.js.map +1 -0
- package/dist/webhooks/responders/index.d.ts +23 -0
- package/dist/webhooks/responders/index.d.ts.map +1 -0
- package/dist/webhooks/responders/index.js +30 -0
- package/dist/webhooks/responders/index.js.map +1 -0
- package/dist/webhooks/responders/linear.d.ts +9 -0
- package/dist/webhooks/responders/linear.d.ts.map +1 -0
- package/dist/webhooks/responders/linear.js +149 -0
- package/dist/webhooks/responders/linear.js.map +1 -0
- package/dist/webhooks/responders/slack.d.ts +20 -0
- package/dist/webhooks/responders/slack.d.ts.map +1 -0
- package/dist/webhooks/responders/slack.js +178 -0
- package/dist/webhooks/responders/slack.js.map +1 -0
- package/dist/webhooks/router.d.ts +25 -0
- package/dist/webhooks/router.d.ts.map +1 -0
- package/dist/webhooks/router.js +504 -0
- package/dist/webhooks/router.js.map +1 -0
- package/dist/webhooks/rules-engine.d.ts +24 -0
- package/dist/webhooks/rules-engine.d.ts.map +1 -0
- package/dist/webhooks/rules-engine.js +287 -0
- package/dist/webhooks/rules-engine.js.map +1 -0
- package/dist/webhooks/types.d.ts +186 -0
- package/dist/webhooks/types.d.ts.map +1 -0
- package/dist/webhooks/types.js +8 -0
- package/dist/webhooks/types.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Relay Cloud - Billing API
|
|
3
|
+
*
|
|
4
|
+
* REST API for subscription and billing management.
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
import { getBillingService, getAllPlans, getPlan, comparePlans } from '../billing/index.js';
|
|
8
|
+
import { getConfig, isAdminUser } from '../config.js';
|
|
9
|
+
import { db } from '../db/index.js';
|
|
10
|
+
import { requireAuth } from './auth.js';
|
|
11
|
+
import { getProvisioner, RESOURCE_TIERS } from '../provisioner/index.js';
|
|
12
|
+
import { getResourceTierForPlan } from '../services/planLimits.js';
|
|
13
|
+
export const billingRouter = Router();
|
|
14
|
+
/**
|
|
15
|
+
* Get the count of connected agents in a running workspace
|
|
16
|
+
* Returns 0 if workspace is not reachable or has no agents
|
|
17
|
+
*/
|
|
18
|
+
async function getWorkspaceAgentCount(publicUrl) {
|
|
19
|
+
try {
|
|
20
|
+
const controller = new AbortController();
|
|
21
|
+
const timeout = setTimeout(() => controller.abort(), 5000);
|
|
22
|
+
const response = await fetch(`${publicUrl}/agents`, {
|
|
23
|
+
signal: controller.signal,
|
|
24
|
+
});
|
|
25
|
+
clearTimeout(timeout);
|
|
26
|
+
if (!response.ok)
|
|
27
|
+
return 0;
|
|
28
|
+
const data = await response.json();
|
|
29
|
+
return data.agents?.length ?? 0;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Workspace not reachable or error - assume no agents
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Resize user's workspaces to match their new plan tier
|
|
38
|
+
* Called after plan upgrade/downgrade to adjust compute resources
|
|
39
|
+
*
|
|
40
|
+
* Strategy:
|
|
41
|
+
* - Stopped workspaces: Resize immediately (no disruption)
|
|
42
|
+
* - Running workspaces with no agents: Resize immediately (safe to restart)
|
|
43
|
+
* - Running workspaces with agents: Save config for next restart (no agent disruption)
|
|
44
|
+
*
|
|
45
|
+
* Returns info about which workspaces were deferred so we can inform the user.
|
|
46
|
+
*/
|
|
47
|
+
async function resizeWorkspacesForPlan(userId, newPlan) {
|
|
48
|
+
const result = { resized: 0, deferred: [], failed: 0 };
|
|
49
|
+
try {
|
|
50
|
+
const workspaces = await db.workspaces.findByUserId(userId);
|
|
51
|
+
if (workspaces.length === 0)
|
|
52
|
+
return result;
|
|
53
|
+
const provisioner = getProvisioner();
|
|
54
|
+
const targetTierName = getResourceTierForPlan(newPlan);
|
|
55
|
+
const targetTier = RESOURCE_TIERS[targetTierName];
|
|
56
|
+
console.log(`[billing] Upgrading ${workspaces.length} workspace(s) for user ${userId.substring(0, 8)} to ${targetTierName}`);
|
|
57
|
+
for (const workspace of workspaces) {
|
|
58
|
+
if (workspace.status !== 'running' && workspace.status !== 'stopped') {
|
|
59
|
+
console.log(`[billing] Skipping workspace ${workspace.id.substring(0, 8)} (status: ${workspace.status})`);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
let skipRestart = false;
|
|
64
|
+
let agentCount = 0;
|
|
65
|
+
// For running workspaces: check if there are active agents
|
|
66
|
+
if (workspace.status === 'running' && workspace.publicUrl) {
|
|
67
|
+
agentCount = await getWorkspaceAgentCount(workspace.publicUrl);
|
|
68
|
+
if (agentCount > 0) {
|
|
69
|
+
// Has active agents - don't disrupt them
|
|
70
|
+
skipRestart = true;
|
|
71
|
+
console.log(`[billing] Workspace ${workspace.id.substring(0, 8)} has ${agentCount} active agent(s), deferring resize`);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// No active agents - safe to restart immediately
|
|
75
|
+
console.log(`[billing] Workspace ${workspace.id.substring(0, 8)} has no active agents, proceeding with immediate resize`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
await provisioner.resize(workspace.id, targetTier, skipRestart);
|
|
79
|
+
if (skipRestart) {
|
|
80
|
+
console.log(`[billing] Queued resize for workspace ${workspace.id.substring(0, 8)} to ${targetTierName} (will apply on next restart)`);
|
|
81
|
+
result.deferred.push({
|
|
82
|
+
workspaceId: workspace.id,
|
|
83
|
+
workspaceName: workspace.name,
|
|
84
|
+
agentCount,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
console.log(`[billing] Resized workspace ${workspace.id.substring(0, 8)} to ${targetTierName}`);
|
|
89
|
+
result.resized++;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
console.error(`[billing] Failed to resize workspace ${workspace.id}:`, error);
|
|
94
|
+
result.failed++;
|
|
95
|
+
// Continue with other workspaces even if one fails
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
console.error('[billing] Failed to resize workspaces:', error);
|
|
101
|
+
}
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* GET /api/billing/plans
|
|
106
|
+
* Get all available billing plans
|
|
107
|
+
*/
|
|
108
|
+
billingRouter.get('/plans', (req, res) => {
|
|
109
|
+
const rawPlans = getAllPlans();
|
|
110
|
+
// Transform plans to frontend format
|
|
111
|
+
const plans = rawPlans.map((plan) => ({
|
|
112
|
+
tier: plan.id,
|
|
113
|
+
name: plan.name,
|
|
114
|
+
description: plan.description,
|
|
115
|
+
price: {
|
|
116
|
+
monthly: plan.priceMonthly / 100, // Convert cents to dollars
|
|
117
|
+
yearly: plan.priceYearly / 100,
|
|
118
|
+
},
|
|
119
|
+
features: plan.features,
|
|
120
|
+
limits: plan.limits,
|
|
121
|
+
recommended: plan.id === 'pro',
|
|
122
|
+
}));
|
|
123
|
+
// Add publishable key for frontend
|
|
124
|
+
const config = getConfig();
|
|
125
|
+
res.json({
|
|
126
|
+
plans,
|
|
127
|
+
publishableKey: config.stripe.publishableKey,
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
/**
|
|
131
|
+
* GET /api/billing/plans/:tier
|
|
132
|
+
* Get a specific plan by tier
|
|
133
|
+
*/
|
|
134
|
+
billingRouter.get('/plans/:tier', (req, res) => {
|
|
135
|
+
const tier = req.params.tier;
|
|
136
|
+
try {
|
|
137
|
+
const plan = getPlan(tier);
|
|
138
|
+
res.json({ plan });
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
res.status(404).json({ error: 'Plan not found' });
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
/**
|
|
145
|
+
* GET /api/billing/compare
|
|
146
|
+
* Compare two plans
|
|
147
|
+
*/
|
|
148
|
+
billingRouter.get('/compare', (req, res) => {
|
|
149
|
+
const { from, to } = req.query;
|
|
150
|
+
if (!from || !to) {
|
|
151
|
+
res.status(400).json({ error: 'Missing from or to parameter' });
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
const comparison = comparePlans(from, to);
|
|
156
|
+
res.json({ comparison });
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
res.status(400).json({ error: 'Invalid plan tier' });
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
/**
|
|
163
|
+
* GET /api/billing/subscription
|
|
164
|
+
* Get current user's subscription status
|
|
165
|
+
*/
|
|
166
|
+
billingRouter.get('/subscription', requireAuth, async (req, res) => {
|
|
167
|
+
const userId = req.session.userId;
|
|
168
|
+
try {
|
|
169
|
+
// Fetch user from database
|
|
170
|
+
const user = await db.users.findById(userId);
|
|
171
|
+
if (!user) {
|
|
172
|
+
return res.status(404).json({ error: 'User not found' });
|
|
173
|
+
}
|
|
174
|
+
// Admin users have special status - show their current plan without Stripe
|
|
175
|
+
if (isAdminUser(user.githubUsername)) {
|
|
176
|
+
return res.json({
|
|
177
|
+
tier: user.plan || 'enterprise',
|
|
178
|
+
subscription: null,
|
|
179
|
+
customer: null,
|
|
180
|
+
isAdmin: true,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
// If user doesn't have a Stripe customer ID, use the database plan value
|
|
184
|
+
// This handles manually-set plans and prevents hanging on Stripe API calls
|
|
185
|
+
if (!user.stripeCustomerId) {
|
|
186
|
+
return res.json({
|
|
187
|
+
tier: user.plan || 'free',
|
|
188
|
+
subscription: null,
|
|
189
|
+
customer: null,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
const billing = getBillingService();
|
|
193
|
+
// Get or create Stripe customer
|
|
194
|
+
const customerId = user.stripeCustomerId ||
|
|
195
|
+
await billing.getOrCreateCustomer(user.id, user.email || '', user.githubUsername);
|
|
196
|
+
// Save customer ID to database if newly created
|
|
197
|
+
if (!user.stripeCustomerId) {
|
|
198
|
+
await db.users.update(userId, { stripeCustomerId: customerId });
|
|
199
|
+
}
|
|
200
|
+
// Get customer details
|
|
201
|
+
const customer = await billing.getCustomer(customerId);
|
|
202
|
+
if (!customer) {
|
|
203
|
+
res.json({
|
|
204
|
+
tier: 'free',
|
|
205
|
+
subscription: null,
|
|
206
|
+
customer: null,
|
|
207
|
+
});
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
// Use Stripe subscription tier if active, otherwise fall back to database plan value
|
|
211
|
+
// This allows manual plan overrides in the database to take effect
|
|
212
|
+
const tier = customer.subscription?.tier || user.plan || 'free';
|
|
213
|
+
res.json({
|
|
214
|
+
tier,
|
|
215
|
+
subscription: customer.subscription,
|
|
216
|
+
customer: {
|
|
217
|
+
id: customer.id,
|
|
218
|
+
email: customer.email,
|
|
219
|
+
name: customer.name,
|
|
220
|
+
paymentMethods: customer.paymentMethods,
|
|
221
|
+
invoices: customer.invoices,
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
console.error('Failed to get subscription:', error);
|
|
227
|
+
res.status(500).json({ error: 'Failed to get subscription status' });
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
/**
|
|
231
|
+
* POST /api/billing/checkout
|
|
232
|
+
* Create a checkout session for subscription
|
|
233
|
+
*/
|
|
234
|
+
billingRouter.post('/checkout', requireAuth, async (req, res) => {
|
|
235
|
+
const userId = req.session.userId;
|
|
236
|
+
const { tier, interval = 'month' } = req.body;
|
|
237
|
+
if (!tier || !['pro', 'team', 'enterprise'].includes(tier)) {
|
|
238
|
+
res.status(400).json({ error: 'Invalid tier' });
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (!['month', 'year'].includes(interval)) {
|
|
242
|
+
res.status(400).json({ error: 'Invalid billing interval' });
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const config = getConfig();
|
|
246
|
+
try {
|
|
247
|
+
// Fetch user from database
|
|
248
|
+
const user = await db.users.findById(userId);
|
|
249
|
+
if (!user) {
|
|
250
|
+
return res.status(404).json({ error: 'User not found' });
|
|
251
|
+
}
|
|
252
|
+
// Admin users get free upgrades - skip Stripe entirely
|
|
253
|
+
if (isAdminUser(user.githubUsername)) {
|
|
254
|
+
// Update user plan directly
|
|
255
|
+
await db.users.update(userId, { plan: tier });
|
|
256
|
+
console.log(`[billing] Admin user ${user.githubUsername} upgraded to ${tier} (free)`);
|
|
257
|
+
// Resize workspaces to match new plan (wait for result to inform user)
|
|
258
|
+
const resizeResult = await resizeWorkspacesForPlan(userId, tier);
|
|
259
|
+
// Build success URL with deferred workspace info if any
|
|
260
|
+
let successUrl = `${config.appUrl}/billing/success?admin=true`;
|
|
261
|
+
if (resizeResult.deferred.length > 0) {
|
|
262
|
+
// Encode deferred workspaces info for the frontend to display
|
|
263
|
+
const deferredInfo = encodeURIComponent(JSON.stringify(resizeResult.deferred));
|
|
264
|
+
successUrl += `&deferred=${deferredInfo}`;
|
|
265
|
+
}
|
|
266
|
+
// Return a fake session that redirects to success
|
|
267
|
+
return res.json({
|
|
268
|
+
sessionId: 'admin-upgrade',
|
|
269
|
+
checkoutUrl: successUrl,
|
|
270
|
+
resizeResult, // Also include in response for API consumers
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
const billing = getBillingService();
|
|
274
|
+
// Get or create customer
|
|
275
|
+
const customerId = user.stripeCustomerId ||
|
|
276
|
+
await billing.getOrCreateCustomer(user.id, user.email || '', user.githubUsername);
|
|
277
|
+
// Save customer ID to database
|
|
278
|
+
if (!user.stripeCustomerId) {
|
|
279
|
+
await db.users.update(userId, { stripeCustomerId: customerId });
|
|
280
|
+
}
|
|
281
|
+
// Create checkout session
|
|
282
|
+
const session = await billing.createCheckoutSession(customerId, tier, interval, `${config.appUrl}/billing/success?session_id={CHECKOUT_SESSION_ID}`, `${config.appUrl}/billing/canceled`);
|
|
283
|
+
res.json(session);
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
console.error('Failed to create checkout session:', error);
|
|
287
|
+
res.status(500).json({ error: 'Failed to create checkout session' });
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
/**
|
|
291
|
+
* POST /api/billing/portal
|
|
292
|
+
* Create a billing portal session for managing subscription
|
|
293
|
+
*/
|
|
294
|
+
billingRouter.post('/portal', requireAuth, async (req, res) => {
|
|
295
|
+
const userId = req.session.userId;
|
|
296
|
+
try {
|
|
297
|
+
const user = await db.users.findById(userId);
|
|
298
|
+
if (!user) {
|
|
299
|
+
return res.status(404).json({ error: 'User not found' });
|
|
300
|
+
}
|
|
301
|
+
if (!user.stripeCustomerId) {
|
|
302
|
+
res.status(400).json({ error: 'No billing account found' });
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const billing = getBillingService();
|
|
306
|
+
const config = getConfig();
|
|
307
|
+
const session = await billing.createPortalSession(user.stripeCustomerId, `${config.appUrl}/billing`);
|
|
308
|
+
res.json(session);
|
|
309
|
+
}
|
|
310
|
+
catch (error) {
|
|
311
|
+
console.error('Failed to create portal session:', error);
|
|
312
|
+
res.status(500).json({ error: 'Failed to create billing portal' });
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
/**
|
|
316
|
+
* POST /api/billing/change
|
|
317
|
+
* Change subscription tier
|
|
318
|
+
*/
|
|
319
|
+
billingRouter.post('/change', requireAuth, async (req, res) => {
|
|
320
|
+
const userId = req.session.userId;
|
|
321
|
+
const { tier, interval = 'month' } = req.body;
|
|
322
|
+
if (!tier || !['free', 'pro', 'team', 'enterprise'].includes(tier)) {
|
|
323
|
+
res.status(400).json({ error: 'Invalid tier' });
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
try {
|
|
327
|
+
const user = await db.users.findById(userId);
|
|
328
|
+
if (!user) {
|
|
329
|
+
return res.status(404).json({ error: 'User not found' });
|
|
330
|
+
}
|
|
331
|
+
if (!user.stripeCustomerId) {
|
|
332
|
+
res.status(400).json({ error: 'No billing account found' });
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const billing = getBillingService();
|
|
336
|
+
// Get current subscription
|
|
337
|
+
const customer = await billing.getCustomer(user.stripeCustomerId);
|
|
338
|
+
if (!customer?.subscription) {
|
|
339
|
+
res.status(400).json({ error: 'No active subscription' });
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
// Handle downgrade to free (cancel)
|
|
343
|
+
if (tier === 'free') {
|
|
344
|
+
const subscription = await billing.cancelSubscription(customer.subscription.stripeSubscriptionId);
|
|
345
|
+
res.json({ subscription, message: 'Subscription will be canceled at period end' });
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
// Change subscription
|
|
349
|
+
const subscription = await billing.changeSubscription(customer.subscription.stripeSubscriptionId, tier, interval);
|
|
350
|
+
res.json({ subscription });
|
|
351
|
+
}
|
|
352
|
+
catch (error) {
|
|
353
|
+
console.error('Failed to change subscription:', error);
|
|
354
|
+
res.status(500).json({ error: 'Failed to change subscription' });
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
/**
|
|
358
|
+
* POST /api/billing/cancel
|
|
359
|
+
* Cancel subscription at period end
|
|
360
|
+
*/
|
|
361
|
+
billingRouter.post('/cancel', requireAuth, async (req, res) => {
|
|
362
|
+
const userId = req.session.userId;
|
|
363
|
+
try {
|
|
364
|
+
const user = await db.users.findById(userId);
|
|
365
|
+
if (!user) {
|
|
366
|
+
return res.status(404).json({ error: 'User not found' });
|
|
367
|
+
}
|
|
368
|
+
if (!user.stripeCustomerId) {
|
|
369
|
+
res.status(400).json({ error: 'No billing account found' });
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const billing = getBillingService();
|
|
373
|
+
const customer = await billing.getCustomer(user.stripeCustomerId);
|
|
374
|
+
if (!customer?.subscription) {
|
|
375
|
+
res.status(400).json({ error: 'No active subscription' });
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
const subscription = await billing.cancelSubscription(customer.subscription.stripeSubscriptionId);
|
|
379
|
+
res.json({
|
|
380
|
+
subscription,
|
|
381
|
+
message: `Subscription will be canceled on ${subscription.currentPeriodEnd.toLocaleDateString()}`,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
catch (error) {
|
|
385
|
+
console.error('Failed to cancel subscription:', error);
|
|
386
|
+
res.status(500).json({ error: 'Failed to cancel subscription' });
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
/**
|
|
390
|
+
* POST /api/billing/resume
|
|
391
|
+
* Resume a canceled subscription
|
|
392
|
+
*/
|
|
393
|
+
billingRouter.post('/resume', requireAuth, async (req, res) => {
|
|
394
|
+
const userId = req.session.userId;
|
|
395
|
+
try {
|
|
396
|
+
const user = await db.users.findById(userId);
|
|
397
|
+
if (!user) {
|
|
398
|
+
return res.status(404).json({ error: 'User not found' });
|
|
399
|
+
}
|
|
400
|
+
if (!user.stripeCustomerId) {
|
|
401
|
+
res.status(400).json({ error: 'No billing account found' });
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
const billing = getBillingService();
|
|
405
|
+
const customer = await billing.getCustomer(user.stripeCustomerId);
|
|
406
|
+
if (!customer?.subscription) {
|
|
407
|
+
res.status(400).json({ error: 'No subscription to resume' });
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
if (!customer.subscription.cancelAtPeriodEnd) {
|
|
411
|
+
res.status(400).json({ error: 'Subscription is not set to cancel' });
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
const subscription = await billing.resumeSubscription(customer.subscription.stripeSubscriptionId);
|
|
415
|
+
res.json({ subscription, message: 'Subscription resumed' });
|
|
416
|
+
}
|
|
417
|
+
catch (error) {
|
|
418
|
+
console.error('Failed to resume subscription:', error);
|
|
419
|
+
res.status(500).json({ error: 'Failed to resume subscription' });
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
/**
|
|
423
|
+
* GET /api/billing/invoices
|
|
424
|
+
* Get user's invoices
|
|
425
|
+
*/
|
|
426
|
+
billingRouter.get('/invoices', requireAuth, async (req, res) => {
|
|
427
|
+
const userId = req.session.userId;
|
|
428
|
+
try {
|
|
429
|
+
const user = await db.users.findById(userId);
|
|
430
|
+
if (!user) {
|
|
431
|
+
return res.status(404).json({ error: 'User not found' });
|
|
432
|
+
}
|
|
433
|
+
// No Stripe customer = no invoices, skip Stripe call entirely
|
|
434
|
+
if (!user.stripeCustomerId) {
|
|
435
|
+
return res.json({ invoices: [] });
|
|
436
|
+
}
|
|
437
|
+
const billing = getBillingService();
|
|
438
|
+
const customer = await billing.getCustomer(user.stripeCustomerId);
|
|
439
|
+
res.json({ invoices: customer?.invoices || [] });
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
console.error('Failed to get invoices:', error);
|
|
443
|
+
res.status(500).json({ error: 'Failed to get invoices' });
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
/**
|
|
447
|
+
* GET /api/billing/upcoming
|
|
448
|
+
* Get upcoming invoice preview
|
|
449
|
+
*/
|
|
450
|
+
billingRouter.get('/upcoming', requireAuth, async (req, res) => {
|
|
451
|
+
const userId = req.session.userId;
|
|
452
|
+
try {
|
|
453
|
+
const user = await db.users.findById(userId);
|
|
454
|
+
if (!user) {
|
|
455
|
+
return res.status(404).json({ error: 'User not found' });
|
|
456
|
+
}
|
|
457
|
+
if (!user.stripeCustomerId) {
|
|
458
|
+
res.json({ invoice: null });
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
const billing = getBillingService();
|
|
462
|
+
const invoice = await billing.getUpcomingInvoice(user.stripeCustomerId);
|
|
463
|
+
res.json({ invoice });
|
|
464
|
+
}
|
|
465
|
+
catch (error) {
|
|
466
|
+
console.error('Failed to get upcoming invoice:', error);
|
|
467
|
+
res.status(500).json({ error: 'Failed to get upcoming invoice' });
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
/**
|
|
471
|
+
* POST /api/billing/webhook
|
|
472
|
+
* Handle Stripe webhooks
|
|
473
|
+
*/
|
|
474
|
+
billingRouter.post('/webhook',
|
|
475
|
+
// Use raw body for webhook signature verification
|
|
476
|
+
(req, res, next) => {
|
|
477
|
+
if (req.headers['content-type'] === 'application/json') {
|
|
478
|
+
next();
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
next();
|
|
482
|
+
}
|
|
483
|
+
}, async (req, res) => {
|
|
484
|
+
const sig = req.headers['stripe-signature'];
|
|
485
|
+
if (!sig) {
|
|
486
|
+
res.status(400).json({ error: 'Missing signature' });
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
const billing = getBillingService();
|
|
490
|
+
try {
|
|
491
|
+
// Use the preserved raw body from express.json verify callback
|
|
492
|
+
// This is critical for Stripe signature verification - JSON.stringify(req.body) won't work
|
|
493
|
+
const rawBody = req.rawBody;
|
|
494
|
+
if (!rawBody) {
|
|
495
|
+
console.error('Raw body not available for Stripe webhook verification');
|
|
496
|
+
res.status(400).json({ error: 'Raw body not available' });
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
// Verify and parse event
|
|
500
|
+
const event = billing.verifyWebhookSignature(rawBody, sig);
|
|
501
|
+
// Process the event
|
|
502
|
+
const billingEvent = await billing.processWebhookEvent(event);
|
|
503
|
+
// Log for debugging
|
|
504
|
+
console.log('Processed billing event:', {
|
|
505
|
+
id: billingEvent.id,
|
|
506
|
+
type: billingEvent.type,
|
|
507
|
+
userId: billingEvent.userId,
|
|
508
|
+
});
|
|
509
|
+
// Handle specific events
|
|
510
|
+
switch (billingEvent.type) {
|
|
511
|
+
case 'subscription.created':
|
|
512
|
+
case 'subscription.updated': {
|
|
513
|
+
// Extract subscription tier and update user's plan
|
|
514
|
+
if (billingEvent.userId) {
|
|
515
|
+
const subscription = billingEvent.data;
|
|
516
|
+
const tier = billing.getTierFromSubscription(subscription);
|
|
517
|
+
// Update user's plan in database
|
|
518
|
+
await db.users.update(billingEvent.userId, { plan: tier });
|
|
519
|
+
console.log(`Updated user ${billingEvent.userId} plan to: ${tier}`);
|
|
520
|
+
// Resize workspaces to match new plan (async, don't block webhook)
|
|
521
|
+
resizeWorkspacesForPlan(billingEvent.userId, tier).then((result) => {
|
|
522
|
+
if (result.deferred.length > 0) {
|
|
523
|
+
console.log(`[billing] User ${billingEvent.userId} upgrade: ${result.resized} resized, ${result.deferred.length} deferred (have active agents)`);
|
|
524
|
+
result.deferred.forEach((d) => {
|
|
525
|
+
console.log(`[billing] - "${d.workspaceName}" has ${d.agentCount} agent(s), will resize on next restart`);
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
console.log(`[billing] User ${billingEvent.userId} upgrade: all ${result.resized} workspace(s) resized immediately`);
|
|
530
|
+
}
|
|
531
|
+
}).catch((err) => {
|
|
532
|
+
console.error(`Failed to resize workspaces for user ${billingEvent.userId}:`, err);
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
console.warn('Subscription event received without userId:', billingEvent.id);
|
|
537
|
+
}
|
|
538
|
+
break;
|
|
539
|
+
}
|
|
540
|
+
case 'subscription.canceled': {
|
|
541
|
+
// Reset user to free plan
|
|
542
|
+
if (billingEvent.userId) {
|
|
543
|
+
await db.users.update(billingEvent.userId, { plan: 'free' });
|
|
544
|
+
console.log(`User ${billingEvent.userId} subscription canceled, reset to free plan`);
|
|
545
|
+
// Resize workspaces down to free tier (async)
|
|
546
|
+
resizeWorkspacesForPlan(billingEvent.userId, 'free').catch((err) => {
|
|
547
|
+
console.error(`Failed to resize workspaces for user ${billingEvent.userId}:`, err);
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
case 'invoice.payment_failed':
|
|
553
|
+
// Log payment failure (don't immediately downgrade - Stripe retries)
|
|
554
|
+
console.log('Payment failed for user:', billingEvent.userId);
|
|
555
|
+
break;
|
|
556
|
+
}
|
|
557
|
+
res.json({ received: true });
|
|
558
|
+
}
|
|
559
|
+
catch (error) {
|
|
560
|
+
console.error('Webhook error:', error);
|
|
561
|
+
res.status(400).json({ error: 'Webhook verification failed' });
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
//# sourceMappingURL=billing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"billing.js","sourceRoot":"","sources":["../../src/api/billing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI PTY Runner
|
|
3
|
+
*
|
|
4
|
+
* Shared module for running CLI auth flows via PTY.
|
|
5
|
+
* Used by both production (onboarding.ts) and tests (ci-test-real-clis.ts).
|
|
6
|
+
*
|
|
7
|
+
* Uses the relay-pty Rust binary for PTY emulation.
|
|
8
|
+
*/
|
|
9
|
+
import { CLI_AUTH_CONFIG, stripAnsiCodes, matchesSuccessPattern, findMatchingPrompt, validateProviderConfig, getSupportedProviders, type CLIAuthConfig, type PromptHandler } from '@agent-relay/config/cli-auth-config';
|
|
10
|
+
export { CLI_AUTH_CONFIG, stripAnsiCodes, matchesSuccessPattern, findMatchingPrompt, validateProviderConfig, getSupportedProviders, type CLIAuthConfig, type PromptHandler, };
|
|
11
|
+
export declare function validateAllProviderConfigs(): void;
|
|
12
|
+
/**
|
|
13
|
+
* Result of running a CLI auth flow via PTY
|
|
14
|
+
*/
|
|
15
|
+
export interface PTYAuthResult {
|
|
16
|
+
authUrl: string | null;
|
|
17
|
+
success: boolean;
|
|
18
|
+
promptsHandled: string[];
|
|
19
|
+
output: string;
|
|
20
|
+
exitCode: number | null;
|
|
21
|
+
error?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Options for running CLI auth via PTY
|
|
25
|
+
*/
|
|
26
|
+
export interface PTYAuthOptions {
|
|
27
|
+
/** Callback when auth URL is found */
|
|
28
|
+
onAuthUrl?: (url: string) => void;
|
|
29
|
+
/** Callback when a prompt is handled */
|
|
30
|
+
onPromptHandled?: (description: string) => void;
|
|
31
|
+
/** Callback for raw PTY output */
|
|
32
|
+
onOutput?: (data: string) => void;
|
|
33
|
+
/** Environment variables override */
|
|
34
|
+
env?: Record<string, string>;
|
|
35
|
+
/** Working directory */
|
|
36
|
+
cwd?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Run CLI auth flow via PTY using relay-pty binary
|
|
40
|
+
*
|
|
41
|
+
* This is the core PTY runner used by both production and tests.
|
|
42
|
+
* It handles:
|
|
43
|
+
* - Spawning the CLI with proper TTY emulation via relay-pty
|
|
44
|
+
* - Auto-responding to interactive prompts
|
|
45
|
+
* - Extracting auth URLs from output
|
|
46
|
+
* - Detecting success patterns
|
|
47
|
+
*
|
|
48
|
+
* @param config - CLI auth configuration for the provider
|
|
49
|
+
* @param options - Optional callbacks and overrides
|
|
50
|
+
* @returns Promise resolving to auth result
|
|
51
|
+
*/
|
|
52
|
+
export declare function runCLIAuthViaPTY(config: CLIAuthConfig, options?: PTYAuthOptions): Promise<PTYAuthResult>;
|
|
53
|
+
//# sourceMappingURL=cli-pty-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-pty-runner.d.ts","sourceRoot":"","sources":["../../src/api/cli-pty-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAaH,OAAO,EACL,eAAe,EACf,cAAc,EACd,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EAEtB,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,aAAa,EACnB,MAAM,qCAAqC,CAAC;AAG7C,OAAO,EACL,eAAe,EACf,cAAc,EACd,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,aAAa,GACnB,CAAC;AAGF,wBAAgB,0BAA0B,IAAI,IAAI,CAKjD;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,wCAAwC;IACxC,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,kCAAkC;IAClC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,qCAAqC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAkCD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,aAAa,EACrB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC,CA0IxB"}
|