alpic 0.0.0-dev.f861645 → 0.0.0-dev.f8fa5ec

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 (180) hide show
  1. package/dist/__tests__/auth.e2e.test.d.ts +1 -0
  2. package/dist/__tests__/auth.e2e.test.js +158 -0
  3. package/dist/__tests__/auth.e2e.test.js.map +1 -0
  4. package/dist/__tests__/deploy-flags.e2e.test.d.ts +1 -0
  5. package/dist/__tests__/deploy-flags.e2e.test.js +111 -0
  6. package/dist/__tests__/deploy-flags.e2e.test.js.map +1 -0
  7. package/dist/__tests__/deploy.e2e.test.d.ts +1 -0
  8. package/dist/__tests__/deploy.e2e.test.js +168 -0
  9. package/dist/__tests__/deploy.e2e.test.js.map +1 -0
  10. package/dist/__tests__/deployment-inspect.e2e.test.d.ts +1 -0
  11. package/dist/__tests__/deployment-inspect.e2e.test.js +113 -0
  12. package/dist/__tests__/deployment-inspect.e2e.test.js.map +1 -0
  13. package/dist/__tests__/deployment-list.e2e.test.d.ts +1 -0
  14. package/dist/__tests__/deployment-list.e2e.test.js +116 -0
  15. package/dist/__tests__/deployment-list.e2e.test.js.map +1 -0
  16. package/dist/__tests__/deployment-logs.e2e.test.d.ts +1 -0
  17. package/dist/__tests__/deployment-logs.e2e.test.js +255 -0
  18. package/dist/__tests__/deployment-logs.e2e.test.js.map +1 -0
  19. package/dist/__tests__/environment-variable/environment-variable-add.e2e.test.d.ts +1 -0
  20. package/dist/__tests__/environment-variable/environment-variable-add.e2e.test.js +260 -0
  21. package/dist/__tests__/environment-variable/environment-variable-add.e2e.test.js.map +1 -0
  22. package/dist/__tests__/environment-variable/environment-variable-list.e2e.test.d.ts +1 -0
  23. package/dist/__tests__/environment-variable/environment-variable-list.e2e.test.js +140 -0
  24. package/dist/__tests__/environment-variable/environment-variable-list.e2e.test.js.map +1 -0
  25. package/dist/__tests__/environment-variable/environment-variable-remove.e2e.test.d.ts +1 -0
  26. package/dist/__tests__/environment-variable/environment-variable-remove.e2e.test.js +151 -0
  27. package/dist/__tests__/environment-variable/environment-variable-remove.e2e.test.js.map +1 -0
  28. package/dist/__tests__/environment-variable/environment-variable-update.e2e.test.d.ts +1 -0
  29. package/dist/__tests__/environment-variable/environment-variable-update.e2e.test.js +343 -0
  30. package/dist/__tests__/environment-variable/environment-variable-update.e2e.test.js.map +1 -0
  31. package/dist/__tests__/environment-variable/environment-variable-validation.test.d.ts +1 -0
  32. package/dist/__tests__/environment-variable/environment-variable-validation.test.js +20 -0
  33. package/dist/__tests__/environment-variable/environment-variable-validation.test.js.map +1 -0
  34. package/dist/__tests__/fixtures/demo-project/index.d.ts +1 -0
  35. package/dist/__tests__/fixtures/demo-project/index.js +4 -0
  36. package/dist/__tests__/fixtures/demo-project/index.js.map +1 -0
  37. package/dist/__tests__/git-flags.e2e.test.d.ts +1 -0
  38. package/dist/__tests__/git-flags.e2e.test.js +124 -0
  39. package/dist/__tests__/git-flags.e2e.test.js.map +1 -0
  40. package/dist/__tests__/git.e2e.test.d.ts +1 -0
  41. package/dist/__tests__/git.e2e.test.js +221 -0
  42. package/dist/__tests__/git.e2e.test.js.map +1 -0
  43. package/dist/__tests__/logs.e2e.test.d.ts +1 -0
  44. package/dist/__tests__/logs.e2e.test.js +227 -0
  45. package/dist/__tests__/logs.e2e.test.js.map +1 -0
  46. package/dist/__tests__/mock-server.d.ts +38 -0
  47. package/dist/__tests__/mock-server.js +728 -0
  48. package/dist/__tests__/mock-server.js.map +1 -0
  49. package/dist/__tests__/publish.e2e.test.d.ts +1 -0
  50. package/dist/__tests__/publish.e2e.test.js +505 -0
  51. package/dist/__tests__/publish.e2e.test.js.map +1 -0
  52. package/dist/__tests__/tunnel.e2e.test.d.ts +1 -0
  53. package/dist/__tests__/tunnel.e2e.test.js +64 -0
  54. package/dist/__tests__/tunnel.e2e.test.js.map +1 -0
  55. package/dist/__tests__/utils.d.ts +72 -0
  56. package/dist/__tests__/utils.js +272 -0
  57. package/dist/__tests__/utils.js.map +1 -0
  58. package/dist/api.d.ts +1 -2
  59. package/dist/api.js +6 -10
  60. package/dist/api.js.map +1 -1
  61. package/dist/commands/deploy.d.ts +7 -4
  62. package/dist/commands/deploy.js +47 -28
  63. package/dist/commands/deploy.js.map +1 -1
  64. package/dist/commands/deployment/inspect.d.ts +11 -0
  65. package/dist/commands/deployment/inspect.js +91 -0
  66. package/dist/commands/deployment/inspect.js.map +1 -0
  67. package/dist/commands/deployment/list.d.ts +11 -0
  68. package/dist/commands/deployment/list.js +97 -0
  69. package/dist/commands/deployment/list.js.map +1 -0
  70. package/dist/commands/deployment/logs.d.ts +12 -0
  71. package/dist/commands/deployment/logs.js +50 -0
  72. package/dist/commands/deployment/logs.js.map +1 -0
  73. package/dist/commands/environment-variable/add.d.ts +14 -0
  74. package/dist/commands/environment-variable/add.js +46 -0
  75. package/dist/commands/environment-variable/add.js.map +1 -0
  76. package/dist/commands/environment-variable/list.d.ts +9 -0
  77. package/dist/commands/environment-variable/list.js +44 -0
  78. package/dist/commands/environment-variable/list.js.map +1 -0
  79. package/dist/commands/environment-variable/remove.d.ts +11 -0
  80. package/dist/commands/environment-variable/remove.js +32 -0
  81. package/dist/commands/environment-variable/remove.js.map +1 -0
  82. package/dist/commands/environment-variable/update.d.ts +13 -0
  83. package/dist/commands/environment-variable/update.js +40 -0
  84. package/dist/commands/environment-variable/update.js.map +1 -0
  85. package/dist/commands/git/connect.d.ts +10 -0
  86. package/dist/commands/git/connect.js +60 -0
  87. package/dist/commands/git/connect.js.map +1 -0
  88. package/dist/commands/git/disconnect.d.ts +9 -0
  89. package/dist/commands/git/disconnect.js +45 -0
  90. package/dist/commands/git/disconnect.js.map +1 -0
  91. package/dist/commands/git.d.ts +6 -0
  92. package/dist/commands/git.js +17 -0
  93. package/dist/commands/git.js.map +1 -0
  94. package/dist/commands/login.d.ts +6 -0
  95. package/dist/commands/login.js +34 -0
  96. package/dist/commands/login.js.map +1 -0
  97. package/dist/commands/logout.d.ts +6 -0
  98. package/dist/commands/logout.js +20 -0
  99. package/dist/commands/logout.js.map +1 -0
  100. package/dist/commands/logs.d.ts +16 -0
  101. package/dist/commands/logs.js +96 -0
  102. package/dist/commands/logs.js.map +1 -0
  103. package/dist/commands/publish.d.ts +15 -0
  104. package/dist/commands/publish.js +51 -0
  105. package/dist/commands/publish.js.map +1 -0
  106. package/dist/commands/tunnel.d.ts +9 -0
  107. package/dist/commands/tunnel.js +53 -0
  108. package/dist/commands/tunnel.js.map +1 -0
  109. package/dist/commands/whoami.d.ts +6 -0
  110. package/dist/commands/whoami.js +13 -0
  111. package/dist/commands/whoami.js.map +1 -0
  112. package/dist/env.d.ts +4 -0
  113. package/dist/env.js +10 -0
  114. package/dist/env.js.map +1 -0
  115. package/dist/lib/alpic-command.d.ts +6 -0
  116. package/dist/lib/alpic-command.js +27 -0
  117. package/dist/lib/alpic-command.js.map +1 -0
  118. package/dist/lib/archive.d.ts +3 -3
  119. package/dist/lib/archive.js +11 -15
  120. package/dist/lib/archive.js.map +1 -1
  121. package/dist/lib/auth/auth.d.ts +2 -0
  122. package/dist/lib/auth/auth.js +21 -0
  123. package/dist/lib/auth/auth.js.map +1 -0
  124. package/dist/lib/auth/oauth/client.d.ts +28 -0
  125. package/dist/lib/auth/oauth/client.js +110 -0
  126. package/dist/lib/auth/oauth/client.js.map +1 -0
  127. package/dist/lib/auth/oauth/constants.d.ts +2 -0
  128. package/dist/lib/auth/oauth/constants.js +3 -0
  129. package/dist/lib/auth/oauth/constants.js.map +1 -0
  130. package/dist/lib/auth/oauth/server/assets/alpic-mountain.png +0 -0
  131. package/dist/lib/auth/oauth/server/assets/authorize.html +195 -0
  132. package/dist/lib/auth/oauth/server/assets/callback.html +88 -0
  133. package/dist/lib/auth/oauth/server/index.d.ts +8 -0
  134. package/dist/lib/auth/oauth/server/index.js +105 -0
  135. package/dist/lib/auth/oauth/server/index.js.map +1 -0
  136. package/dist/lib/auth/whoami.d.ts +1 -0
  137. package/dist/lib/auth/whoami.js +41 -0
  138. package/dist/lib/auth/whoami.js.map +1 -0
  139. package/dist/lib/base-workflow.d.ts +10 -0
  140. package/dist/lib/base-workflow.js +22 -0
  141. package/dist/lib/base-workflow.js.map +1 -0
  142. package/dist/lib/config.d.ts +2 -2
  143. package/dist/lib/config.js +7 -7
  144. package/dist/lib/config.js.map +1 -1
  145. package/dist/lib/deployment.d.ts +70 -3
  146. package/dist/lib/deployment.js +121 -9
  147. package/dist/lib/deployment.js.map +1 -1
  148. package/dist/lib/environment-variable.d.ts +41 -0
  149. package/dist/lib/environment-variable.js +311 -0
  150. package/dist/lib/environment-variable.js.map +1 -0
  151. package/dist/lib/git.d.ts +22 -0
  152. package/dist/lib/git.js +131 -0
  153. package/dist/lib/git.js.map +1 -0
  154. package/dist/lib/global-store.d.ts +28 -0
  155. package/dist/lib/global-store.js +76 -0
  156. package/dist/lib/global-store.js.map +1 -0
  157. package/dist/lib/logs.d.ts +20 -0
  158. package/dist/lib/logs.js +86 -0
  159. package/dist/lib/logs.js.map +1 -0
  160. package/dist/lib/project.d.ts +68 -61
  161. package/dist/lib/project.js +275 -250
  162. package/dist/lib/project.js.map +1 -1
  163. package/dist/lib/publish.d.ts +22 -0
  164. package/dist/lib/publish.js +188 -0
  165. package/dist/lib/publish.js.map +1 -0
  166. package/dist/lib/table.d.ts +8 -0
  167. package/dist/lib/table.js +27 -0
  168. package/dist/lib/table.js.map +1 -0
  169. package/dist/lib/telemetry.js +7 -7
  170. package/dist/lib/telemetry.js.map +1 -1
  171. package/dist/lib/utils.d.ts +4 -0
  172. package/dist/lib/utils.js +45 -0
  173. package/dist/lib/utils.js.map +1 -0
  174. package/dist/lib/utils.test.d.ts +1 -0
  175. package/dist/lib/utils.test.js +27 -0
  176. package/dist/lib/utils.test.js.map +1 -0
  177. package/package.json +36 -26
  178. package/dist/lib/global-config.d.ts +0 -9
  179. package/dist/lib/global-config.js +0 -48
  180. package/dist/lib/global-config.js.map +0 -1
@@ -0,0 +1,728 @@
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";
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
+ }
21
+ export class MockApiServer {
22
+ server = null;
23
+ app;
24
+ port = null;
25
+ mockData;
26
+ callHistory = [];
27
+ constructor() {
28
+ this.app = express();
29
+ this.mockData = {
30
+ projects: new Map(),
31
+ environments: new Map(),
32
+ deployments: new Map(),
33
+ environmentVariables: new Map(),
34
+ runtimeLogs: new Map(),
35
+ runtimeLogPages: new Map(),
36
+ deploymentLogPages: new Map(),
37
+ deploymentLogCallCounts: new Map(),
38
+ publishedServers: new Map(),
39
+ };
40
+ }
41
+ async start() {
42
+ if (this.server) {
43
+ throw new Error("Server is already running");
44
+ }
45
+ this.configureServer();
46
+ const tlsAssets = getTlsAssets();
47
+ process.env.NODE_EXTRA_CA_CERTS = tlsAssets.certPath;
48
+ const httpsOptions = { key: tlsAssets.key, cert: tlsAssets.cert };
49
+ return new Promise((resolve) => {
50
+ this.server = https.createServer(httpsOptions, this.app).listen(0, "127.0.0.1", () => {
51
+ if (!this.server) {
52
+ throw new Error("Server is not running");
53
+ }
54
+ const address = this.server.address();
55
+ this.port = address.port;
56
+ const url = `https://127.0.0.1:${this.port}`;
57
+ resolve(url);
58
+ });
59
+ });
60
+ }
61
+ configureServer() {
62
+ this.app.put("/__mock__upload/:token", express.raw({ type: "*/*", limit: "50mb" }), async (req, res) => {
63
+ const apiCall = {
64
+ method: req.method,
65
+ path: req.path,
66
+ timestamp: new Date(),
67
+ input: { token: req.params.token, size: req.body.length },
68
+ responseStatus: 200,
69
+ };
70
+ this.callHistory.push(apiCall);
71
+ res.status(200).end();
72
+ });
73
+ this.app.use(express.json());
74
+ this.app.get("/.well-known/oauth-protected-resource", (_req, res) => {
75
+ const base = `https://127.0.0.1:${this.port}`;
76
+ res.status(200).json({
77
+ resource: "https://api.alpic.ai",
78
+ authorization_servers: [base],
79
+ bearer_methods_supported: ["header"],
80
+ scopes_supported: ["openid", "email", "profile"],
81
+ resource_documentation: "https://docs.alpic.ai",
82
+ });
83
+ });
84
+ this.app.get("/.well-known/openid-configuration", (_req, res) => {
85
+ const base = `https://127.0.0.1:${this.port}`;
86
+ res.status(200).json({
87
+ issuer: base,
88
+ userinfo_endpoint: `${base}/oauth2/userInfo`,
89
+ authorization_endpoint: `${base}/oauth2/authorize`,
90
+ token_endpoint: `${base}/oauth2/token`,
91
+ jwks_uri: `${base}/.well-known/jwks.json`,
92
+ });
93
+ });
94
+ this.app.get("/oauth2/userInfo", (req, res) => {
95
+ const auth = req.headers.authorization;
96
+ if (!auth?.startsWith("Bearer ")) {
97
+ res.status(401).json({ error: "Missing or invalid Authorization" });
98
+ return;
99
+ }
100
+ res.status(200).json({
101
+ sub: "test-sub",
102
+ email_verified: "true",
103
+ identities: [],
104
+ name: "Test User",
105
+ email: "test@example.com",
106
+ picture: "",
107
+ username: "testuser",
108
+ });
109
+ });
110
+ const router = implement(contract).router({
111
+ tunnels: {
112
+ getTicket: {
113
+ v1: implement(contract.tunnels.getTicket.v1).handler(async () => {
114
+ return {
115
+ subdomain: "cool-mongoose-123",
116
+ ticket: "mock-ticket",
117
+ tunnelHost: "tunnel.alpic.dev",
118
+ };
119
+ }),
120
+ },
121
+ },
122
+ teams: {
123
+ list: {
124
+ v1: implement(contract.teams.list.v1).handler(async () => {
125
+ return [
126
+ {
127
+ id: "mock-team-id",
128
+ name: "Mock Team",
129
+ createdAt: new Date(),
130
+ hasStripeAccount: false,
131
+ },
132
+ ];
133
+ }),
134
+ },
135
+ },
136
+ analytics: {
137
+ get: {
138
+ v1: implement(contract.analytics.get.v1).handler(async ({ input }) => {
139
+ const project = this.mockData.projects.get(input.projectId);
140
+ if (!project) {
141
+ throw new ORPCError("NOT_FOUND", {
142
+ message: "Project not found",
143
+ });
144
+ }
145
+ const emptyTimeSeries = {
146
+ sessions_count: [],
147
+ requests_count: [],
148
+ requests_latency_mean: [],
149
+ tool_errors: [],
150
+ mcp_errors: [],
151
+ output_token_mean: [],
152
+ task_count: [],
153
+ };
154
+ return {
155
+ metadata: {
156
+ startTimestamp: input.startTimestamp,
157
+ endTimestamp: input.endTimestamp,
158
+ timeZone: input.timeZone,
159
+ startDate: new Date(input.startTimestamp),
160
+ interval: "1h",
161
+ },
162
+ timeSeries: emptyTimeSeries,
163
+ };
164
+ }),
165
+ },
166
+ },
167
+ projects: {
168
+ list: {
169
+ v1: implement(contract.projects.list.v1).handler(async () => {
170
+ return Array.from(this.mockData.projects.values()).map((project) => ({
171
+ id: project.id,
172
+ name: project.name,
173
+ teamId: project.teamId,
174
+ environments: project.environments,
175
+ productionEnvironment: project.productionEnvironment,
176
+ sourceRepository: project.sourceRepository,
177
+ runtime: project.runtime,
178
+ transport: project.transport,
179
+ rootDirectory: project.rootDirectory,
180
+ buildCommand: project.buildCommand,
181
+ buildOutputDir: project.buildOutputDir,
182
+ installCommand: project.installCommand,
183
+ startCommand: project.startCommand,
184
+ createdAt: project.createdAt,
185
+ }));
186
+ }),
187
+ },
188
+ get: {
189
+ v1: implement(contract.projects.get.v1).handler(async ({ input }) => {
190
+ const project = this.mockData.projects.get(input.projectId);
191
+ if (!project) {
192
+ throw new ORPCError("NOT_FOUND", {
193
+ message: "Project not found",
194
+ });
195
+ }
196
+ return project;
197
+ }),
198
+ },
199
+ create: {
200
+ v1: implement(contract.projects.create.v1).handler(async ({ input }) => {
201
+ const projectId = randomUUID();
202
+ const teamId = "mock-team-id";
203
+ const productionEnvId = randomUUID();
204
+ const productionEnvName = "production";
205
+ const project = {
206
+ id: projectId,
207
+ name: input.name,
208
+ teamId,
209
+ environments: [],
210
+ productionEnvironment: {
211
+ id: productionEnvId,
212
+ name: productionEnvName,
213
+ },
214
+ sourceRepository: input.sourceRepository ?? null,
215
+ runtime: input.runtime,
216
+ transport: input.transport ?? null,
217
+ rootDirectory: input.rootDirectory ?? null,
218
+ buildCommand: input.settings?.buildCommand ?? null,
219
+ buildOutputDir: input.settings?.buildOutputDir ?? null,
220
+ installCommand: input.settings?.installCommand ?? null,
221
+ startCommand: input.settings?.startCommand ?? null,
222
+ createdAt: new Date(),
223
+ };
224
+ const environment = {
225
+ id: productionEnvId,
226
+ name: productionEnvName,
227
+ sourceBranch: null,
228
+ mcpServerUrl: `https://mcp-${projectId}.alpic.ai`,
229
+ domains: [`https://mcp-${projectId}.alpic.ai`],
230
+ createdAt: new Date(),
231
+ projectId,
232
+ };
233
+ this.mockData.environments.set(productionEnvId, environment);
234
+ const fullProject = {
235
+ ...project,
236
+ productionEnvironment: {
237
+ id: productionEnvId,
238
+ name: productionEnvName,
239
+ mcpServerUrl: `https://mcp-${projectId}.alpic.ai`,
240
+ domains: [],
241
+ latestDeployment: null,
242
+ },
243
+ environments: [
244
+ {
245
+ id: productionEnvId,
246
+ name: productionEnvName,
247
+ sourceBranch: null,
248
+ mcpServerUrl: `https://mcp-${projectId}.alpic.ai`,
249
+ createdAt: new Date(),
250
+ projectId,
251
+ latestDeployment: null,
252
+ },
253
+ ],
254
+ };
255
+ this.mockData.projects.set(projectId, fullProject);
256
+ return project;
257
+ }),
258
+ },
259
+ update: {
260
+ v1: implement(contract.projects.update.v1).handler(async ({ input }) => {
261
+ const project = this.mockData.projects.get(input.projectId);
262
+ if (!project) {
263
+ throw new ORPCError("NOT_FOUND", {
264
+ message: "Project not found",
265
+ });
266
+ }
267
+ if (input.sourceRepository !== undefined) {
268
+ project.sourceRepository = input.sourceRepository;
269
+ }
270
+ this.mockData.projects.set(input.projectId, project);
271
+ return project;
272
+ }),
273
+ },
274
+ delete: {
275
+ v1: implement(contract.projects.delete.v1).handler(async ({ input }) => {
276
+ const project = this.mockData.projects.get(input.projectId);
277
+ if (!project) {
278
+ throw new ORPCError("NOT_FOUND", {
279
+ message: "Project not found",
280
+ });
281
+ }
282
+ this.mockData.projects.delete(input.projectId);
283
+ return { success: true };
284
+ }),
285
+ },
286
+ },
287
+ environments: {
288
+ create: {
289
+ v1: implement(contract.environments.create.v1).handler(async ({ input }) => {
290
+ const project = this.mockData.projects.get(input.projectId);
291
+ if (!project) {
292
+ throw new ORPCError("NOT_FOUND", {
293
+ message: "Project not found",
294
+ });
295
+ }
296
+ const environmentId = randomUUID();
297
+ const mcpServerUrl = `https://mcp-${environmentId}.alpic.ai`;
298
+ const createdAt = new Date();
299
+ const environment = {
300
+ id: environmentId,
301
+ name: input.name,
302
+ sourceBranch: input.sourceBranch,
303
+ mcpServerUrl,
304
+ domains: [mcpServerUrl],
305
+ createdAt,
306
+ projectId: input.projectId,
307
+ };
308
+ this.mockData.environments.set(environmentId, environment);
309
+ this.mockData.projects.set(input.projectId, {
310
+ ...project,
311
+ environments: [
312
+ ...project.environments,
313
+ {
314
+ id: environmentId,
315
+ name: input.name,
316
+ sourceBranch: input.sourceBranch,
317
+ mcpServerUrl,
318
+ createdAt,
319
+ projectId: input.projectId,
320
+ latestDeployment: null,
321
+ },
322
+ ],
323
+ });
324
+ return {
325
+ id: environmentId,
326
+ name: input.name,
327
+ sourceBranch: input.sourceBranch,
328
+ createdAt,
329
+ projectId: input.projectId,
330
+ urls: [mcpServerUrl],
331
+ };
332
+ }),
333
+ },
334
+ get: {
335
+ v1: implement(contract.environments.get.v1).handler(async ({ input }) => {
336
+ const environment = this.mockData.environments.get(input.environmentId);
337
+ if (!environment) {
338
+ throw new ORPCError("NOT_FOUND", {
339
+ message: "Environment not found",
340
+ });
341
+ }
342
+ return environment;
343
+ }),
344
+ },
345
+ getLogs: {
346
+ v1: implement(contract.environments.getLogs.v1).handler(async ({ input }) => {
347
+ const environment = this.mockData.environments.get(input.environmentId);
348
+ if (!environment) {
349
+ throw new ORPCError("NOT_FOUND", {
350
+ message: "Environment not found",
351
+ });
352
+ }
353
+ const pagedLogs = this.mockData.runtimeLogPages.get(input.environmentId);
354
+ const pageIndex = input.nextToken === undefined ? 0 : Number.parseInt(input.nextToken, 10);
355
+ const allLogs = pagedLogs === undefined
356
+ ? (this.mockData.runtimeLogs.get(input.environmentId) ?? [])
357
+ : (pagedLogs[pageIndex] ?? []);
358
+ let logs = allLogs;
359
+ if (input.level !== undefined) {
360
+ const levels = input.level;
361
+ logs = allLogs.filter((log) => levels.includes(log.type));
362
+ }
363
+ const nextToken = pagedLogs === undefined || pageIndex + 1 >= pagedLogs.length ? null : String(pageIndex + 1);
364
+ return { logs, nextToken };
365
+ }),
366
+ },
367
+ deploy: {
368
+ v1: implement(contract.environments.deploy.v1).handler(async ({ input }) => {
369
+ const environment = this.mockData.environments.get(input.environmentId);
370
+ if (!environment) {
371
+ throw new ORPCError("NOT_FOUND", {
372
+ message: "Environment not found",
373
+ });
374
+ }
375
+ const deploymentId = randomUUID();
376
+ const deployment = {
377
+ id: deploymentId,
378
+ status: "ongoing",
379
+ environmentId: environment.id,
380
+ environmentName: environment.name,
381
+ isCurrent: false,
382
+ sourceRef: environment.sourceBranch,
383
+ sourceCommitId: randomUUID().slice(0, 7),
384
+ sourceCommitMessage: "Mock deployment",
385
+ authorUsername: "test-user",
386
+ authorAvatarUrl: null,
387
+ startedAt: new Date(),
388
+ completedAt: null,
389
+ deploymentPageUrl: "https://app.alpic.ai/deployments/mock",
390
+ };
391
+ this.mockData.deployments.set(deploymentId, deployment);
392
+ return deployment;
393
+ }),
394
+ },
395
+ },
396
+ environmentVariables: {
397
+ list: {
398
+ v1: implement(contract.environmentVariables.list.v1).handler(async ({ input }) => {
399
+ const environment = this.mockData.environments.get(input.environmentId);
400
+ if (!environment) {
401
+ throw new ORPCError("NOT_FOUND", {
402
+ message: "Environment not found",
403
+ });
404
+ }
405
+ return this.mockData.environmentVariables.get(input.environmentId) ?? [];
406
+ }),
407
+ },
408
+ create: {
409
+ v1: implement(contract.environmentVariables.create.v1).handler(async ({ input }) => {
410
+ const environment = this.mockData.environments.get(input.environmentId);
411
+ if (!environment) {
412
+ throw new ORPCError("NOT_FOUND", {
413
+ message: "Environment not found",
414
+ });
415
+ }
416
+ const existing = this.mockData.environmentVariables.get(input.environmentId) ?? [];
417
+ const newVars = input.environmentVariables.map((variable) => ({
418
+ id: randomUUID(),
419
+ key: variable.key,
420
+ value: variable.value,
421
+ isSecret: variable.isSecret,
422
+ createdAt: new Date(),
423
+ }));
424
+ for (const newVar of newVars) {
425
+ if (existing.some((existingVar) => existingVar.key === newVar.key)) {
426
+ throw new ORPCError("BAD_REQUEST", {
427
+ message: `Environment variable "${newVar.key}" already exists`,
428
+ });
429
+ }
430
+ }
431
+ this.mockData.environmentVariables.set(input.environmentId, [...existing, ...newVars]);
432
+ return { success: true };
433
+ }),
434
+ },
435
+ update: {
436
+ v1: implement(contract.environmentVariables.update.v1).handler(async ({ input }) => {
437
+ for (const [environmentId, variables] of this.mockData.environmentVariables.entries()) {
438
+ const index = variables.findIndex((variable) => variable.id === input.environmentVariableId);
439
+ if (index !== -1) {
440
+ const updated = variables.map((variable, i) => i === index
441
+ ? {
442
+ ...variable,
443
+ key: input.key,
444
+ value: input.value ?? variable.value,
445
+ isSecret: input.isSecret,
446
+ }
447
+ : variable);
448
+ this.mockData.environmentVariables.set(environmentId, updated);
449
+ return { success: true };
450
+ }
451
+ }
452
+ throw new ORPCError("NOT_FOUND", {
453
+ message: "Environment variable not found",
454
+ });
455
+ }),
456
+ },
457
+ delete: {
458
+ v1: implement(contract.environmentVariables.delete.v1).handler(async ({ input }) => {
459
+ for (const [environmentId, variables] of this.mockData.environmentVariables.entries()) {
460
+ const index = variables.findIndex((variable) => variable.id === input.environmentVariableId);
461
+ if (index !== -1) {
462
+ this.mockData.environmentVariables.set(environmentId, variables.filter((_, i) => i !== index));
463
+ return { success: true };
464
+ }
465
+ }
466
+ throw new ORPCError("NOT_FOUND", {
467
+ message: "Environment variable not found",
468
+ });
469
+ }),
470
+ },
471
+ },
472
+ distribution: {
473
+ info: {
474
+ v1: implement(contract.distribution.info.v1).handler(async ({ input }) => {
475
+ const existing = this.mockData.publishedServers.get(`${input.projectId}:${input.domain}`);
476
+ return {
477
+ serverFields: existing ?? {
478
+ $schema: "https://registry.modelcontextprotocol.io/schemas/1.0/server.json",
479
+ name: "",
480
+ description: "",
481
+ },
482
+ };
483
+ }),
484
+ },
485
+ publish: {
486
+ v1: implement(contract.distribution.publish.v1).handler(async ({ input }) => {
487
+ const project = this.mockData.projects.get(input.projectId);
488
+ if (!project) {
489
+ throw new ORPCError("NOT_FOUND", {
490
+ message: "Project not found",
491
+ });
492
+ }
493
+ const key = `${input.projectId}:${input.domain}`;
494
+ const existing = this.mockData.publishedServers.get(key);
495
+ const version = existing?.version ? (semverInc(existing.version, "patch") ?? "0.0.1") : "0.0.1";
496
+ const serverFields = {
497
+ $schema: "https://registry.modelcontextprotocol.io/schemas/1.0/server.json",
498
+ name: input.domain,
499
+ description: input.description,
500
+ title: input.title,
501
+ version,
502
+ ...(input.websiteUrl ? { websiteUrl: input.websiteUrl } : {}),
503
+ ...(input.iconSrc ? { icons: [{ src: input.iconSrc }] } : {}),
504
+ };
505
+ if (!input.dryRun) {
506
+ this.mockData.publishedServers.set(key, serverFields);
507
+ }
508
+ return { serverFields };
509
+ }),
510
+ },
511
+ },
512
+ deployments: {
513
+ list: {
514
+ v1: implement(contract.deployments.list.v1).handler(async ({ input }) => {
515
+ const project = this.mockData.projects.get(input.projectId);
516
+ if (!project) {
517
+ throw new ORPCError("NOT_FOUND", {
518
+ message: "Project not found",
519
+ });
520
+ }
521
+ let deployments = Array.from(this.mockData.deployments.values());
522
+ if (input.environmentId) {
523
+ deployments = deployments.filter((deployment) => deployment.environmentId === input.environmentId);
524
+ }
525
+ if (input.status?.length) {
526
+ deployments = deployments.filter((deployment) => input.status.includes(deployment.status));
527
+ }
528
+ return deployments.map((deployment) => ({
529
+ ...deployment,
530
+ isCurrent: deployment.status === "deployed",
531
+ }));
532
+ }),
533
+ },
534
+ get: {
535
+ v1: implement(contract.deployments.get.v1).handler(async ({ input }) => {
536
+ const deployment = this.mockData.deployments.get(input.deploymentId);
537
+ if (!deployment) {
538
+ throw new ORPCError("NOT_FOUND", {
539
+ message: "Deployment not found",
540
+ });
541
+ }
542
+ if (deployment.status === "ongoing") {
543
+ const updatedDeployment = {
544
+ ...deployment,
545
+ status: "deployed",
546
+ completedAt: new Date(),
547
+ deploymentPageUrl: deployment.deploymentPageUrl ?? null,
548
+ };
549
+ this.mockData.deployments.set(input.deploymentId, updatedDeployment);
550
+ return updatedDeployment;
551
+ }
552
+ return deployment;
553
+ }),
554
+ },
555
+ getLogs: {
556
+ v1: implement(contract.deployments.getLogs.v1).handler(async ({ input }) => {
557
+ const deployment = this.mockData.deployments.get(input.deploymentId);
558
+ if (!deployment) {
559
+ throw new ORPCError("NOT_FOUND", {
560
+ message: "Deployment not found",
561
+ });
562
+ }
563
+ const pages = this.mockData.deploymentLogPages.get(input.deploymentId);
564
+ if (pages !== undefined) {
565
+ const callCount = this.mockData.deploymentLogCallCounts.get(input.deploymentId) ?? 0;
566
+ const pageIndex = Math.min(callCount, pages.length - 1);
567
+ this.mockData.deploymentLogCallCounts.set(input.deploymentId, callCount + 1);
568
+ return pages[pageIndex] ?? { logs: [], hasMoreLogs: false };
569
+ }
570
+ return {
571
+ logs: [{ timestamp: new Date(), content: "Mock log entry" }],
572
+ hasMoreLogs: false,
573
+ };
574
+ }),
575
+ },
576
+ uploadArtifact: {
577
+ v1: implement(contract.deployments.uploadArtifact.v1).handler(async () => {
578
+ const token = randomUUID();
579
+ const baseUrl = `https://127.0.0.1:${this.port}`;
580
+ const uploadUrl = `${baseUrl}/__mock__upload/${token}`;
581
+ return {
582
+ uploadUrl,
583
+ token,
584
+ expiresAt: new Date(Date.now() + 3600000),
585
+ };
586
+ }),
587
+ },
588
+ },
589
+ });
590
+ const handler = new OpenAPIHandler(router);
591
+ this.app.use(async (req, res) => {
592
+ const apiCall = {
593
+ method: req.method,
594
+ path: req.path,
595
+ timestamp: new Date(),
596
+ };
597
+ if (req.method === "GET") {
598
+ if (Object.keys(req.query).length > 0) {
599
+ apiCall.input = req.query;
600
+ }
601
+ }
602
+ else if (req.body) {
603
+ apiCall.input = req.body;
604
+ }
605
+ const result = await handler.handle(req, res, {
606
+ context: {},
607
+ });
608
+ if (!result.matched) {
609
+ apiCall.responseStatus = 404;
610
+ this.callHistory.push(apiCall);
611
+ res.status(404).json({ error: "Not found" });
612
+ return;
613
+ }
614
+ apiCall.responseStatus = res.statusCode || 200;
615
+ this.callHistory.push(apiCall);
616
+ });
617
+ }
618
+ async stop() {
619
+ return new Promise((resolve, reject) => {
620
+ if (!this.server) {
621
+ resolve();
622
+ return;
623
+ }
624
+ this.server.close((error) => {
625
+ if (error) {
626
+ console.error("[MOCK] Error stopping server:", error);
627
+ reject(error);
628
+ }
629
+ else {
630
+ this.server = null;
631
+ resolve();
632
+ }
633
+ });
634
+ });
635
+ }
636
+ getCalls(method, pathPattern) {
637
+ return this.callHistory.filter((call) => {
638
+ if (method && call.method !== method)
639
+ return false;
640
+ if (pathPattern) {
641
+ if (typeof pathPattern === "string") {
642
+ if (!call.path.includes(pathPattern))
643
+ return false;
644
+ }
645
+ else {
646
+ if (!pathPattern.test(call.path))
647
+ return false;
648
+ }
649
+ }
650
+ return true;
651
+ });
652
+ }
653
+ getLastCall(method, pathPattern) {
654
+ for (let i = this.callHistory.length - 1; i >= 0; i--) {
655
+ const call = this.callHistory[i];
656
+ if (!call)
657
+ continue;
658
+ if (method && call.method !== method)
659
+ continue;
660
+ if (pathPattern) {
661
+ if (typeof pathPattern === "string") {
662
+ if (!call.path.includes(pathPattern))
663
+ continue;
664
+ }
665
+ else {
666
+ if (!pathPattern.test(call.path))
667
+ continue;
668
+ }
669
+ }
670
+ return call;
671
+ }
672
+ return undefined;
673
+ }
674
+ addEnvironmentVariables(environmentId, variables) {
675
+ this.mockData.environmentVariables.set(environmentId, variables);
676
+ }
677
+ setRuntimeLogs(environmentId, logs) {
678
+ this.mockData.runtimeLogs.set(environmentId, logs);
679
+ this.mockData.runtimeLogPages.delete(environmentId);
680
+ }
681
+ setRuntimeLogPages(environmentId, pages) {
682
+ this.mockData.runtimeLogPages.set(environmentId, pages);
683
+ this.mockData.runtimeLogs.delete(environmentId);
684
+ }
685
+ setPublishedServer(projectId, domain, server) {
686
+ this.mockData.publishedServers.set(`${projectId}:${domain}`, server);
687
+ }
688
+ addDeployments(deployments) {
689
+ for (const deployment of deployments) {
690
+ this.mockData.deployments.set(deployment.id, {
691
+ ...deployment,
692
+ deploymentPageUrl: null,
693
+ });
694
+ }
695
+ }
696
+ setDeploymentLogPages(deploymentId, pages) {
697
+ this.mockData.deploymentLogPages.set(deploymentId, pages);
698
+ this.mockData.deploymentLogCallCounts.set(deploymentId, 0);
699
+ }
700
+ addProject(project) {
701
+ this.mockData.projects.set(project.id, project);
702
+ if (project.productionEnvironment) {
703
+ const env = {
704
+ id: project.productionEnvironment.id,
705
+ name: project.productionEnvironment.name,
706
+ sourceBranch: null,
707
+ mcpServerUrl: project.productionEnvironment.mcpServerUrl,
708
+ domains: [project.productionEnvironment.mcpServerUrl],
709
+ createdAt: new Date(),
710
+ projectId: project.id,
711
+ };
712
+ this.mockData.environments.set(env.id, env);
713
+ }
714
+ for (const env of project.environments) {
715
+ const fullEnv = {
716
+ id: env.id,
717
+ name: env.name,
718
+ sourceBranch: env.sourceBranch,
719
+ mcpServerUrl: env.mcpServerUrl,
720
+ domains: [env.mcpServerUrl],
721
+ createdAt: env.createdAt,
722
+ projectId: project.id,
723
+ };
724
+ this.mockData.environments.set(env.id, fullEnv);
725
+ }
726
+ }
727
+ }
728
+ //# sourceMappingURL=mock-server.js.map