alpic 0.0.0-dev.f19a8ca → 0.0.0-dev.f1adf05
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/README.md +40 -0
- package/bin/run.js +5 -0
- package/dist/__tests__/audit.e2e.test.d.ts +1 -0
- package/dist/__tests__/audit.e2e.test.js +562 -0
- package/dist/__tests__/audit.e2e.test.js.map +1 -0
- package/dist/__tests__/auth.e2e.test.d.ts +1 -0
- package/dist/__tests__/auth.e2e.test.js +162 -0
- package/dist/__tests__/auth.e2e.test.js.map +1 -0
- package/dist/__tests__/deploy-flags.e2e.test.d.ts +1 -0
- package/dist/__tests__/deploy-flags.e2e.test.js +228 -0
- package/dist/__tests__/deploy-flags.e2e.test.js.map +1 -0
- package/dist/__tests__/deploy.e2e.test.js +66 -66
- package/dist/__tests__/deploy.e2e.test.js.map +1 -1
- package/dist/__tests__/deployment-inspect.e2e.test.d.ts +1 -0
- package/dist/__tests__/deployment-inspect.e2e.test.js +119 -0
- package/dist/__tests__/deployment-inspect.e2e.test.js.map +1 -0
- package/dist/__tests__/deployment-list.e2e.test.d.ts +1 -0
- package/dist/__tests__/deployment-list.e2e.test.js +121 -0
- package/dist/__tests__/deployment-list.e2e.test.js.map +1 -0
- package/dist/__tests__/deployment-logs.e2e.test.d.ts +1 -0
- package/dist/__tests__/deployment-logs.e2e.test.js +260 -0
- package/dist/__tests__/deployment-logs.e2e.test.js.map +1 -0
- package/dist/__tests__/environment-variable/environment-variable-add.e2e.test.d.ts +1 -0
- package/dist/__tests__/environment-variable/environment-variable-add.e2e.test.js +264 -0
- package/dist/__tests__/environment-variable/environment-variable-add.e2e.test.js.map +1 -0
- package/dist/__tests__/environment-variable/environment-variable-list.e2e.test.d.ts +1 -0
- package/dist/__tests__/environment-variable/environment-variable-list.e2e.test.js +144 -0
- package/dist/__tests__/environment-variable/environment-variable-list.e2e.test.js.map +1 -0
- package/dist/__tests__/environment-variable/environment-variable-remove.e2e.test.d.ts +1 -0
- package/dist/__tests__/environment-variable/environment-variable-remove.e2e.test.js +155 -0
- package/dist/__tests__/environment-variable/environment-variable-remove.e2e.test.js.map +1 -0
- package/dist/__tests__/environment-variable/environment-variable-update.e2e.test.d.ts +1 -0
- package/dist/__tests__/environment-variable/environment-variable-update.e2e.test.js +347 -0
- package/dist/__tests__/environment-variable/environment-variable-update.e2e.test.js.map +1 -0
- package/dist/__tests__/environment-variable/environment-variable-validation.test.d.ts +1 -0
- package/dist/__tests__/environment-variable/environment-variable-validation.test.js +20 -0
- package/dist/__tests__/environment-variable/environment-variable-validation.test.js.map +1 -0
- package/dist/__tests__/fixtures/demo-project/index.js +1 -1
- package/dist/__tests__/fixtures/demo-project/index.js.map +1 -1
- package/dist/__tests__/git-flags.e2e.test.d.ts +1 -0
- package/dist/__tests__/git-flags.e2e.test.js +129 -0
- package/dist/__tests__/git-flags.e2e.test.js.map +1 -0
- package/dist/__tests__/git.e2e.test.js +67 -21
- package/dist/__tests__/git.e2e.test.js.map +1 -1
- package/dist/__tests__/link.e2e.test.d.ts +1 -0
- package/dist/__tests__/link.e2e.test.js +284 -0
- package/dist/__tests__/link.e2e.test.js.map +1 -0
- package/dist/__tests__/logs.e2e.test.d.ts +1 -0
- package/dist/__tests__/logs.e2e.test.js +231 -0
- package/dist/__tests__/logs.e2e.test.js.map +1 -0
- package/dist/__tests__/mock-server.d.ts +23 -0
- package/dist/__tests__/mock-server.js +377 -21
- package/dist/__tests__/mock-server.js.map +1 -1
- package/dist/__tests__/publish.e2e.test.d.ts +1 -0
- package/dist/__tests__/publish.e2e.test.js +510 -0
- package/dist/__tests__/publish.e2e.test.js.map +1 -0
- package/dist/__tests__/tunnel.e2e.test.d.ts +1 -0
- package/dist/__tests__/tunnel.e2e.test.js +66 -0
- package/dist/__tests__/tunnel.e2e.test.js.map +1 -0
- package/dist/__tests__/utils.d.ts +23 -5
- package/dist/__tests__/utils.js +138 -21
- package/dist/__tests__/utils.js.map +1 -1
- package/dist/api.d.ts +1 -2
- package/dist/api.js +13 -10
- package/dist/api.js.map +1 -1
- package/dist/commands/audit.d.ts +14 -0
- package/dist/commands/audit.js +49 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/deploy.d.ts +8 -2
- package/dist/commands/deploy.js +64 -29
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/deployment/inspect.d.ts +11 -0
- package/dist/commands/deployment/inspect.js +91 -0
- package/dist/commands/deployment/inspect.js.map +1 -0
- package/dist/commands/deployment/list.d.ts +11 -0
- package/dist/commands/deployment/list.js +97 -0
- package/dist/commands/deployment/list.js.map +1 -0
- package/dist/commands/deployment/logs.d.ts +12 -0
- package/dist/commands/deployment/logs.js +50 -0
- package/dist/commands/deployment/logs.js.map +1 -0
- package/dist/commands/environment-variable/add.d.ts +14 -0
- package/dist/commands/environment-variable/add.js +47 -0
- package/dist/commands/environment-variable/add.js.map +1 -0
- package/dist/commands/environment-variable/list.d.ts +9 -0
- package/dist/commands/environment-variable/list.js +45 -0
- package/dist/commands/environment-variable/list.js.map +1 -0
- package/dist/commands/environment-variable/remove.d.ts +11 -0
- package/dist/commands/environment-variable/remove.js +33 -0
- package/dist/commands/environment-variable/remove.js.map +1 -0
- package/dist/commands/environment-variable/update.d.ts +13 -0
- package/dist/commands/environment-variable/update.js +41 -0
- package/dist/commands/environment-variable/update.js.map +1 -0
- package/dist/commands/git/connect.d.ts +3 -2
- package/dist/commands/git/connect.js +29 -34
- package/dist/commands/git/connect.js.map +1 -1
- package/dist/commands/git/disconnect.d.ts +2 -2
- package/dist/commands/git/disconnect.js +20 -30
- package/dist/commands/git/disconnect.js.map +1 -1
- package/dist/commands/git.js +3 -3
- package/dist/commands/git.js.map +1 -1
- package/dist/commands/link.d.ts +17 -0
- package/dist/commands/link.js +101 -0
- package/dist/commands/link.js.map +1 -0
- package/dist/commands/login.d.ts +6 -0
- package/dist/commands/login.js +21 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +6 -0
- package/dist/commands/logout.js +20 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/logs.d.ts +16 -0
- package/dist/commands/logs.js +96 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/publish.d.ts +15 -0
- package/dist/commands/publish.js +51 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/tunnel.d.ts +10 -0
- package/dist/commands/tunnel.js +132 -0
- package/dist/commands/tunnel.js.map +1 -0
- package/dist/commands/whoami.d.ts +6 -0
- package/dist/commands/whoami.js +13 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/env.d.ts +4 -0
- package/dist/env.js +10 -0
- package/dist/env.js.map +1 -0
- package/dist/lib/alpic-command.d.ts +2 -0
- package/dist/lib/alpic-command.js +12 -7
- package/dist/lib/alpic-command.js.map +1 -1
- package/dist/lib/archive.d.ts +3 -3
- package/dist/lib/archive.js +21 -19
- package/dist/lib/archive.js.map +1 -1
- package/dist/lib/audit.d.ts +16 -0
- package/dist/lib/audit.js +245 -0
- package/dist/lib/audit.js.map +1 -0
- package/dist/lib/auth/auth.d.ts +5 -0
- package/dist/lib/auth/auth.js +44 -0
- package/dist/lib/auth/auth.js.map +1 -0
- package/dist/lib/auth/oauth/client.d.ts +28 -0
- package/dist/lib/auth/oauth/client.js +110 -0
- package/dist/lib/auth/oauth/client.js.map +1 -0
- package/dist/lib/auth/oauth/constants.d.ts +2 -0
- package/dist/lib/auth/oauth/constants.js +3 -0
- package/dist/lib/auth/oauth/constants.js.map +1 -0
- package/dist/lib/auth/oauth/server/assets/alpic-mountain.png +0 -0
- package/dist/lib/auth/oauth/server/assets/authorize.html +195 -0
- package/dist/lib/auth/oauth/server/assets/callback.html +88 -0
- package/dist/lib/auth/oauth/server/index.d.ts +9 -0
- package/dist/lib/auth/oauth/server/index.js +128 -0
- package/dist/lib/auth/oauth/server/index.js.map +1 -0
- package/dist/lib/auth/whoami.d.ts +1 -0
- package/dist/lib/auth/whoami.js +45 -0
- package/dist/lib/auth/whoami.js.map +1 -0
- package/dist/lib/base-workflow.d.ts +10 -0
- package/dist/lib/base-workflow.js +22 -0
- package/dist/lib/base-workflow.js.map +1 -0
- package/dist/lib/config.d.ts +3 -2
- package/dist/lib/config.js +8 -7
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/deployment.d.ts +71 -4
- package/dist/lib/deployment.js +122 -9
- package/dist/lib/deployment.js.map +1 -1
- package/dist/lib/environment-variable.d.ts +37 -0
- package/dist/lib/environment-variable.js +299 -0
- package/dist/lib/environment-variable.js.map +1 -0
- package/dist/lib/git.d.ts +12 -4
- package/dist/lib/git.js +52 -27
- package/dist/lib/git.js.map +1 -1
- package/dist/lib/global-store.d.ts +28 -0
- package/dist/lib/global-store.js +76 -0
- package/dist/lib/global-store.js.map +1 -0
- package/dist/lib/link.d.ts +83 -0
- package/dist/lib/link.js +387 -0
- package/dist/lib/link.js.map +1 -0
- package/dist/lib/logs.d.ts +20 -0
- package/dist/lib/logs.js +87 -0
- package/dist/lib/logs.js.map +1 -0
- package/dist/lib/publish.d.ts +22 -0
- package/dist/lib/publish.js +185 -0
- package/dist/lib/publish.js.map +1 -0
- package/dist/lib/resolve.d.ts +6 -0
- package/dist/lib/resolve.js +26 -0
- package/dist/lib/resolve.js.map +1 -0
- package/dist/lib/table.d.ts +8 -0
- package/dist/lib/table.js +27 -0
- package/dist/lib/table.js.map +1 -0
- package/dist/lib/telemetry.js +7 -7
- package/dist/lib/telemetry.js.map +1 -1
- package/dist/lib/utils.d.ts +5 -0
- package/dist/lib/utils.js +53 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/lib/utils.test.d.ts +1 -0
- package/dist/lib/utils.test.js +27 -0
- package/dist/lib/utils.test.js.map +1 -0
- package/dist/types.d.ts +1 -0
- package/package.json +35 -21
- package/dist/lib/auth.d.ts +0 -1
- package/dist/lib/auth.js +0 -10
- package/dist/lib/auth.js.map +0 -1
- package/dist/lib/global-config.d.ts +0 -9
- package/dist/lib/global-config.js +0 -48
- package/dist/lib/global-config.js.map +0 -1
- package/dist/lib/project.d.ts +0 -67
- package/dist/lib/project.js +0 -285
- package/dist/lib/project.js.map +0 -1
|
@@ -1,8 +1,23 @@
|
|
|
1
|
-
import { OpenAPIHandler } from "@orpc/openapi/node";
|
|
2
|
-
import { ORPCError, implement } from "@orpc/server";
|
|
3
|
-
import express, {} from "express";
|
|
4
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import * as https from "node:https";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { contract } from "@alpic-ai/api";
|
|
7
|
+
import { OpenAPIHandler } from "@orpc/openapi/node";
|
|
8
|
+
import { implement, ORPCError } from "@orpc/server";
|
|
9
|
+
import express, {} from "express";
|
|
10
|
+
import { inc as semverInc } from "semver";
|
|
11
|
+
const __testDirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const FIXTURE_CERT_PATH = join(__testDirname, "fixtures", "certs", "localhost-cert.pem");
|
|
13
|
+
const FIXTURE_KEY_PATH = join(__testDirname, "fixtures", "certs", "localhost-key.pem");
|
|
14
|
+
function getTlsAssets() {
|
|
15
|
+
return {
|
|
16
|
+
key: readFileSync(FIXTURE_KEY_PATH, "utf8"),
|
|
17
|
+
cert: readFileSync(FIXTURE_CERT_PATH, "utf8"),
|
|
18
|
+
certPath: FIXTURE_CERT_PATH,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
6
21
|
export class MockApiServer {
|
|
7
22
|
server = null;
|
|
8
23
|
app;
|
|
@@ -12,9 +27,18 @@ export class MockApiServer {
|
|
|
12
27
|
constructor() {
|
|
13
28
|
this.app = express();
|
|
14
29
|
this.mockData = {
|
|
30
|
+
teams: null,
|
|
15
31
|
projects: new Map(),
|
|
16
32
|
environments: new Map(),
|
|
17
33
|
deployments: new Map(),
|
|
34
|
+
environmentVariables: new Map(),
|
|
35
|
+
runtimeLogs: new Map(),
|
|
36
|
+
runtimeLogPages: new Map(),
|
|
37
|
+
deploymentLogPages: new Map(),
|
|
38
|
+
deploymentLogCallCounts: new Map(),
|
|
39
|
+
publishedServers: new Map(),
|
|
40
|
+
beaconGetResponses: [],
|
|
41
|
+
beaconGetCallCount: 0,
|
|
18
42
|
};
|
|
19
43
|
}
|
|
20
44
|
async start() {
|
|
@@ -22,11 +46,17 @@ export class MockApiServer {
|
|
|
22
46
|
throw new Error("Server is already running");
|
|
23
47
|
}
|
|
24
48
|
this.configureServer();
|
|
49
|
+
const tlsAssets = getTlsAssets();
|
|
50
|
+
process.env.NODE_EXTRA_CA_CERTS = tlsAssets.certPath;
|
|
51
|
+
const httpsOptions = { key: tlsAssets.key, cert: tlsAssets.cert };
|
|
25
52
|
return new Promise((resolve) => {
|
|
26
|
-
this.server = this.app.listen(0, "127.0.0.1", () => {
|
|
53
|
+
this.server = https.createServer(httpsOptions, this.app).listen(0, "127.0.0.1", () => {
|
|
54
|
+
if (!this.server) {
|
|
55
|
+
throw new Error("Server is not running");
|
|
56
|
+
}
|
|
27
57
|
const address = this.server.address();
|
|
28
58
|
this.port = address.port;
|
|
29
|
-
const url = `
|
|
59
|
+
const url = `https://127.0.0.1:${this.port}`;
|
|
30
60
|
resolve(url);
|
|
31
61
|
});
|
|
32
62
|
});
|
|
@@ -44,17 +74,66 @@ export class MockApiServer {
|
|
|
44
74
|
res.status(200).end();
|
|
45
75
|
});
|
|
46
76
|
this.app.use(express.json());
|
|
77
|
+
this.app.get("/.well-known/oauth-protected-resource", (_req, res) => {
|
|
78
|
+
const base = `https://127.0.0.1:${this.port}`;
|
|
79
|
+
res.status(200).json({
|
|
80
|
+
resource: "https://api.alpic.ai",
|
|
81
|
+
authorization_servers: [base],
|
|
82
|
+
bearer_methods_supported: ["header"],
|
|
83
|
+
scopes_supported: ["openid", "email", "profile"],
|
|
84
|
+
resource_documentation: "https://docs.alpic.ai",
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
this.app.get("/.well-known/openid-configuration", (_req, res) => {
|
|
88
|
+
const base = `https://127.0.0.1:${this.port}`;
|
|
89
|
+
res.status(200).json({
|
|
90
|
+
issuer: base,
|
|
91
|
+
userinfo_endpoint: `${base}/oauth2/userInfo`,
|
|
92
|
+
authorization_endpoint: `${base}/oauth2/authorize`,
|
|
93
|
+
token_endpoint: `${base}/oauth2/token`,
|
|
94
|
+
jwks_uri: `${base}/.well-known/jwks.json`,
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
this.app.get("/oauth2/userInfo", (req, res) => {
|
|
98
|
+
const auth = req.headers.authorization;
|
|
99
|
+
if (!auth?.startsWith("Bearer ")) {
|
|
100
|
+
res.status(401).json({ error: "Missing or invalid Authorization" });
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
res.status(200).json({
|
|
104
|
+
sub: "test-sub",
|
|
105
|
+
email_verified: "true",
|
|
106
|
+
identities: [],
|
|
107
|
+
name: "Test User",
|
|
108
|
+
email: "test@example.com",
|
|
109
|
+
picture: "",
|
|
110
|
+
username: "testuser",
|
|
111
|
+
});
|
|
112
|
+
});
|
|
47
113
|
const router = implement(contract).router({
|
|
114
|
+
tunnels: {
|
|
115
|
+
getTicket: {
|
|
116
|
+
v1: implement(contract.tunnels.getTicket.v1).handler(async () => {
|
|
117
|
+
return {
|
|
118
|
+
subdomain: "cool-mongoose-123",
|
|
119
|
+
ticket: "mock-ticket",
|
|
120
|
+
tunnelHost: "tunnel.alpic.dev",
|
|
121
|
+
};
|
|
122
|
+
}),
|
|
123
|
+
},
|
|
124
|
+
},
|
|
48
125
|
teams: {
|
|
49
126
|
list: {
|
|
50
127
|
v1: implement(contract.teams.list.v1).handler(async () => {
|
|
128
|
+
if (this.mockData.teams) {
|
|
129
|
+
return this.mockData.teams;
|
|
130
|
+
}
|
|
51
131
|
return [
|
|
52
132
|
{
|
|
53
133
|
id: "mock-team-id",
|
|
54
134
|
name: "Mock Team",
|
|
55
135
|
createdAt: new Date(),
|
|
56
136
|
hasStripeAccount: false,
|
|
57
|
-
hasActiveSubscription: false,
|
|
58
137
|
},
|
|
59
138
|
];
|
|
60
139
|
}),
|
|
@@ -65,7 +144,9 @@ export class MockApiServer {
|
|
|
65
144
|
v1: implement(contract.analytics.get.v1).handler(async ({ input }) => {
|
|
66
145
|
const project = this.mockData.projects.get(input.projectId);
|
|
67
146
|
if (!project) {
|
|
68
|
-
throw new ORPCError("NOT_FOUND", {
|
|
147
|
+
throw new ORPCError("NOT_FOUND", {
|
|
148
|
+
message: "Project not found",
|
|
149
|
+
});
|
|
69
150
|
}
|
|
70
151
|
const emptyTimeSeries = {
|
|
71
152
|
sessions_count: [],
|
|
@@ -114,7 +195,9 @@ export class MockApiServer {
|
|
|
114
195
|
v1: implement(contract.projects.get.v1).handler(async ({ input }) => {
|
|
115
196
|
const project = this.mockData.projects.get(input.projectId);
|
|
116
197
|
if (!project) {
|
|
117
|
-
throw new ORPCError("NOT_FOUND", {
|
|
198
|
+
throw new ORPCError("NOT_FOUND", {
|
|
199
|
+
message: "Project not found",
|
|
200
|
+
});
|
|
118
201
|
}
|
|
119
202
|
return project;
|
|
120
203
|
}),
|
|
@@ -122,7 +205,7 @@ export class MockApiServer {
|
|
|
122
205
|
create: {
|
|
123
206
|
v1: implement(contract.projects.create.v1).handler(async ({ input }) => {
|
|
124
207
|
const projectId = randomUUID();
|
|
125
|
-
const teamId = "mock-team-id";
|
|
208
|
+
const teamId = input.teamId ?? "mock-team-id";
|
|
126
209
|
const productionEnvId = randomUUID();
|
|
127
210
|
const productionEnvName = "production";
|
|
128
211
|
const project = {
|
|
@@ -160,6 +243,7 @@ export class MockApiServer {
|
|
|
160
243
|
id: productionEnvId,
|
|
161
244
|
name: productionEnvName,
|
|
162
245
|
mcpServerUrl: `https://mcp-${projectId}.alpic.ai`,
|
|
246
|
+
domains: [],
|
|
163
247
|
latestDeployment: null,
|
|
164
248
|
},
|
|
165
249
|
environments: [
|
|
@@ -182,7 +266,9 @@ export class MockApiServer {
|
|
|
182
266
|
v1: implement(contract.projects.update.v1).handler(async ({ input }) => {
|
|
183
267
|
const project = this.mockData.projects.get(input.projectId);
|
|
184
268
|
if (!project) {
|
|
185
|
-
throw new ORPCError("NOT_FOUND", {
|
|
269
|
+
throw new ORPCError("NOT_FOUND", {
|
|
270
|
+
message: "Project not found",
|
|
271
|
+
});
|
|
186
272
|
}
|
|
187
273
|
if (input.sourceRepository !== undefined) {
|
|
188
274
|
project.sourceRepository = input.sourceRepository;
|
|
@@ -195,7 +281,9 @@ export class MockApiServer {
|
|
|
195
281
|
v1: implement(contract.projects.delete.v1).handler(async ({ input }) => {
|
|
196
282
|
const project = this.mockData.projects.get(input.projectId);
|
|
197
283
|
if (!project) {
|
|
198
|
-
throw new ORPCError("NOT_FOUND", {
|
|
284
|
+
throw new ORPCError("NOT_FOUND", {
|
|
285
|
+
message: "Project not found",
|
|
286
|
+
});
|
|
199
287
|
}
|
|
200
288
|
this.mockData.projects.delete(input.projectId);
|
|
201
289
|
return { success: true };
|
|
@@ -207,7 +295,9 @@ export class MockApiServer {
|
|
|
207
295
|
v1: implement(contract.environments.create.v1).handler(async ({ input }) => {
|
|
208
296
|
const project = this.mockData.projects.get(input.projectId);
|
|
209
297
|
if (!project) {
|
|
210
|
-
throw new ORPCError("NOT_FOUND", {
|
|
298
|
+
throw new ORPCError("NOT_FOUND", {
|
|
299
|
+
message: "Project not found",
|
|
300
|
+
});
|
|
211
301
|
}
|
|
212
302
|
const environmentId = randomUUID();
|
|
213
303
|
const mcpServerUrl = `https://mcp-${environmentId}.alpic.ai`;
|
|
@@ -251,21 +341,50 @@ export class MockApiServer {
|
|
|
251
341
|
v1: implement(contract.environments.get.v1).handler(async ({ input }) => {
|
|
252
342
|
const environment = this.mockData.environments.get(input.environmentId);
|
|
253
343
|
if (!environment) {
|
|
254
|
-
throw new ORPCError("NOT_FOUND", {
|
|
344
|
+
throw new ORPCError("NOT_FOUND", {
|
|
345
|
+
message: "Environment not found",
|
|
346
|
+
});
|
|
255
347
|
}
|
|
256
348
|
return environment;
|
|
257
349
|
}),
|
|
258
350
|
},
|
|
351
|
+
getLogs: {
|
|
352
|
+
v1: implement(contract.environments.getLogs.v1).handler(async ({ input }) => {
|
|
353
|
+
const environment = this.mockData.environments.get(input.environmentId);
|
|
354
|
+
if (!environment) {
|
|
355
|
+
throw new ORPCError("NOT_FOUND", {
|
|
356
|
+
message: "Environment not found",
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
const pagedLogs = this.mockData.runtimeLogPages.get(input.environmentId);
|
|
360
|
+
const pageIndex = input.nextToken === undefined ? 0 : Number.parseInt(input.nextToken, 10);
|
|
361
|
+
const allLogs = pagedLogs === undefined
|
|
362
|
+
? (this.mockData.runtimeLogs.get(input.environmentId) ?? [])
|
|
363
|
+
: (pagedLogs[pageIndex] ?? []);
|
|
364
|
+
let logs = allLogs;
|
|
365
|
+
if (input.level !== undefined) {
|
|
366
|
+
const levels = input.level;
|
|
367
|
+
logs = allLogs.filter((log) => levels.includes(log.type));
|
|
368
|
+
}
|
|
369
|
+
const nextToken = pagedLogs === undefined || pageIndex + 1 >= pagedLogs.length ? null : String(pageIndex + 1);
|
|
370
|
+
return { logs, nextToken };
|
|
371
|
+
}),
|
|
372
|
+
},
|
|
259
373
|
deploy: {
|
|
260
374
|
v1: implement(contract.environments.deploy.v1).handler(async ({ input }) => {
|
|
261
375
|
const environment = this.mockData.environments.get(input.environmentId);
|
|
262
376
|
if (!environment) {
|
|
263
|
-
throw new ORPCError("NOT_FOUND", {
|
|
377
|
+
throw new ORPCError("NOT_FOUND", {
|
|
378
|
+
message: "Environment not found",
|
|
379
|
+
});
|
|
264
380
|
}
|
|
265
381
|
const deploymentId = randomUUID();
|
|
266
382
|
const deployment = {
|
|
267
383
|
id: deploymentId,
|
|
268
384
|
status: "ongoing",
|
|
385
|
+
environmentId: environment.id,
|
|
386
|
+
environmentName: environment.name,
|
|
387
|
+
isCurrent: false,
|
|
269
388
|
sourceRef: environment.sourceBranch,
|
|
270
389
|
sourceCommitId: randomUUID().slice(0, 7),
|
|
271
390
|
sourceCommitMessage: "Mock deployment",
|
|
@@ -273,23 +392,187 @@ export class MockApiServer {
|
|
|
273
392
|
authorAvatarUrl: null,
|
|
274
393
|
startedAt: new Date(),
|
|
275
394
|
completedAt: null,
|
|
395
|
+
deploymentPageUrl: "https://app.alpic.ai/deployments/mock",
|
|
276
396
|
};
|
|
277
397
|
this.mockData.deployments.set(deploymentId, deployment);
|
|
278
398
|
return deployment;
|
|
279
399
|
}),
|
|
280
400
|
},
|
|
281
401
|
},
|
|
402
|
+
environmentVariables: {
|
|
403
|
+
list: {
|
|
404
|
+
v1: implement(contract.environmentVariables.list.v1).handler(async ({ input }) => {
|
|
405
|
+
const environment = this.mockData.environments.get(input.environmentId);
|
|
406
|
+
if (!environment) {
|
|
407
|
+
throw new ORPCError("NOT_FOUND", {
|
|
408
|
+
message: "Environment not found",
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
return this.mockData.environmentVariables.get(input.environmentId) ?? [];
|
|
412
|
+
}),
|
|
413
|
+
},
|
|
414
|
+
create: {
|
|
415
|
+
v1: implement(contract.environmentVariables.create.v1).handler(async ({ input }) => {
|
|
416
|
+
const environment = this.mockData.environments.get(input.environmentId);
|
|
417
|
+
if (!environment) {
|
|
418
|
+
throw new ORPCError("NOT_FOUND", {
|
|
419
|
+
message: "Environment not found",
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
const existing = this.mockData.environmentVariables.get(input.environmentId) ?? [];
|
|
423
|
+
const newVars = input.environmentVariables.map((variable) => ({
|
|
424
|
+
id: randomUUID(),
|
|
425
|
+
key: variable.key,
|
|
426
|
+
value: variable.value,
|
|
427
|
+
isSecret: variable.isSecret,
|
|
428
|
+
createdAt: new Date(),
|
|
429
|
+
}));
|
|
430
|
+
for (const newVar of newVars) {
|
|
431
|
+
if (existing.some((existingVar) => existingVar.key === newVar.key)) {
|
|
432
|
+
throw new ORPCError("BAD_REQUEST", {
|
|
433
|
+
message: `Environment variable "${newVar.key}" already exists`,
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
this.mockData.environmentVariables.set(input.environmentId, [...existing, ...newVars]);
|
|
438
|
+
return { success: true };
|
|
439
|
+
}),
|
|
440
|
+
},
|
|
441
|
+
update: {
|
|
442
|
+
v1: implement(contract.environmentVariables.update.v1).handler(async ({ input }) => {
|
|
443
|
+
for (const [environmentId, variables] of this.mockData.environmentVariables.entries()) {
|
|
444
|
+
const index = variables.findIndex((variable) => variable.id === input.environmentVariableId);
|
|
445
|
+
if (index !== -1) {
|
|
446
|
+
const updated = variables.map((variable, i) => i === index
|
|
447
|
+
? {
|
|
448
|
+
...variable,
|
|
449
|
+
key: input.key,
|
|
450
|
+
value: input.value ?? variable.value,
|
|
451
|
+
isSecret: input.isSecret,
|
|
452
|
+
}
|
|
453
|
+
: variable);
|
|
454
|
+
this.mockData.environmentVariables.set(environmentId, updated);
|
|
455
|
+
return { success: true };
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
throw new ORPCError("NOT_FOUND", {
|
|
459
|
+
message: "Environment variable not found",
|
|
460
|
+
});
|
|
461
|
+
}),
|
|
462
|
+
},
|
|
463
|
+
delete: {
|
|
464
|
+
v1: implement(contract.environmentVariables.delete.v1).handler(async ({ input }) => {
|
|
465
|
+
for (const [environmentId, variables] of this.mockData.environmentVariables.entries()) {
|
|
466
|
+
const index = variables.findIndex((variable) => variable.id === input.environmentVariableId);
|
|
467
|
+
if (index !== -1) {
|
|
468
|
+
this.mockData.environmentVariables.set(environmentId, variables.filter((_, i) => i !== index));
|
|
469
|
+
return { success: true };
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
throw new ORPCError("NOT_FOUND", {
|
|
473
|
+
message: "Environment variable not found",
|
|
474
|
+
});
|
|
475
|
+
}),
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
distribution: {
|
|
479
|
+
get: {
|
|
480
|
+
v1: implement(contract.distribution.get.v1).handler(async ({ input }) => {
|
|
481
|
+
const existing = this.mockData.publishedServers.get(`${input.projectId}:${input.domain}`);
|
|
482
|
+
return {
|
|
483
|
+
serverFields: existing ?? {
|
|
484
|
+
$schema: "https://registry.modelcontextprotocol.io/schemas/1.0/server.json",
|
|
485
|
+
name: "",
|
|
486
|
+
description: "",
|
|
487
|
+
},
|
|
488
|
+
};
|
|
489
|
+
}),
|
|
490
|
+
},
|
|
491
|
+
publish: {
|
|
492
|
+
v1: implement(contract.distribution.publish.v1).handler(async ({ input }) => {
|
|
493
|
+
const project = this.mockData.projects.get(input.projectId);
|
|
494
|
+
if (!project) {
|
|
495
|
+
throw new ORPCError("NOT_FOUND", {
|
|
496
|
+
message: "Project not found",
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
const key = `${input.projectId}:${input.domain}`;
|
|
500
|
+
const existing = this.mockData.publishedServers.get(key);
|
|
501
|
+
const version = existing?.version ? (semverInc(existing.version, "patch") ?? "0.0.1") : "0.0.1";
|
|
502
|
+
const serverFields = {
|
|
503
|
+
$schema: "https://registry.modelcontextprotocol.io/schemas/1.0/server.json",
|
|
504
|
+
name: input.domain,
|
|
505
|
+
description: input.description,
|
|
506
|
+
title: input.title,
|
|
507
|
+
version,
|
|
508
|
+
...(input.websiteUrl ? { websiteUrl: input.websiteUrl } : {}),
|
|
509
|
+
...(input.iconSrc ? { icons: [{ src: input.iconSrc }] } : {}),
|
|
510
|
+
};
|
|
511
|
+
if (!input.dryRun) {
|
|
512
|
+
this.mockData.publishedServers.set(key, serverFields);
|
|
513
|
+
}
|
|
514
|
+
return { serverFields };
|
|
515
|
+
}),
|
|
516
|
+
},
|
|
517
|
+
},
|
|
518
|
+
beacon: {
|
|
519
|
+
create: {
|
|
520
|
+
v1: implement(contract.beacon.create.v1).handler(async () => {
|
|
521
|
+
return { id: "mock-analysis-id" };
|
|
522
|
+
}),
|
|
523
|
+
},
|
|
524
|
+
get: {
|
|
525
|
+
v1: implement(contract.beacon.get.v1).handler(async () => {
|
|
526
|
+
if (this.mockData.beaconGetResponses.length > 0) {
|
|
527
|
+
const index = Math.min(this.mockData.beaconGetCallCount, this.mockData.beaconGetResponses.length - 1);
|
|
528
|
+
this.mockData.beaconGetCallCount++;
|
|
529
|
+
const response = this.mockData.beaconGetResponses[index];
|
|
530
|
+
if (!response) {
|
|
531
|
+
throw new Error("Missing mocked beacon.get response");
|
|
532
|
+
}
|
|
533
|
+
return response;
|
|
534
|
+
}
|
|
535
|
+
return {
|
|
536
|
+
id: "mock-analysis-id",
|
|
537
|
+
targetUrl: "https://example.com/mcp",
|
|
538
|
+
status: "completed",
|
|
539
|
+
durationMs: 1234,
|
|
540
|
+
createdAt: new Date(),
|
|
541
|
+
report: {
|
|
542
|
+
schemaVersion: "v20260224",
|
|
543
|
+
auditId: "mock-analysis-id",
|
|
544
|
+
targetUrl: "https://example.com/mcp",
|
|
545
|
+
startedAt: new Date().toISOString(),
|
|
546
|
+
completedAt: new Date().toISOString(),
|
|
547
|
+
durationMs: 1234,
|
|
548
|
+
results: [],
|
|
549
|
+
requiresAuth: false,
|
|
550
|
+
hasViewSupport: false,
|
|
551
|
+
isReadyForPlatform: { chatgpt: true, claudeai: true },
|
|
552
|
+
},
|
|
553
|
+
};
|
|
554
|
+
}),
|
|
555
|
+
},
|
|
556
|
+
},
|
|
282
557
|
deployments: {
|
|
283
558
|
list: {
|
|
284
559
|
v1: implement(contract.deployments.list.v1).handler(async ({ input }) => {
|
|
285
560
|
const project = this.mockData.projects.get(input.projectId);
|
|
286
561
|
if (!project) {
|
|
287
|
-
throw new ORPCError("NOT_FOUND", {
|
|
562
|
+
throw new ORPCError("NOT_FOUND", {
|
|
563
|
+
message: "Project not found",
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
let deployments = Array.from(this.mockData.deployments.values());
|
|
567
|
+
if (input.environmentId) {
|
|
568
|
+
deployments = deployments.filter((deployment) => deployment.environmentId === input.environmentId);
|
|
288
569
|
}
|
|
289
|
-
|
|
570
|
+
if (input.status?.length) {
|
|
571
|
+
deployments = deployments.filter((deployment) => input.status.includes(deployment.status));
|
|
572
|
+
}
|
|
573
|
+
return deployments.map((deployment) => ({
|
|
290
574
|
...deployment,
|
|
291
575
|
isCurrent: deployment.status === "deployed",
|
|
292
|
-
environmentId: project.productionEnvironment?.id ?? "",
|
|
293
576
|
}));
|
|
294
577
|
}),
|
|
295
578
|
},
|
|
@@ -297,13 +580,16 @@ export class MockApiServer {
|
|
|
297
580
|
v1: implement(contract.deployments.get.v1).handler(async ({ input }) => {
|
|
298
581
|
const deployment = this.mockData.deployments.get(input.deploymentId);
|
|
299
582
|
if (!deployment) {
|
|
300
|
-
throw new ORPCError("NOT_FOUND", {
|
|
583
|
+
throw new ORPCError("NOT_FOUND", {
|
|
584
|
+
message: "Deployment not found",
|
|
585
|
+
});
|
|
301
586
|
}
|
|
302
587
|
if (deployment.status === "ongoing") {
|
|
303
588
|
const updatedDeployment = {
|
|
304
589
|
...deployment,
|
|
305
590
|
status: "deployed",
|
|
306
591
|
completedAt: new Date(),
|
|
592
|
+
deploymentPageUrl: deployment.deploymentPageUrl ?? null,
|
|
307
593
|
};
|
|
308
594
|
this.mockData.deployments.set(input.deploymentId, updatedDeployment);
|
|
309
595
|
return updatedDeployment;
|
|
@@ -315,7 +601,16 @@ export class MockApiServer {
|
|
|
315
601
|
v1: implement(contract.deployments.getLogs.v1).handler(async ({ input }) => {
|
|
316
602
|
const deployment = this.mockData.deployments.get(input.deploymentId);
|
|
317
603
|
if (!deployment) {
|
|
318
|
-
throw new ORPCError("NOT_FOUND", {
|
|
604
|
+
throw new ORPCError("NOT_FOUND", {
|
|
605
|
+
message: "Deployment not found",
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
const pages = this.mockData.deploymentLogPages.get(input.deploymentId);
|
|
609
|
+
if (pages !== undefined) {
|
|
610
|
+
const callCount = this.mockData.deploymentLogCallCounts.get(input.deploymentId) ?? 0;
|
|
611
|
+
const pageIndex = Math.min(callCount, pages.length - 1);
|
|
612
|
+
this.mockData.deploymentLogCallCounts.set(input.deploymentId, callCount + 1);
|
|
613
|
+
return pages[pageIndex] ?? { logs: [], hasMoreLogs: false };
|
|
319
614
|
}
|
|
320
615
|
return {
|
|
321
616
|
logs: [{ timestamp: new Date(), content: "Mock log entry" }],
|
|
@@ -326,7 +621,7 @@ export class MockApiServer {
|
|
|
326
621
|
uploadArtifact: {
|
|
327
622
|
v1: implement(contract.deployments.uploadArtifact.v1).handler(async () => {
|
|
328
623
|
const token = randomUUID();
|
|
329
|
-
const baseUrl = `
|
|
624
|
+
const baseUrl = `https://127.0.0.1:${this.port}`;
|
|
330
625
|
const uploadUrl = `${baseUrl}/__mock__upload/${token}`;
|
|
331
626
|
return {
|
|
332
627
|
uploadUrl,
|
|
@@ -344,7 +639,12 @@ export class MockApiServer {
|
|
|
344
639
|
path: req.path,
|
|
345
640
|
timestamp: new Date(),
|
|
346
641
|
};
|
|
347
|
-
if (req.
|
|
642
|
+
if (req.method === "GET") {
|
|
643
|
+
if (Object.keys(req.query).length > 0) {
|
|
644
|
+
apiCall.input = req.query;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
else if (req.body) {
|
|
348
648
|
apiCall.input = req.body;
|
|
349
649
|
}
|
|
350
650
|
const result = await handler.handle(req, res, {
|
|
@@ -360,6 +660,23 @@ export class MockApiServer {
|
|
|
360
660
|
this.callHistory.push(apiCall);
|
|
361
661
|
});
|
|
362
662
|
}
|
|
663
|
+
reset() {
|
|
664
|
+
this.callHistory = [];
|
|
665
|
+
this.mockData = {
|
|
666
|
+
teams: null,
|
|
667
|
+
projects: new Map(),
|
|
668
|
+
environments: new Map(),
|
|
669
|
+
deployments: new Map(),
|
|
670
|
+
environmentVariables: new Map(),
|
|
671
|
+
runtimeLogs: new Map(),
|
|
672
|
+
runtimeLogPages: new Map(),
|
|
673
|
+
deploymentLogPages: new Map(),
|
|
674
|
+
deploymentLogCallCounts: new Map(),
|
|
675
|
+
publishedServers: new Map(),
|
|
676
|
+
beaconGetResponses: [],
|
|
677
|
+
beaconGetCallCount: 0,
|
|
678
|
+
};
|
|
679
|
+
}
|
|
363
680
|
async stop() {
|
|
364
681
|
return new Promise((resolve, reject) => {
|
|
365
682
|
if (!this.server) {
|
|
@@ -398,6 +715,8 @@ export class MockApiServer {
|
|
|
398
715
|
getLastCall(method, pathPattern) {
|
|
399
716
|
for (let i = this.callHistory.length - 1; i >= 0; i--) {
|
|
400
717
|
const call = this.callHistory[i];
|
|
718
|
+
if (!call)
|
|
719
|
+
continue;
|
|
401
720
|
if (method && call.method !== method)
|
|
402
721
|
continue;
|
|
403
722
|
if (pathPattern) {
|
|
@@ -414,6 +733,43 @@ export class MockApiServer {
|
|
|
414
733
|
}
|
|
415
734
|
return undefined;
|
|
416
735
|
}
|
|
736
|
+
setTeams(teams) {
|
|
737
|
+
this.mockData.teams = teams.map((team) => ({
|
|
738
|
+
...team,
|
|
739
|
+
createdAt: new Date(),
|
|
740
|
+
hasStripeAccount: false,
|
|
741
|
+
}));
|
|
742
|
+
}
|
|
743
|
+
addEnvironmentVariables(environmentId, variables) {
|
|
744
|
+
this.mockData.environmentVariables.set(environmentId, variables);
|
|
745
|
+
}
|
|
746
|
+
setRuntimeLogs(environmentId, logs) {
|
|
747
|
+
this.mockData.runtimeLogs.set(environmentId, logs);
|
|
748
|
+
this.mockData.runtimeLogPages.delete(environmentId);
|
|
749
|
+
}
|
|
750
|
+
setRuntimeLogPages(environmentId, pages) {
|
|
751
|
+
this.mockData.runtimeLogPages.set(environmentId, pages);
|
|
752
|
+
this.mockData.runtimeLogs.delete(environmentId);
|
|
753
|
+
}
|
|
754
|
+
setPublishedServer(projectId, domain, server) {
|
|
755
|
+
this.mockData.publishedServers.set(`${projectId}:${domain}`, server);
|
|
756
|
+
}
|
|
757
|
+
addDeployments(deployments) {
|
|
758
|
+
for (const deployment of deployments) {
|
|
759
|
+
this.mockData.deployments.set(deployment.id, {
|
|
760
|
+
...deployment,
|
|
761
|
+
deploymentPageUrl: null,
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
setDeploymentLogPages(deploymentId, pages) {
|
|
766
|
+
this.mockData.deploymentLogPages.set(deploymentId, pages);
|
|
767
|
+
this.mockData.deploymentLogCallCounts.set(deploymentId, 0);
|
|
768
|
+
}
|
|
769
|
+
setBeaconGetResponses(responses) {
|
|
770
|
+
this.mockData.beaconGetResponses = responses;
|
|
771
|
+
this.mockData.beaconGetCallCount = 0;
|
|
772
|
+
}
|
|
417
773
|
addProject(project) {
|
|
418
774
|
this.mockData.projects.set(project.id, project);
|
|
419
775
|
if (project.productionEnvironment) {
|