alpic 0.0.0-dev.ea11209 → 0.0.0-dev.eb59c8a

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.
Files changed (57) hide show
  1. package/dist/__tests__/deploy.e2e.test.d.ts +1 -0
  2. package/dist/__tests__/deploy.e2e.test.js +250 -0
  3. package/dist/__tests__/deploy.e2e.test.js.map +1 -0
  4. package/dist/__tests__/fixtures/demo-project/index.d.ts +1 -0
  5. package/dist/__tests__/fixtures/demo-project/index.js +4 -0
  6. package/dist/__tests__/fixtures/demo-project/index.js.map +1 -0
  7. package/dist/__tests__/mock-server.d.ts +22 -0
  8. package/dist/__tests__/mock-server.js +353 -0
  9. package/dist/__tests__/mock-server.js.map +1 -0
  10. package/dist/__tests__/utils.d.ts +29 -0
  11. package/dist/__tests__/utils.js +89 -0
  12. package/dist/__tests__/utils.js.map +1 -0
  13. package/dist/api.d.ts +4 -0
  14. package/dist/api.js +19 -0
  15. package/dist/api.js.map +1 -0
  16. package/dist/commands/deploy.d.ts +9 -0
  17. package/dist/commands/deploy.js +86 -0
  18. package/dist/commands/deploy.js.map +1 -0
  19. package/dist/commands/{hello.d.ts → telemetry/disable.d.ts} +1 -2
  20. package/dist/commands/telemetry/disable.js +14 -0
  21. package/dist/commands/telemetry/disable.js.map +1 -0
  22. package/dist/commands/telemetry/enable.d.ts +5 -0
  23. package/dist/commands/telemetry/enable.js +13 -0
  24. package/dist/commands/telemetry/enable.js.map +1 -0
  25. package/dist/commands/telemetry/status.d.ts +5 -0
  26. package/dist/commands/telemetry/status.js +19 -0
  27. package/dist/commands/telemetry/status.js.map +1 -0
  28. package/dist/lib/archive.d.ts +7 -0
  29. package/dist/lib/archive.js +55 -0
  30. package/dist/lib/archive.js.map +1 -0
  31. package/dist/lib/config.d.ts +11 -0
  32. package/dist/lib/config.js +31 -0
  33. package/dist/lib/config.js.map +1 -0
  34. package/dist/lib/deployment.d.ts +21 -0
  35. package/dist/lib/deployment.js +38 -0
  36. package/dist/lib/deployment.js.map +1 -0
  37. package/dist/lib/global-config.d.ts +9 -0
  38. package/dist/lib/global-config.js +48 -0
  39. package/dist/lib/global-config.js.map +1 -0
  40. package/dist/lib/project.d.ts +67 -0
  41. package/dist/lib/project.js +281 -0
  42. package/dist/lib/project.js.map +1 -0
  43. package/dist/lib/telemetry.d.ts +7 -0
  44. package/dist/lib/telemetry.js +66 -0
  45. package/dist/lib/telemetry.js.map +1 -0
  46. package/dist/lib/upload.d.ts +1 -0
  47. package/dist/lib/upload.js +14 -0
  48. package/dist/lib/upload.js.map +1 -0
  49. package/dist/posthog.d.ts +3 -0
  50. package/dist/posthog.js +10 -0
  51. package/dist/posthog.js.map +1 -0
  52. package/dist/types.d.ts +7 -0
  53. package/dist/types.js +2 -0
  54. package/dist/types.js.map +1 -0
  55. package/package.json +25 -5
  56. package/dist/commands/hello.js +0 -10
  57. package/dist/commands/hello.js.map +0 -1
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,250 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
3
+ import { cp, mkdtemp, readFile } from "node:fs/promises";
4
+ import { tmpdir } from "node:os";
5
+ import { dirname, join } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
8
+ import { MockApiServer } from "./mock-server";
9
+ import { cliSession } from "./utils";
10
+ const __dirname = dirname(fileURLToPath(import.meta.url));
11
+ describe("alpic deploy (E2E)", () => {
12
+ let mockServer;
13
+ let serverUrl;
14
+ let cwd;
15
+ let binPath;
16
+ beforeEach(async () => {
17
+ mockServer = new MockApiServer();
18
+ serverUrl = await mockServer.start();
19
+ const setup = await setupTestDirectory();
20
+ cwd = setup.cwd;
21
+ binPath = setup.binPath;
22
+ });
23
+ afterEach(async () => {
24
+ await mockServer.stop();
25
+ if (cwd) {
26
+ rmSync(cwd, { recursive: true, force: true });
27
+ }
28
+ });
29
+ it("creates config from prompt flow and completes deployment", async () => {
30
+ const { exitCode, output } = await cliSession(process.execPath, [binPath, "deploy"], {
31
+ cwd,
32
+ env: {
33
+ ALPIC_API_BASE_URL: serverUrl,
34
+ ALPIC_FRONTEND_BASE_URL: "http://mocked.frontend.url",
35
+ ALPIC_API_KEY: "test-api-key",
36
+ },
37
+ }, async (cli) => {
38
+ await cli.expect("Deploy the directory?");
39
+ await cli.send("");
40
+ await cli.expect("Link to existing project?");
41
+ await cli.send("n");
42
+ await cli.expect("Project name");
43
+ await cli.send("demo");
44
+ await cli.expect("Runtime");
45
+ await cli.send("");
46
+ await cli.expect("Root directory");
47
+ await cli.send("");
48
+ await cli.expect("Project created.");
49
+ const createProjectCall = mockServer.getLastCall("POST", "/v1/projects");
50
+ expectSuccessfulApiCall(createProjectCall, (call) => {
51
+ expect(call.input).toMatchObject({
52
+ name: "demo",
53
+ runtime: "node24",
54
+ });
55
+ });
56
+ await verifyDeploymentFlow(cli, mockServer);
57
+ });
58
+ expect(exitCode).toBe(0);
59
+ await verifyConfigFile(cwd, output, {
60
+ projectName: "demo",
61
+ environmentName: "production",
62
+ });
63
+ });
64
+ it("links to existing project and completes deployment", async () => {
65
+ const existingProjectId = "existing-project-id";
66
+ const existingTeamId = "mock-team-id";
67
+ const existingEnvId = "existing-env-id";
68
+ const existingEnvName = "production";
69
+ mockServer.addProject(buildMockProject({
70
+ projectId: existingProjectId,
71
+ teamId: existingTeamId,
72
+ projectName: "existing-project",
73
+ environmentId: existingEnvId,
74
+ environmentName: existingEnvName,
75
+ }));
76
+ const { exitCode, output } = await cliSession(process.execPath, [binPath, "deploy"], {
77
+ cwd,
78
+ env: {
79
+ ALPIC_API_BASE_URL: serverUrl,
80
+ ALPIC_FRONTEND_BASE_URL: "http://mocked.frontend.url",
81
+ ALPIC_API_KEY: "test-api-key",
82
+ },
83
+ }, async (cli) => {
84
+ await cli.expect("Deploy the directory?");
85
+ await cli.send("");
86
+ await cli.expect("Link to existing project?");
87
+ await cli.send("y");
88
+ await cli.expect("Choose a project");
89
+ await cli.send("");
90
+ await cli.expect("Choose an environment to deploy to");
91
+ await cli.send("");
92
+ await verifyDeploymentFlow(cli, mockServer);
93
+ });
94
+ expect(exitCode).toBe(0);
95
+ await verifyConfigFile(cwd, output, {
96
+ projectName: "existing-project",
97
+ projectId: existingProjectId,
98
+ teamId: existingTeamId,
99
+ environmentId: existingEnvId,
100
+ environmentName: existingEnvName,
101
+ });
102
+ const listProjectsCall = mockServer.getLastCall("GET", "/v1/projects");
103
+ expectSuccessfulApiCall(listProjectsCall);
104
+ });
105
+ it("deploys with existing config file", async () => {
106
+ const existingProjectId = "existing-project-id";
107
+ const existingTeamId = "mock-team-id";
108
+ const existingEnvId = "existing-env-id";
109
+ const existingEnvName = "production";
110
+ mockServer.addProject(buildMockProject({
111
+ projectId: existingProjectId,
112
+ teamId: existingTeamId,
113
+ projectName: "existing-project",
114
+ environmentId: existingEnvId,
115
+ environmentName: existingEnvName,
116
+ }));
117
+ createConfigFile(cwd, existingProjectId, existingTeamId, "existing-project", existingEnvId, existingEnvName);
118
+ const { exitCode, output } = await cliSession(process.execPath, [binPath, "deploy"], {
119
+ cwd,
120
+ env: {
121
+ ALPIC_API_BASE_URL: serverUrl,
122
+ ALPIC_FRONTEND_BASE_URL: "http://mocked.frontend.url",
123
+ ALPIC_API_KEY: "test-api-key",
124
+ },
125
+ }, async (cli) => {
126
+ await cli.expect("Deploy the directory?");
127
+ await cli.send("");
128
+ await cli.expect(`Deploy project "existing-project" to environment "production"?`);
129
+ await cli.send("");
130
+ await verifyDeploymentFlow(cli, mockServer);
131
+ });
132
+ expect(exitCode).toBe(0);
133
+ await verifyConfigFile(cwd, output, {
134
+ projectName: "existing-project",
135
+ projectId: existingProjectId,
136
+ teamId: existingTeamId,
137
+ environmentId: existingEnvId,
138
+ environmentName: existingEnvName,
139
+ });
140
+ });
141
+ }, 15_000);
142
+ function buildMockProject(params) {
143
+ const { projectId, teamId, projectName, environmentId, environmentName } = params;
144
+ const mcpServerUrl = `https://mcp-${projectId}.alpic.ai`;
145
+ return {
146
+ id: projectId,
147
+ name: projectName,
148
+ teamId,
149
+ environments: [
150
+ {
151
+ id: environmentId,
152
+ name: environmentName,
153
+ sourceBranch: null,
154
+ mcpServerUrl,
155
+ createdAt: new Date(),
156
+ projectId,
157
+ latestDeployment: null,
158
+ },
159
+ ],
160
+ productionEnvironment: {
161
+ id: environmentId,
162
+ name: environmentName,
163
+ mcpServerUrl,
164
+ latestDeployment: null,
165
+ },
166
+ sourceRepository: null,
167
+ runtime: "node24",
168
+ transport: null,
169
+ rootDirectory: null,
170
+ buildCommand: null,
171
+ buildOutputDir: null,
172
+ installCommand: null,
173
+ startCommand: null,
174
+ createdAt: new Date(),
175
+ };
176
+ }
177
+ async function setupTestDirectory() {
178
+ const uniqueId = randomUUID();
179
+ const cwd = await mkdtemp(join(tmpdir(), `alpic-cli-e2e-${uniqueId}-`));
180
+ const fixturePath = join(__dirname, "fixtures", "demo-project");
181
+ await cp(fixturePath, cwd, { recursive: true });
182
+ const binPath = join(process.cwd(), "bin", "dev.js");
183
+ return { cwd, binPath };
184
+ }
185
+ function createConfigFile(cwd, projectId, teamId, projectName, environmentId, environmentName) {
186
+ const configDir = join(cwd, ".alpic");
187
+ mkdirSync(configDir, { recursive: true });
188
+ const configPath = join(configDir, "project.json");
189
+ writeFileSync(configPath, JSON.stringify({
190
+ projectId,
191
+ teamId,
192
+ projectName,
193
+ environmentId,
194
+ environmentName,
195
+ }));
196
+ }
197
+ async function verifyConfigFile(cwd, output, expected) {
198
+ const cfgPath = join(cwd, ".alpic", "project.json");
199
+ const cfg = await readFile(cfgPath, "utf8");
200
+ const config = JSON.parse(cfg);
201
+ expect(config.projectName).toBe(expected.projectName);
202
+ if (expected.projectId !== undefined) {
203
+ expect(config.projectId).toBe(expected.projectId);
204
+ }
205
+ else {
206
+ expect(config.projectId).toBeDefined();
207
+ }
208
+ if (expected.teamId !== undefined) {
209
+ expect(config.teamId).toBe(expected.teamId);
210
+ }
211
+ else {
212
+ expect(config.teamId).toBeDefined();
213
+ }
214
+ if (expected.environmentId !== undefined) {
215
+ expect(config.environmentId).toBe(expected.environmentId);
216
+ }
217
+ else {
218
+ expect(config.environmentId).toBeDefined();
219
+ }
220
+ if (expected.environmentName !== undefined) {
221
+ expect(config.environmentName).toBe(expected.environmentName);
222
+ }
223
+ else {
224
+ expect(config.environmentName).toBeDefined();
225
+ }
226
+ expect(output).toMatch(/Deployment completed|Deployment summary/);
227
+ }
228
+ async function verifyDeploymentFlow(cli, mockServer) {
229
+ await cli.expect(/Collected \d+ file/);
230
+ await cli.expect("Upload complete");
231
+ const uploadCall = mockServer.getLastCall("POST", "/v1/deployments/upload");
232
+ expectSuccessfulApiCall(uploadCall);
233
+ await cli.expect("Deployment started");
234
+ const deployCall = mockServer.getLastCall("POST", /\/v1\/environments\/.*\/deploy/);
235
+ expectSuccessfulApiCall(deployCall);
236
+ await cli.expect("View deployment details:");
237
+ await cli.expect("Deployment summary:");
238
+ const deploymentStatusCalls = mockServer.getCalls("GET", /\/v1\/deployments\/.*/);
239
+ expect(deploymentStatusCalls.length).toBeGreaterThan(0);
240
+ const envCall = mockServer.getLastCall("GET", /\/v1\/environments\/.*/);
241
+ expectSuccessfulApiCall(envCall);
242
+ }
243
+ function expectSuccessfulApiCall(call, customAssertions) {
244
+ expect(call).toBeDefined();
245
+ expect(call?.responseStatus).toBe(200);
246
+ if (customAssertions && call) {
247
+ customAssertions(call);
248
+ }
249
+ }
250
+ //# sourceMappingURL=deploy.e2e.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.e2e.test.js","sourceRoot":"","sources":["../../src/__tests__/deploy.e2e.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ console.log("Hello from Alpic!");
2
+ module.exports = {};
3
+ export {};
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/__tests__/fixtures/demo-project/index.js"],"names":[],"mappings":"AAAA,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;AACjC,MAAM,CAAC,OAAO,GAAG,EAAE,CAAC"}
@@ -0,0 +1,22 @@
1
+ import { type RouterOutput } from "@alpic-ai/api";
2
+ export type ApiCall = {
3
+ method: string;
4
+ path: string;
5
+ timestamp: Date;
6
+ input?: unknown;
7
+ responseStatus?: number;
8
+ };
9
+ export declare class MockApiServer {
10
+ private server;
11
+ private app;
12
+ private port;
13
+ private mockData;
14
+ private callHistory;
15
+ constructor();
16
+ start(): Promise<string>;
17
+ private configureServer;
18
+ stop(): Promise<void>;
19
+ getCalls(method?: string, pathPattern?: string | RegExp): ApiCall[];
20
+ getLastCall(method?: string, pathPattern?: string | RegExp): ApiCall | undefined;
21
+ addProject(project: RouterOutput["projects"]["get"]["v1"]): void;
22
+ }
@@ -0,0 +1,353 @@
1
+ import { OpenAPIHandler } from "@orpc/openapi/node";
2
+ import { ORPCError, implement } from "@orpc/server";
3
+ import express, {} from "express";
4
+ import { randomUUID } from "node:crypto";
5
+ import { contract } from "@alpic-ai/api";
6
+ export class MockApiServer {
7
+ server = null;
8
+ app;
9
+ port = null;
10
+ mockData;
11
+ callHistory = [];
12
+ constructor() {
13
+ this.app = express();
14
+ this.mockData = {
15
+ projects: new Map(),
16
+ environments: new Map(),
17
+ deployments: new Map(),
18
+ };
19
+ }
20
+ async start() {
21
+ if (this.server) {
22
+ throw new Error("Server is already running");
23
+ }
24
+ this.configureServer();
25
+ return new Promise((resolve) => {
26
+ this.server = this.app.listen(0, "127.0.0.1", () => {
27
+ const address = this.server.address();
28
+ this.port = address.port;
29
+ const url = `http://127.0.0.1:${this.port}`;
30
+ resolve(url);
31
+ });
32
+ });
33
+ }
34
+ configureServer() {
35
+ this.app.put("/__mock__upload/:token", express.raw({ type: "*/*", limit: "50mb" }), async (req, res) => {
36
+ const apiCall = {
37
+ method: req.method,
38
+ path: req.path,
39
+ timestamp: new Date(),
40
+ input: { token: req.params.token, size: req.body.length },
41
+ responseStatus: 200,
42
+ };
43
+ this.callHistory.push(apiCall);
44
+ res.status(200).end();
45
+ });
46
+ this.app.use(express.json());
47
+ const router = implement(contract).router({
48
+ projects: {
49
+ list: {
50
+ v1: implement(contract.projects.list.v1).handler(async () => {
51
+ return Array.from(this.mockData.projects.values()).map((project) => ({
52
+ id: project.id,
53
+ name: project.name,
54
+ teamId: project.teamId,
55
+ environments: project.environments,
56
+ productionEnvironment: project.productionEnvironment,
57
+ sourceRepository: project.sourceRepository,
58
+ runtime: project.runtime,
59
+ transport: project.transport,
60
+ rootDirectory: project.rootDirectory,
61
+ buildCommand: project.buildCommand,
62
+ buildOutputDir: project.buildOutputDir,
63
+ installCommand: project.installCommand,
64
+ startCommand: project.startCommand,
65
+ createdAt: project.createdAt,
66
+ }));
67
+ }),
68
+ },
69
+ get: {
70
+ v1: implement(contract.projects.get.v1).handler(async ({ input }) => {
71
+ const project = this.mockData.projects.get(input.projectId);
72
+ if (!project) {
73
+ throw new ORPCError("NOT_FOUND", { message: "Project not found" });
74
+ }
75
+ return project;
76
+ }),
77
+ },
78
+ create: {
79
+ v1: implement(contract.projects.create.v1).handler(async ({ input }) => {
80
+ const projectId = randomUUID();
81
+ const teamId = "mock-team-id";
82
+ const productionEnvId = randomUUID();
83
+ const productionEnvName = "production";
84
+ const project = {
85
+ id: projectId,
86
+ name: input.name,
87
+ teamId,
88
+ environments: [],
89
+ productionEnvironment: {
90
+ id: productionEnvId,
91
+ name: productionEnvName,
92
+ },
93
+ sourceRepository: input.sourceRepository ?? null,
94
+ runtime: input.runtime,
95
+ transport: input.transport ?? null,
96
+ rootDirectory: input.rootDirectory ?? null,
97
+ buildCommand: input.settings?.buildCommand ?? null,
98
+ buildOutputDir: input.settings?.buildOutputDir ?? null,
99
+ installCommand: input.settings?.installCommand ?? null,
100
+ startCommand: input.settings?.startCommand ?? null,
101
+ createdAt: new Date(),
102
+ };
103
+ const environment = {
104
+ id: productionEnvId,
105
+ name: productionEnvName,
106
+ sourceBranch: null,
107
+ mcpServerUrl: `https://mcp-${projectId}.alpic.ai`,
108
+ domains: [`https://mcp-${projectId}.alpic.ai`],
109
+ createdAt: new Date(),
110
+ projectId,
111
+ };
112
+ this.mockData.environments.set(productionEnvId, environment);
113
+ const fullProject = {
114
+ ...project,
115
+ productionEnvironment: {
116
+ id: productionEnvId,
117
+ name: productionEnvName,
118
+ mcpServerUrl: `https://mcp-${projectId}.alpic.ai`,
119
+ latestDeployment: null,
120
+ },
121
+ environments: [
122
+ {
123
+ id: productionEnvId,
124
+ name: productionEnvName,
125
+ sourceBranch: null,
126
+ mcpServerUrl: `https://mcp-${projectId}.alpic.ai`,
127
+ createdAt: new Date(),
128
+ projectId,
129
+ latestDeployment: null,
130
+ },
131
+ ],
132
+ };
133
+ this.mockData.projects.set(projectId, fullProject);
134
+ return project;
135
+ }),
136
+ },
137
+ },
138
+ environments: {
139
+ create: {
140
+ v1: implement(contract.environments.create.v1).handler(async ({ input }) => {
141
+ const project = this.mockData.projects.get(input.projectId);
142
+ if (!project) {
143
+ throw new ORPCError("NOT_FOUND", { message: "Project not found" });
144
+ }
145
+ const environmentId = randomUUID();
146
+ const mcpServerUrl = `https://mcp-${environmentId}.alpic.ai`;
147
+ const createdAt = new Date();
148
+ const environment = {
149
+ id: environmentId,
150
+ name: input.name,
151
+ sourceBranch: input.sourceBranch,
152
+ mcpServerUrl,
153
+ domains: [mcpServerUrl],
154
+ createdAt,
155
+ projectId: input.projectId,
156
+ };
157
+ this.mockData.environments.set(environmentId, environment);
158
+ this.mockData.projects.set(input.projectId, {
159
+ ...project,
160
+ environments: [
161
+ ...project.environments,
162
+ {
163
+ id: environmentId,
164
+ name: input.name,
165
+ sourceBranch: input.sourceBranch,
166
+ mcpServerUrl,
167
+ createdAt,
168
+ projectId: input.projectId,
169
+ latestDeployment: null,
170
+ },
171
+ ],
172
+ });
173
+ return {
174
+ id: environmentId,
175
+ name: input.name,
176
+ sourceBranch: input.sourceBranch,
177
+ createdAt,
178
+ projectId: input.projectId,
179
+ urls: [mcpServerUrl],
180
+ };
181
+ }),
182
+ },
183
+ get: {
184
+ v1: implement(contract.environments.get.v1).handler(async ({ input }) => {
185
+ const environment = this.mockData.environments.get(input.environmentId);
186
+ if (!environment) {
187
+ throw new ORPCError("NOT_FOUND", { message: "Environment not found" });
188
+ }
189
+ return environment;
190
+ }),
191
+ },
192
+ deploy: {
193
+ v1: implement(contract.environments.deploy.v1).handler(async ({ input }) => {
194
+ const environment = this.mockData.environments.get(input.environmentId);
195
+ if (!environment) {
196
+ throw new ORPCError("NOT_FOUND", { message: "Environment not found" });
197
+ }
198
+ const deploymentId = randomUUID();
199
+ const deployment = {
200
+ id: deploymentId,
201
+ status: "ongoing",
202
+ sourceRef: environment.sourceBranch,
203
+ sourceCommitId: randomUUID().slice(0, 7),
204
+ sourceCommitMessage: "Mock deployment",
205
+ authorUsername: "test-user",
206
+ authorAvatarUrl: null,
207
+ startedAt: new Date(),
208
+ completedAt: null,
209
+ };
210
+ this.mockData.deployments.set(deploymentId, deployment);
211
+ return deployment;
212
+ }),
213
+ },
214
+ },
215
+ deployments: {
216
+ get: {
217
+ v1: implement(contract.deployments.get.v1).handler(async ({ input }) => {
218
+ const deployment = this.mockData.deployments.get(input.deploymentId);
219
+ if (!deployment) {
220
+ throw new ORPCError("NOT_FOUND", { message: "Deployment not found" });
221
+ }
222
+ if (deployment.status === "ongoing") {
223
+ const updatedDeployment = {
224
+ ...deployment,
225
+ status: "deployed",
226
+ completedAt: new Date(),
227
+ };
228
+ this.mockData.deployments.set(input.deploymentId, updatedDeployment);
229
+ return updatedDeployment;
230
+ }
231
+ return deployment;
232
+ }),
233
+ },
234
+ uploadArtifact: {
235
+ v1: implement(contract.deployments.uploadArtifact.v1).handler(async () => {
236
+ const token = randomUUID();
237
+ const baseUrl = `http://127.0.0.1:${this.port}`;
238
+ const uploadUrl = `${baseUrl}/__mock__upload/${token}`;
239
+ return {
240
+ uploadUrl,
241
+ token,
242
+ expiresAt: new Date(Date.now() + 3600000),
243
+ };
244
+ }),
245
+ },
246
+ },
247
+ });
248
+ const handler = new OpenAPIHandler(router);
249
+ this.app.use(async (req, res) => {
250
+ const apiCall = {
251
+ method: req.method,
252
+ path: req.path,
253
+ timestamp: new Date(),
254
+ };
255
+ if (req.body) {
256
+ apiCall.input = req.body;
257
+ }
258
+ const result = await handler.handle(req, res, {
259
+ context: {},
260
+ });
261
+ if (!result.matched) {
262
+ apiCall.responseStatus = 404;
263
+ this.callHistory.push(apiCall);
264
+ res.status(404).json({ error: "Not found" });
265
+ return;
266
+ }
267
+ apiCall.responseStatus = res.statusCode || 200;
268
+ this.callHistory.push(apiCall);
269
+ });
270
+ }
271
+ async stop() {
272
+ return new Promise((resolve, reject) => {
273
+ if (!this.server) {
274
+ resolve();
275
+ return;
276
+ }
277
+ this.server.close((error) => {
278
+ if (error) {
279
+ console.error("[MOCK] Error stopping server:", error);
280
+ reject(error);
281
+ }
282
+ else {
283
+ this.server = null;
284
+ resolve();
285
+ }
286
+ });
287
+ });
288
+ }
289
+ getCalls(method, pathPattern) {
290
+ return this.callHistory.filter((call) => {
291
+ if (method && call.method !== method)
292
+ return false;
293
+ if (pathPattern) {
294
+ if (typeof pathPattern === "string") {
295
+ if (!call.path.includes(pathPattern))
296
+ return false;
297
+ }
298
+ else {
299
+ if (!pathPattern.test(call.path))
300
+ return false;
301
+ }
302
+ }
303
+ return true;
304
+ });
305
+ }
306
+ getLastCall(method, pathPattern) {
307
+ for (let i = this.callHistory.length - 1; i >= 0; i--) {
308
+ const call = this.callHistory[i];
309
+ if (method && call.method !== method)
310
+ continue;
311
+ if (pathPattern) {
312
+ if (typeof pathPattern === "string") {
313
+ if (!call.path.includes(pathPattern))
314
+ continue;
315
+ }
316
+ else {
317
+ if (!pathPattern.test(call.path))
318
+ continue;
319
+ }
320
+ }
321
+ return call;
322
+ }
323
+ return undefined;
324
+ }
325
+ addProject(project) {
326
+ this.mockData.projects.set(project.id, project);
327
+ if (project.productionEnvironment) {
328
+ const env = {
329
+ id: project.productionEnvironment.id,
330
+ name: project.productionEnvironment.name,
331
+ sourceBranch: null,
332
+ mcpServerUrl: project.productionEnvironment.mcpServerUrl,
333
+ domains: [project.productionEnvironment.mcpServerUrl],
334
+ createdAt: new Date(),
335
+ projectId: project.id,
336
+ };
337
+ this.mockData.environments.set(env.id, env);
338
+ }
339
+ for (const env of project.environments) {
340
+ const fullEnv = {
341
+ id: env.id,
342
+ name: env.name,
343
+ sourceBranch: env.sourceBranch,
344
+ mcpServerUrl: env.mcpServerUrl,
345
+ domains: [env.mcpServerUrl],
346
+ createdAt: env.createdAt,
347
+ projectId: project.id,
348
+ };
349
+ this.mockData.environments.set(env.id, fullEnv);
350
+ }
351
+ }
352
+ }
353
+ //# sourceMappingURL=mock-server.js.map