alpic 0.0.0-dev.ff7eedf → 0.0.0-dev.ffd67d5

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