alpic 0.0.0-dev.ff063bb → 0.0.0-dev.ff4302e

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