@mintmcp/hosted-cli 0.0.17 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.d.ts CHANGED
@@ -2,6 +2,10 @@ import z from "zod";
2
2
  export declare const HOSTED_ID_PREFIX: "hosted-";
3
3
  export declare const HostedIdSchema: z.ZodBranded<z.ZodEffects<z.ZodString, string, string>, "HostedId">;
4
4
  export type HostedId = z.infer<typeof HostedIdSchema>;
5
+ export declare const GatewayIdSchema: z.ZodString;
6
+ export type GatewayId = z.infer<typeof GatewayIdSchema>;
7
+ export declare const ManagedImageTagSchema: z.ZodString;
8
+ export type ManagedImageTag = z.infer<typeof ManagedImageTagSchema>;
5
9
  export declare const EnvUpdateValueSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
6
10
  type: z.ZodLiteral<"copyPreviousValue">;
7
11
  fromName: z.ZodString;
@@ -45,7 +49,7 @@ export type HostedTransport = z.infer<typeof HostedTransportSchema>;
45
49
  export declare const UserConfigUpdateSchema: z.ZodObject<{
46
50
  userGivenName: z.ZodString;
47
51
  image: z.ZodDefault<z.ZodString>;
48
- command: z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>;
52
+ command: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodArray<z.ZodString, "many">]>>;
49
53
  transport: z.ZodDefault<z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
50
54
  type: z.ZodLiteral<"http">;
51
55
  path: z.ZodString;
@@ -115,7 +119,6 @@ export declare const UserConfigUpdateSchema: z.ZodObject<{
115
119
  }, "strip", z.ZodTypeAny, {
116
120
  userGivenName: string;
117
121
  image: string;
118
- command: string | string[];
119
122
  transport: {
120
123
  path: string;
121
124
  type: "http";
@@ -137,10 +140,10 @@ export declare const UserConfigUpdateSchema: z.ZodObject<{
137
140
  };
138
141
  name: string;
139
142
  }[];
143
+ command?: string | string[] | undefined;
140
144
  secretDataZipGcsPath?: string | undefined;
141
145
  }, {
142
146
  userGivenName: string;
143
- command: string | string[];
144
147
  replaceEnv: {
145
148
  value: {
146
149
  type: "copyPreviousValue";
@@ -153,6 +156,7 @@ export declare const UserConfigUpdateSchema: z.ZodObject<{
153
156
  name: string;
154
157
  }[];
155
158
  image?: string | undefined;
159
+ command?: string | string[] | undefined;
156
160
  transport?: {
157
161
  path: string;
158
162
  type: "http";
@@ -181,7 +185,6 @@ declare const appRouter: import("@trpc/server").TRPCBuiltRouter<{
181
185
  input: {
182
186
  config: {
183
187
  userGivenName: string;
184
- command: string | string[];
185
188
  replaceEnv: {
186
189
  value: {
187
190
  type: "copyPreviousValue";
@@ -194,6 +197,7 @@ declare const appRouter: import("@trpc/server").TRPCBuiltRouter<{
194
197
  name: string;
195
198
  }[];
196
199
  image?: string | undefined;
200
+ command?: string | string[] | undefined;
197
201
  transport?: {
198
202
  path: string;
199
203
  type: "http";
@@ -209,6 +213,7 @@ declare const appRouter: import("@trpc/server").TRPCBuiltRouter<{
209
213
  };
210
214
  output: {
211
215
  hostedId: string & z.BRAND<"HostedId">;
216
+ gatewayId: string;
212
217
  };
213
218
  meta: object;
214
219
  }>;
@@ -217,6 +222,75 @@ declare const appRouter: import("@trpc/server").TRPCBuiltRouter<{
217
222
  hostedId: string;
218
223
  update: {
219
224
  userGivenName?: string | undefined;
225
+ image?: string | undefined;
226
+ command?: string | string[] | null | undefined;
227
+ transport?: {
228
+ path: string;
229
+ type: "http";
230
+ } | {
231
+ type: "stdio";
232
+ } | undefined;
233
+ secretDataZipGcsPath?: string | undefined;
234
+ };
235
+ };
236
+ output: {
237
+ hostedId: string & z.BRAND<"HostedId">;
238
+ gatewayId?: string | undefined;
239
+ };
240
+ meta: object;
241
+ }>;
242
+ createRegistryPushSession: import("@trpc/server").TRPCMutationProcedure<{
243
+ input: {
244
+ hostedId: string;
245
+ };
246
+ output: {
247
+ registryHost: string;
248
+ repository: string;
249
+ username: string;
250
+ password: string;
251
+ imageTag: string;
252
+ finalizeToken: string;
253
+ };
254
+ meta: object;
255
+ }>;
256
+ createRegistryPushSessionForCreate: import("@trpc/server").TRPCMutationProcedure<{
257
+ input: {};
258
+ output: {
259
+ registryHost: string;
260
+ repository: string;
261
+ username: string;
262
+ password: string;
263
+ imageTag: string;
264
+ finalizeToken: string;
265
+ };
266
+ meta: object;
267
+ }>;
268
+ finalizeRegistryPush: import("@trpc/server").TRPCMutationProcedure<{
269
+ input: {
270
+ hostedId: string;
271
+ finalizeToken: string;
272
+ };
273
+ output: {
274
+ hostedId: string & z.BRAND<"HostedId">;
275
+ gatewayId?: string | undefined;
276
+ };
277
+ meta: object;
278
+ }>;
279
+ finalizeRegistryPushCreate: import("@trpc/server").TRPCMutationProcedure<{
280
+ input: {
281
+ config: {
282
+ userGivenName: string;
283
+ replaceEnv: {
284
+ value: {
285
+ type: "copyPreviousValue";
286
+ fromName: string;
287
+ } | {
288
+ value: string;
289
+ type: "set";
290
+ isSecret: boolean;
291
+ };
292
+ name: string;
293
+ }[];
220
294
  command?: string | string[] | undefined;
221
295
  transport?: {
222
296
  path: string;
@@ -224,10 +298,18 @@ declare const appRouter: import("@trpc/server").TRPCBuiltRouter<{
224
298
  } | {
225
299
  type: "stdio";
226
300
  } | undefined;
301
+ cpu?: number | undefined;
302
+ memoryMiB?: number | undefined;
303
+ urlPath?: string | undefined;
227
304
  secretDataZipGcsPath?: string | undefined;
305
+ startupProbe?: "startupProbeOn" | "startupProbeOff" | undefined;
228
306
  };
307
+ finalizeToken: string;
308
+ };
309
+ output: {
310
+ hostedId: string & z.BRAND<"HostedId">;
311
+ gatewayId: string;
229
312
  };
230
- output: unknown;
231
313
  meta: object;
232
314
  }>;
233
315
  makeSignedUploadUrl: import("@trpc/server").TRPCMutationProcedure<{
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAQA,OAAO,CAAC,MAAM,KAAK,CAAC;AAKpB,eAAO,MAAM,gBAAgB,EAAG,SAAkB,CAAC;AACnD,eAAO,MAAM,cAAc,qEAOL,CAAC;AACvB,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;IAU/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;KAWQ,CAAC;AAC3C,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmBjC,CAAC;AAKH,QAAA,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCb,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAQA,OAAO,CAAC,MAAM,KAAK,CAAC;AAKpB,eAAO,MAAM,gBAAgB,EAAG,SAAkB,CAAC;AACnD,eAAO,MAAM,cAAc,qEAOL,CAAC;AACvB,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAEtD,eAAO,MAAM,eAAe,aAAoB,CAAC;AACjD,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAExD,eAAO,MAAM,qBAAqB,aAA2C,CAAC;AAC9E,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;IAU/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAElE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;KAWQ,CAAC;AAC3C,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmBjC,CAAC;AAKH,QAAA,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkHb,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC"}
package/dist/api.js CHANGED
@@ -13,6 +13,8 @@ export const HostedIdSchema = z
13
13
  .refine((v) => v.startsWith(HOSTED_ID_PREFIX) &&
14
14
  UUID_RE.test(v.substring(HOSTED_ID_PREFIX.length)))
15
15
  .brand();
16
+ export const GatewayIdSchema = z.string().min(1);
17
+ export const ManagedImageTagSchema = z.string().regex(/^mi_[0-9A-Za-z]{22}$/);
16
18
  export const EnvUpdateValueSchema = z.discriminatedUnion("type", [
17
19
  z.object({
18
20
  type: z.literal("copyPreviousValue"),
@@ -41,7 +43,7 @@ export const UserConfigUpdateSchema = z.object({
41
43
  image: z
42
44
  .string()
43
45
  .default("nikolaik/python-nodejs@sha256:1dcaf296688723fbe79c400e1dda743c8e8a8b2812ef4b0af70779914a9cec3c"),
44
- command: z.union([z.string(), z.array(z.string())]),
46
+ command: z.union([z.string(), z.array(z.string())]).optional(),
45
47
  transport: HostedTransportSchema,
46
48
  cpu: z.number().default(1),
47
49
  memoryMiB: z.number().default(4096),
@@ -58,7 +60,7 @@ const appRouter = router({
58
60
  mcpHost: router({
59
61
  createServer: procedure
60
62
  .input(z.object({ config: UserConfigUpdateSchema }))
61
- .output(z.object({ hostedId: HostedIdSchema }))
63
+ .output(z.object({ hostedId: HostedIdSchema, gatewayId: GatewayIdSchema }))
62
64
  .mutation(() => {
63
65
  throw new Error("stub");
64
66
  }),
@@ -67,12 +69,71 @@ const appRouter = router({
67
69
  hostedId: HostedIdSchema,
68
70
  update: z.object({
69
71
  userGivenName: z.string().optional(),
70
- command: z.union([z.string(), z.array(z.string())]).optional(),
72
+ image: z.string().optional(),
73
+ command: z
74
+ .union([z.string(), z.array(z.string())])
75
+ .optional()
76
+ .nullable(),
71
77
  transport: HostedTransportSchema.optional(),
72
78
  secretDataZipGcsPath: z.string().optional(),
73
79
  }),
74
80
  }))
75
- .output(z.unknown())
81
+ .output(z.object({
82
+ hostedId: HostedIdSchema,
83
+ gatewayId: GatewayIdSchema.optional(),
84
+ }))
85
+ .mutation(() => {
86
+ throw new Error("stub");
87
+ }),
88
+ createRegistryPushSession: procedure
89
+ .input(z.object({
90
+ hostedId: HostedIdSchema,
91
+ }))
92
+ .output(z.object({
93
+ registryHost: z.string(),
94
+ repository: z.string(),
95
+ username: z.string(),
96
+ password: z.string(),
97
+ imageTag: ManagedImageTagSchema,
98
+ finalizeToken: z.string(),
99
+ }))
100
+ .mutation(() => {
101
+ throw new Error("stub");
102
+ }),
103
+ createRegistryPushSessionForCreate: procedure
104
+ .input(z.object({}))
105
+ .output(z.object({
106
+ registryHost: z.string(),
107
+ repository: z.string(),
108
+ username: z.string(),
109
+ password: z.string(),
110
+ imageTag: ManagedImageTagSchema,
111
+ finalizeToken: z.string(),
112
+ }))
113
+ .mutation(() => {
114
+ throw new Error("stub");
115
+ }),
116
+ finalizeRegistryPush: procedure
117
+ .input(z.object({
118
+ hostedId: HostedIdSchema,
119
+ finalizeToken: z.string(),
120
+ }))
121
+ .output(z.object({
122
+ hostedId: HostedIdSchema,
123
+ gatewayId: GatewayIdSchema.optional(),
124
+ }))
125
+ .mutation(() => {
126
+ throw new Error("stub");
127
+ }),
128
+ finalizeRegistryPushCreate: procedure
129
+ .input(z.object({
130
+ finalizeToken: z.string(),
131
+ config: UserConfigUpdateSchema.omit({ image: true }),
132
+ }))
133
+ .output(z.object({
134
+ hostedId: HostedIdSchema,
135
+ gatewayId: GatewayIdSchema,
136
+ }))
76
137
  .mutation(() => {
77
138
  throw new Error("stub");
78
139
  }),
package/dist/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import { execFileSync, spawn } from "node:child_process";
2
+ export interface BuildOptions {
3
+ dockerfile?: string;
4
+ context?: string;
5
+ buildArgs?: string[];
6
+ target?: string;
7
+ platform?: string;
8
+ imageRef: string;
9
+ }
10
+ export interface BuildResult {
11
+ imageRef: string;
12
+ platform?: string;
13
+ sizeBytes: number;
14
+ sizeHuman: string;
15
+ }
16
+ export interface SmokeTestOptions {
17
+ imageRef: string;
18
+ probePath?: string;
19
+ probeTimeoutMs?: number;
20
+ env?: string[];
21
+ envFile?: string;
22
+ }
23
+ export interface SmokeTestResult {
24
+ containerName: string;
25
+ imageRef: string;
26
+ url: string;
27
+ }
28
+ interface ContainerBuilderDeps {
29
+ execFileSync: typeof execFileSync;
30
+ spawn: typeof spawn;
31
+ fetch: typeof fetch;
32
+ getAvailablePort: () => Promise<number>;
33
+ sleep: (ms: number) => Promise<void>;
34
+ now: () => number;
35
+ }
36
+ export declare function defaultBuildPlatform(): string;
37
+ export declare function defaultLocalTestImageRef(now?: number): string;
38
+ export declare function ensureDockerAvailable(deps?: ContainerBuilderDeps): void;
39
+ export declare function ensureDockerBuildxAvailable(deps?: ContainerBuilderDeps): void;
40
+ export declare function buildImage(options: BuildOptions, deps?: ContainerBuilderDeps): BuildResult;
41
+ export declare function pushImage(imageRef: string, deps?: ContainerBuilderDeps): void;
42
+ export declare function loginToRegistry(registryHost: string, username: string, password: string, deps?: ContainerBuilderDeps): void;
43
+ export declare function tagImage(sourceImageRef: string, targetImageRef: string, deps?: ContainerBuilderDeps): void;
44
+ export declare function ensureImageAvailableLocally(imageRef: string, deps?: ContainerBuilderDeps): void;
45
+ export declare function assertImageSupportsPlatform(imageRef: string, platform: string, deps?: ContainerBuilderDeps): void;
46
+ export declare function smokeTestImage(options: SmokeTestOptions, deps?: ContainerBuilderDeps): Promise<SmokeTestResult>;
47
+ export {};
48
+ //# sourceMappingURL=containerBuilder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"containerBuilder.d.ts","sourceRoot":"","sources":["../src/containerBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,YAAY,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAQ5E,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb;AAYD,UAAU,oBAAoB;IAC5B,YAAY,EAAE,OAAO,YAAY,CAAC;IAClC,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,gBAAgB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,GAAG,EAAE,MAAM,MAAM,CAAC;CACnB;AAmBD,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,wBAAwB,CAAC,GAAG,SAAoB,GAAG,MAAM,CAExE;AAED,wBAAgB,qBAAqB,CACnC,IAAI,GAAE,oBAAkC,GACvC,IAAI,CAQN;AAED,wBAAgB,2BAA2B,CACzC,IAAI,GAAE,oBAAkC,GACvC,IAAI,CAQN;AAED,wBAAgB,UAAU,CACxB,OAAO,EAAE,YAAY,EACrB,IAAI,GAAE,oBAAkC,GACvC,WAAW,CA+Db;AAED,wBAAgB,SAAS,CACvB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,oBAAkC,GACvC,IAAI,CAIN;AAED,wBAAgB,eAAe,CAC7B,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,oBAAkC,GACvC,IAAI,CAUN;AAED,wBAAgB,QAAQ,CACtB,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EACtB,IAAI,GAAE,oBAAkC,GACvC,IAAI,CAIN;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,oBAAkC,GACvC,IAAI,CAUN;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,oBAAkC,GACvC,IAAI,CAYN;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,gBAAgB,EACzB,IAAI,GAAE,oBAAkC,GACvC,OAAO,CAAC,eAAe,CAAC,CA4C1B"}
@@ -0,0 +1,301 @@
1
+ import { execFileSync, spawn } from "node:child_process";
2
+ import { randomUUID } from "node:crypto";
3
+ import net from "node:net";
4
+ import { setTimeout as delay } from "node:timers/promises";
5
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
6
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
7
+ const defaultDeps = {
8
+ execFileSync,
9
+ spawn,
10
+ fetch,
11
+ getAvailablePort,
12
+ sleep: (ms) => delay(ms),
13
+ now: () => Date.now(),
14
+ };
15
+ const SIZE_WARN_BYTES = 250 * 1024 * 1024;
16
+ const SIZE_REJECT_BYTES = 1024 * 1024 * 1024;
17
+ const DEFAULT_BUILD_PLATFORM = "linux/amd64";
18
+ const DEFAULT_PROBE_PATH = "/mcp";
19
+ const DEFAULT_PROBE_TIMEOUT_MS = 30_000;
20
+ const LOCAL_TEST_IMAGE_PREFIX = "mintmcp-local-test";
21
+ const LOCAL_TEST_POLL_INTERVAL_MS = 500;
22
+ export function defaultBuildPlatform() {
23
+ return DEFAULT_BUILD_PLATFORM;
24
+ }
25
+ export function defaultLocalTestImageRef(now = defaultDeps.now()) {
26
+ return `${LOCAL_TEST_IMAGE_PREFIX}:${now}`;
27
+ }
28
+ export function ensureDockerAvailable(deps = defaultDeps) {
29
+ try {
30
+ deps.execFileSync("docker", ["info"], { stdio: "ignore" });
31
+ }
32
+ catch {
33
+ throw new Error("Docker is not running or not installed. Install Docker Desktop or start the Docker daemon.");
34
+ }
35
+ }
36
+ export function ensureDockerBuildxAvailable(deps = defaultDeps) {
37
+ try {
38
+ deps.execFileSync("docker", ["buildx", "version"], { stdio: "ignore" });
39
+ }
40
+ catch {
41
+ throw new Error("Docker Buildx is required. Install a Docker version with buildx support and try again.");
42
+ }
43
+ }
44
+ export function buildImage(options, deps = defaultDeps) {
45
+ const { dockerfile = "Dockerfile", context = ".", buildArgs = [], target, platform, imageRef, } = options;
46
+ if (platform != undefined) {
47
+ assertSinglePlatform(platform);
48
+ }
49
+ const args = [
50
+ "buildx",
51
+ "build",
52
+ "--load",
53
+ ...(platform != undefined ? ["--platform", platform] : []),
54
+ "-f",
55
+ dockerfile,
56
+ "-t",
57
+ imageRef,
58
+ ...(target ? ["--target", target] : []),
59
+ ...buildArgs.flatMap((arg) => ["--build-arg", arg]),
60
+ context,
61
+ ];
62
+ console.log(`Building image: docker ${args.join(" ")}`);
63
+ deps.execFileSync("docker", args, { stdio: "inherit" });
64
+ const inspectOutput = deps
65
+ .execFileSync("docker", ["image", "inspect", imageRef, "--format", "{{.Size}}"], { encoding: "utf8" })
66
+ .trim();
67
+ const sizeBytes = Number.parseInt(inspectOutput, 10);
68
+ const sizeHuman = formatBytes(sizeBytes);
69
+ if (!Number.isFinite(sizeBytes)) {
70
+ throw new Error(`Could not determine built image size for ${imageRef}.`);
71
+ }
72
+ if (sizeBytes > SIZE_REJECT_BYTES) {
73
+ throw new Error(`Image size ${sizeHuman} exceeds maximum of 1 GB. Reduce layers or use a smaller base image.`);
74
+ }
75
+ if (sizeBytes > SIZE_WARN_BYTES) {
76
+ console.warn(`Image size ${sizeHuman} exceeds 250 MB. Consider optimizing.`);
77
+ }
78
+ else {
79
+ console.log(`Image size: ${sizeHuman}`);
80
+ }
81
+ return {
82
+ imageRef,
83
+ ...(platform != undefined ? { platform } : {}),
84
+ sizeBytes,
85
+ sizeHuman,
86
+ };
87
+ }
88
+ export function pushImage(imageRef, deps = defaultDeps) {
89
+ console.log(`Pushing image: ${imageRef}`);
90
+ deps.execFileSync("docker", ["push", imageRef], { stdio: "inherit" });
91
+ console.log("Image pushed.");
92
+ }
93
+ export function loginToRegistry(registryHost, username, password, deps = defaultDeps) {
94
+ console.log(`Logging in to registry: ${registryHost}`);
95
+ deps.execFileSync("docker", ["login", registryHost, "-u", username, "--password-stdin"], {
96
+ input: password,
97
+ stdio: "pipe",
98
+ });
99
+ }
100
+ export function tagImage(sourceImageRef, targetImageRef, deps = defaultDeps) {
101
+ deps.execFileSync("docker", ["tag", sourceImageRef, targetImageRef], {
102
+ stdio: "inherit",
103
+ });
104
+ }
105
+ export function ensureImageAvailableLocally(imageRef, deps = defaultDeps) {
106
+ try {
107
+ deps.execFileSync("docker", ["image", "inspect", imageRef], {
108
+ stdio: "ignore",
109
+ });
110
+ return;
111
+ }
112
+ catch {
113
+ console.log(`Pulling image: ${imageRef}`);
114
+ deps.execFileSync("docker", ["pull", imageRef], { stdio: "inherit" });
115
+ }
116
+ }
117
+ export function assertImageSupportsPlatform(imageRef, platform, deps = defaultDeps) {
118
+ assertSinglePlatform(platform);
119
+ const manifestOutput = deps.execFileSync("docker", ["manifest", "inspect", imageRef, "-v"], { encoding: "utf8" });
120
+ if (!manifestSupportsPlatform(manifestOutput, platform)) {
121
+ throw new Error(`Pushed image ${imageRef} does not advertise support for ${platform}. Build and push a compatible image before deploying to the hosted runtime.`);
122
+ }
123
+ }
124
+ export async function smokeTestImage(options, deps = defaultDeps) {
125
+ const probePath = options.probePath ?? DEFAULT_PROBE_PATH;
126
+ const probeTimeoutMs = options.probeTimeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
127
+ const hostPort = await deps.getAvailablePort();
128
+ const containerName = `${LOCAL_TEST_IMAGE_PREFIX}-${randomUUID().slice(0, 12)}`;
129
+ const url = `http://127.0.0.1:${hostPort}${probePath}`;
130
+ console.log(`Running image locally: ${options.imageRef}`);
131
+ const container = deps.spawn("docker", [
132
+ "run",
133
+ "--rm",
134
+ "--name",
135
+ containerName,
136
+ "-p",
137
+ `${hostPort}:${hostPort}`,
138
+ "-e",
139
+ `PORT=${hostPort}`,
140
+ ...(options.envFile ? ["--env-file", options.envFile] : []),
141
+ ...(options.env ?? []).flatMap((entry) => ["-e", entry]),
142
+ options.imageRef,
143
+ ], { stdio: ["ignore", "pipe", "pipe"] });
144
+ const { logs, exitInfo } = captureContainerLogs(container);
145
+ try {
146
+ await mcpSmokeTest({ url, probeTimeoutMs }, {
147
+ fetch: deps.fetch,
148
+ sleep: deps.sleep,
149
+ getExitInfo: () => exitInfo.value,
150
+ });
151
+ return { containerName, imageRef: options.imageRef, url };
152
+ }
153
+ catch (error) {
154
+ const message = formatSmokeTestFailureMessage(error, logs.join(""));
155
+ throw new Error(message);
156
+ }
157
+ finally {
158
+ await stopContainer(containerName, deps);
159
+ }
160
+ }
161
+ function assertSinglePlatform(platform) {
162
+ if (platform.includes(",")) {
163
+ throw new Error("Multiple platforms are not supported yet. Pass a single platform such as linux/amd64.");
164
+ }
165
+ }
166
+ function formatBytes(bytes) {
167
+ if (bytes < 1024) {
168
+ return `${bytes} B`;
169
+ }
170
+ if (bytes < 1024 * 1024) {
171
+ return `${(bytes / 1024).toFixed(1)} KB`;
172
+ }
173
+ if (bytes < 1024 * 1024 * 1024) {
174
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
175
+ }
176
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
177
+ }
178
+ function manifestSupportsPlatform(rawManifest, platform) {
179
+ const parsed = parsePlatform(platform);
180
+ const manifest = JSON.parse(rawManifest);
181
+ if (!manifest) {
182
+ return false;
183
+ }
184
+ if (platformMatches(manifest.Descriptor?.platform, parsed)) {
185
+ return true;
186
+ }
187
+ if (manifest.os != undefined &&
188
+ manifest.architecture != undefined &&
189
+ platformMatches({
190
+ os: manifest.os,
191
+ architecture: manifest.architecture,
192
+ ...(manifest.variant != undefined ? { variant: manifest.variant } : {}),
193
+ }, parsed)) {
194
+ return true;
195
+ }
196
+ return (manifest.manifests?.some((entry) => platformMatches(entry.platform, parsed)) ?? false);
197
+ }
198
+ function parsePlatform(platform) {
199
+ const [os, architecture, variant, ...rest] = platform.split("/");
200
+ if (!os || !architecture || rest.length > 0) {
201
+ throw new Error(`Unsupported platform "${platform}". Use a single platform like linux/amd64.`);
202
+ }
203
+ return { os, architecture, ...(variant ? { variant } : {}) };
204
+ }
205
+ function platformMatches(actual, expected) {
206
+ return (actual?.os === expected.os &&
207
+ actual?.architecture === expected.architecture &&
208
+ (expected.variant == undefined || actual?.variant === expected.variant));
209
+ }
210
+ function captureContainerLogs(container) {
211
+ const logs = [];
212
+ const exitInfo = {};
213
+ for (const stream of [container.stdout, container.stderr]) {
214
+ stream?.on("data", (chunk) => {
215
+ logs.push(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
216
+ });
217
+ }
218
+ container.on("exit", (code, signal) => {
219
+ exitInfo.value = { code, signal };
220
+ });
221
+ return { logs, exitInfo };
222
+ }
223
+ async function mcpSmokeTest(params, deps) {
224
+ const deadline = Date.now() + params.probeTimeoutMs;
225
+ while (Date.now() < deadline) {
226
+ const exitInfo = deps.getExitInfo();
227
+ if (exitInfo) {
228
+ throw new Error(`Container exited before responding to the MCP probe (code=${String(exitInfo.code)}, signal=${String(exitInfo.signal)}).`);
229
+ }
230
+ const client = new Client({
231
+ name: "MintMCP Local Probe",
232
+ version: "1.0.0",
233
+ });
234
+ const transport = new StreamableHTTPClientTransport(new URL(params.url), {
235
+ fetch: deps.fetch,
236
+ });
237
+ try {
238
+ await client.connect(transport);
239
+ console.log(`Local MCP initialize succeeded: ${params.url}`);
240
+ const toolsResult = await client.listTools();
241
+ console.log(`Local tools/list succeeded: ${toolsResult.tools.length} tool(s) found`);
242
+ await client.close();
243
+ return;
244
+ }
245
+ catch {
246
+ try {
247
+ await client.close();
248
+ }
249
+ catch {
250
+ // Ignore close errors during retry
251
+ }
252
+ const exitInfo = deps.getExitInfo();
253
+ if (exitInfo) {
254
+ throw new Error(`Container exited before responding to the MCP probe (code=${String(exitInfo.code)}, signal=${String(exitInfo.signal)}).`);
255
+ }
256
+ await deps.sleep(LOCAL_TEST_POLL_INTERVAL_MS);
257
+ }
258
+ }
259
+ throw new Error(`Timed out waiting ${params.probeTimeoutMs}ms for the local MCP probe to succeed.`);
260
+ }
261
+ async function stopContainer(containerName, deps) {
262
+ try {
263
+ deps.execFileSync("docker", ["rm", "-f", containerName], {
264
+ stdio: "ignore",
265
+ });
266
+ }
267
+ catch {
268
+ // Ignore cleanup failures: the container may have already exited.
269
+ }
270
+ }
271
+ async function getAvailablePort() {
272
+ return await new Promise((resolve, reject) => {
273
+ const server = net.createServer();
274
+ server.unref();
275
+ server.on("error", reject);
276
+ server.listen(0, "127.0.0.1", () => {
277
+ const address = server.address();
278
+ if (address == null || typeof address === "string") {
279
+ server.close(() => reject(new Error("Could not determine a free port")));
280
+ return;
281
+ }
282
+ const { port } = address;
283
+ server.close((error) => {
284
+ if (error) {
285
+ reject(error);
286
+ return;
287
+ }
288
+ resolve(port);
289
+ });
290
+ });
291
+ });
292
+ }
293
+ function formatSmokeTestFailureMessage(error, logs) {
294
+ const message = error instanceof Error ? error.message : String(error);
295
+ const trimmedLogs = logs.trim();
296
+ if (trimmedLogs.length === 0) {
297
+ return `Local image smoke test failed: ${message}`;
298
+ }
299
+ return `Local image smoke test failed: ${message}\n\nContainer logs:\n${trimmedLogs}`;
300
+ }
301
+ //# sourceMappingURL=containerBuilder.js.map