@prisma/compute-sdk 0.24.0 → 0.26.0

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 (46) hide show
  1. package/dist/apply-migrations.d.ts +61 -0
  2. package/dist/apply-migrations.d.ts.map +1 -0
  3. package/dist/apply-migrations.js +314 -0
  4. package/dist/apply-migrations.js.map +1 -0
  5. package/dist/astro-build.d.ts.map +1 -1
  6. package/dist/astro-build.js +2 -1
  7. package/dist/astro-build.js.map +1 -1
  8. package/dist/bun-build.d.ts.map +1 -1
  9. package/dist/bun-build.js +2 -0
  10. package/dist/bun-build.js.map +1 -1
  11. package/dist/config/frameworks.d.ts +8 -1
  12. package/dist/config/frameworks.d.ts.map +1 -1
  13. package/dist/config/frameworks.js +28 -0
  14. package/dist/config/frameworks.js.map +1 -1
  15. package/dist/config/index.d.ts +1 -1
  16. package/dist/config/index.d.ts.map +1 -1
  17. package/dist/config/index.js +1 -1
  18. package/dist/config/index.js.map +1 -1
  19. package/dist/detect-schema.d.ts +31 -0
  20. package/dist/detect-schema.d.ts.map +1 -0
  21. package/dist/detect-schema.js +212 -0
  22. package/dist/detect-schema.js.map +1 -0
  23. package/dist/index.d.ts +4 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +2 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/nextjs-build.d.ts.map +1 -1
  28. package/dist/nextjs-build.js +2 -1
  29. package/dist/nextjs-build.js.map +1 -1
  30. package/dist/nuxt-build.d.ts.map +1 -1
  31. package/dist/nuxt-build.js +2 -1
  32. package/dist/nuxt-build.js.map +1 -1
  33. package/dist/tanstack-start-build.d.ts.map +1 -1
  34. package/dist/tanstack-start-build.js +4 -1
  35. package/dist/tanstack-start-build.js.map +1 -1
  36. package/package.json +1 -1
  37. package/src/apply-migrations.ts +454 -0
  38. package/src/astro-build.ts +2 -1
  39. package/src/bun-build.ts +2 -0
  40. package/src/config/frameworks.ts +38 -0
  41. package/src/config/index.ts +1 -0
  42. package/src/detect-schema.ts +384 -0
  43. package/src/index.ts +14 -0
  44. package/src/nextjs-build.ts +2 -1
  45. package/src/nuxt-build.ts +2 -1
  46. package/src/tanstack-start-build.ts +4 -1
@@ -0,0 +1,454 @@
1
+ /**
2
+ * Applies an application's database schema against a database, owning the
3
+ * prisma CLI resolution so every deploy front door (git-push build-runner,
4
+ * `prisma app deploy`) runs migrations the same way.
5
+ *
6
+ * The resolver locates the project's own prisma binary by walking
7
+ * `node_modules` from the schema directory up to the source root, the way
8
+ * Node resolves a dependency. That covers npm, pnpm, yarn, and monorepo
9
+ * layouts where prisma is installed but the flat `node_modules/.bin/prisma`
10
+ * symlink is absent at the app root.
11
+ */
12
+ import { spawn } from "node:child_process";
13
+ import { readFile } from "node:fs/promises";
14
+ import path from "node:path";
15
+ import type { Readable } from "node:stream";
16
+ import { sourceRootLineage } from "./config/source-root.ts";
17
+ import type {
18
+ DetectedSchema,
19
+ MigrationCommand,
20
+ SchemaEngine,
21
+ } from "./detect-schema.ts";
22
+ import { detectAppSchema } from "./detect-schema.ts";
23
+ import { BuildError } from "./errors.ts";
24
+
25
+ export interface ApplyMigrationsOptions {
26
+ /** Application root the build runs in; also the CLI working directory. */
27
+ appPath: string;
28
+ /** Connection used for migrations: the direct/admin database URL. */
29
+ databaseUrl: string;
30
+ /** Auto-detected from `appPath` when omitted. */
31
+ schema?: DetectedSchema;
32
+ /** Extra environment for the CLI child, e.g. a user-set `DIRECT_URL`. */
33
+ env?: Record<string, string>;
34
+ signal?: AbortSignal;
35
+ onLog?: (line: string, stream: "stdout" | "stderr") => void;
36
+ }
37
+
38
+ export type ApplyMigrationsResult =
39
+ | { applied: true; via: MigrationCommand }
40
+ | { applied: false; reason: "no-schema" };
41
+
42
+ /**
43
+ * Last resort for repos that ship a schema with no prisma installed at all.
44
+ * Pinned to the 6.x line: Prisma 7 rejects the classic `url = env(...)`
45
+ * datasource form (P1012), which is exactly the schema shape such repos have.
46
+ * Bump deliberately, never to `latest`.
47
+ */
48
+ export const FALLBACK_PRISMA_CLI_VERSION = "6.19.3";
49
+
50
+ export interface CliLauncher {
51
+ command: string;
52
+ argsPrefix: string[];
53
+ /** Human-readable command prefix used in failure messages. */
54
+ display: string;
55
+ }
56
+
57
+ /**
58
+ * Applies the app's schema and returns how it was applied, or `no-schema`
59
+ * when the app has none. Throws {@link BuildError} on failure: a non-zero
60
+ * CLI exit carries `exited with code N` (a user-fixable error), while an
61
+ * unrunnable launcher does not (an infrastructure error).
62
+ */
63
+ export async function applyMigrations(
64
+ opts: ApplyMigrationsOptions,
65
+ ): Promise<ApplyMigrationsResult> {
66
+ opts.signal?.throwIfAborted();
67
+
68
+ const schema =
69
+ opts.schema ?? (await detectAppSchema(opts.appPath, opts.signal)).schema;
70
+ if (!schema) {
71
+ return { applied: false, reason: "no-schema" };
72
+ }
73
+
74
+ const launchers = await resolveSchemaEngineCli(
75
+ schema,
76
+ opts.appPath,
77
+ opts.signal,
78
+ );
79
+ const relativeSchemaPath =
80
+ path.relative(opts.appPath, schema.path) ||
81
+ defaultSchemaSourcePath(schema.engine);
82
+ const env = {
83
+ ...process.env,
84
+ ...opts.env,
85
+ DATABASE_URL: opts.databaseUrl,
86
+ // Update nags pollute the migration log and failure snippets.
87
+ PRISMA_HIDE_UPDATE_MESSAGE: "1",
88
+ };
89
+
90
+ for (const subcommand of subcommandsFor(
91
+ schema,
92
+ relativeSchemaPath,
93
+ opts.databaseUrl,
94
+ )) {
95
+ await runWithLaunchers({
96
+ launchers,
97
+ subcommand: subcommand.args,
98
+ subcommandDisplay: subcommand.display,
99
+ cwd: opts.appPath,
100
+ env,
101
+ signal: opts.signal,
102
+ onLog: opts.onLog,
103
+ });
104
+ }
105
+
106
+ return { applied: true, via: schema.command };
107
+ }
108
+
109
+ /**
110
+ * Resolves the launcher ladder for a schema's engine: the project's own
111
+ * binary first (run via `node`), then download fallbacks tried in order when
112
+ * the binary is not installed.
113
+ */
114
+ export async function resolveSchemaEngineCli(
115
+ schema: DetectedSchema,
116
+ appPath: string,
117
+ signal?: AbortSignal,
118
+ ): Promise<CliLauncher[]> {
119
+ const startDir = path.dirname(schema.path) || appPath;
120
+
121
+ if (schema.engine === "prisma-next") {
122
+ const localBin = await resolveLocalCliBin(
123
+ startDir,
124
+ "@prisma-next/cli",
125
+ "prisma-next",
126
+ signal,
127
+ );
128
+ if (localBin) {
129
+ return [
130
+ { command: "node", argsPrefix: [localBin], display: "prisma-next" },
131
+ ];
132
+ }
133
+ // `@prisma-next/cli` is not published to npm, so there is no download
134
+ // fallback; `--no-install` keeps today's behaviour when it is missing.
135
+ return [
136
+ {
137
+ command: "npx",
138
+ argsPrefix: ["--no-install", "prisma-next"],
139
+ display: "npx --no-install prisma-next",
140
+ },
141
+ ];
142
+ }
143
+
144
+ const localBin = await resolveLocalCliBin(
145
+ startDir,
146
+ "prisma",
147
+ "prisma",
148
+ signal,
149
+ );
150
+ if (localBin) {
151
+ return [{ command: "node", argsPrefix: [localBin], display: "prisma" }];
152
+ }
153
+
154
+ const pinned =
155
+ (await readResolvedPrismaVersion(startDir, signal)) ??
156
+ FALLBACK_PRISMA_CLI_VERSION;
157
+ return [
158
+ {
159
+ command: "npx",
160
+ argsPrefix: ["--yes", "--package", `prisma@${pinned}`, "prisma"],
161
+ display: `npx prisma@${pinned}`,
162
+ },
163
+ {
164
+ command: "bunx",
165
+ argsPrefix: [`prisma@${pinned}`],
166
+ display: `bunx prisma@${pinned}`,
167
+ },
168
+ ];
169
+ }
170
+
171
+ async function resolveLocalCliBin(
172
+ startDir: string,
173
+ packageName: string,
174
+ binName: string,
175
+ signal?: AbortSignal,
176
+ ): Promise<string | null> {
177
+ for (const dir of await sourceRootLineage(startDir, signal)) {
178
+ const packageDir = path.join(dir, "node_modules", packageName);
179
+ const bin = await readBinFromPackageJson(
180
+ path.join(packageDir, "package.json"),
181
+ binName,
182
+ signal,
183
+ );
184
+ if (bin) {
185
+ return path.resolve(packageDir, bin);
186
+ }
187
+ }
188
+ return null;
189
+ }
190
+
191
+ async function readBinFromPackageJson(
192
+ packageJsonPath: string,
193
+ binName: string,
194
+ signal?: AbortSignal,
195
+ ): Promise<string | null> {
196
+ let raw: string;
197
+ try {
198
+ raw = await readFile(packageJsonPath, { encoding: "utf8", signal });
199
+ } catch (error) {
200
+ if (signal?.aborted) throw error;
201
+ return null;
202
+ }
203
+
204
+ let parsed: unknown;
205
+ try {
206
+ parsed = JSON.parse(raw);
207
+ } catch {
208
+ return null;
209
+ }
210
+
211
+ const bin = (parsed as { bin?: unknown }).bin;
212
+ if (typeof bin === "string") {
213
+ return bin;
214
+ }
215
+ if (bin && typeof bin === "object") {
216
+ const entry = (bin as Record<string, unknown>)[binName];
217
+ return typeof entry === "string" ? entry : null;
218
+ }
219
+ return null;
220
+ }
221
+
222
+ async function readResolvedPrismaVersion(
223
+ startDir: string,
224
+ signal?: AbortSignal,
225
+ ): Promise<string | null> {
226
+ for (const dir of await sourceRootLineage(startDir, signal)) {
227
+ const version = await readPackageVersion(
228
+ path.join(dir, "node_modules", "@prisma", "client", "package.json"),
229
+ signal,
230
+ );
231
+ if (version) {
232
+ return version;
233
+ }
234
+ }
235
+ return null;
236
+ }
237
+
238
+ async function readPackageVersion(
239
+ packageJsonPath: string,
240
+ signal?: AbortSignal,
241
+ ): Promise<string | null> {
242
+ let raw: string;
243
+ try {
244
+ raw = await readFile(packageJsonPath, { encoding: "utf8", signal });
245
+ } catch (error) {
246
+ if (signal?.aborted) throw error;
247
+ return null;
248
+ }
249
+
250
+ try {
251
+ const parsed: unknown = JSON.parse(raw);
252
+ const version = (parsed as { version?: unknown }).version;
253
+ return typeof version === "string" && version.length > 0 ? version : null;
254
+ } catch {
255
+ return null;
256
+ }
257
+ }
258
+
259
+ function subcommandsFor(
260
+ schema: DetectedSchema,
261
+ relativeSchemaPath: string,
262
+ databaseUrl: string,
263
+ ): Array<{ args: string[]; display: string }> {
264
+ switch (schema.command) {
265
+ case "migrate-deploy":
266
+ return [
267
+ {
268
+ args: ["migrate", "deploy", "--schema", relativeSchemaPath],
269
+ display: "migrate deploy",
270
+ },
271
+ ];
272
+ case "db-push":
273
+ return [
274
+ {
275
+ args: ["db", "push", "--schema", relativeSchemaPath],
276
+ display: "db push",
277
+ },
278
+ ];
279
+ case "prisma-next-init":
280
+ return [
281
+ {
282
+ args: ["contract", "emit", "--config", relativeSchemaPath],
283
+ display: "contract emit",
284
+ },
285
+ {
286
+ args: [
287
+ "db",
288
+ "init",
289
+ "--config",
290
+ relativeSchemaPath,
291
+ "--db",
292
+ databaseUrl,
293
+ ],
294
+ display: "db init",
295
+ },
296
+ ];
297
+ default: {
298
+ const exhaustive: never = schema.command;
299
+ throw new BuildError({
300
+ message: `Unknown migration command: ${String(exhaustive)}`,
301
+ });
302
+ }
303
+ }
304
+ }
305
+
306
+ function defaultSchemaSourcePath(engine: SchemaEngine): string {
307
+ return engine === "prisma-next" ? "prisma-next.config.ts" : "schema.prisma";
308
+ }
309
+
310
+ type LauncherOutcome =
311
+ | { kind: "ok" }
312
+ | { kind: "unavailable" }
313
+ | { kind: "failed"; code: number };
314
+
315
+ /**
316
+ * Runs `subcommand` against the launcher ladder, falling through to the next
317
+ * launcher when one cannot run (spawn ENOENT or exit 127) and throwing on the
318
+ * first launcher that runs the tool to a real non-zero exit.
319
+ */
320
+ export async function runWithLaunchers(opts: {
321
+ launchers: CliLauncher[];
322
+ subcommand: string[];
323
+ subcommandDisplay: string;
324
+ cwd: string;
325
+ env: NodeJS.ProcessEnv;
326
+ signal?: AbortSignal;
327
+ onLog?: (line: string, stream: "stdout" | "stderr") => void;
328
+ }): Promise<void> {
329
+ for (const launcher of opts.launchers) {
330
+ opts.signal?.throwIfAborted();
331
+ const outcome = await runOnce(launcher, opts);
332
+ if (outcome.kind === "ok") {
333
+ return;
334
+ }
335
+ if (outcome.kind === "failed") {
336
+ throw new BuildError({
337
+ message: `${launcher.display} ${opts.subcommandDisplay} exited with code ${outcome.code}`,
338
+ });
339
+ }
340
+ }
341
+
342
+ throw new BuildError({
343
+ message: `Could not run ${opts.subcommandDisplay}: no prisma launcher was runnable (tried ${opts.launchers
344
+ .map((launcher) => launcher.display)
345
+ .join(", ")})`,
346
+ });
347
+ }
348
+
349
+ function runOnce(
350
+ launcher: CliLauncher,
351
+ opts: {
352
+ subcommand: string[];
353
+ cwd: string;
354
+ env: NodeJS.ProcessEnv;
355
+ signal?: AbortSignal;
356
+ onLog?: (line: string, stream: "stdout" | "stderr") => void;
357
+ },
358
+ ): Promise<LauncherOutcome> {
359
+ return new Promise<LauncherOutcome>((resolve, reject) => {
360
+ const child = spawn(
361
+ launcher.command,
362
+ [...launcher.argsPrefix, ...opts.subcommand],
363
+ {
364
+ cwd: opts.cwd,
365
+ env: opts.env,
366
+ signal: opts.signal,
367
+ stdio: ["ignore", "pipe", "pipe"],
368
+ },
369
+ );
370
+
371
+ const flushStdout = streamLines(child.stdout, "stdout", opts.onLog);
372
+ const flushStderr = streamLines(child.stderr, "stderr", opts.onLog);
373
+
374
+ child.once("error", (error: NodeJS.ErrnoException) => {
375
+ if (opts.signal?.aborted) {
376
+ reject(error);
377
+ return;
378
+ }
379
+ // A launcher that is not installed (e.g. `bunx` absent) should fall
380
+ // through to the next, not surface as a migration failure.
381
+ if (error.code === "ENOENT") {
382
+ resolve({ kind: "unavailable" });
383
+ return;
384
+ }
385
+ reject(
386
+ new BuildError({
387
+ message: `Failed to start ${launcher.display}: ${error.message}`,
388
+ }),
389
+ );
390
+ });
391
+
392
+ child.once("close", (code, terminationSignal) => {
393
+ flushStdout();
394
+ flushStderr();
395
+
396
+ if (terminationSignal) {
397
+ if (opts.signal?.aborted) {
398
+ reject(opts.signal.reason ?? new Error("aborted"));
399
+ return;
400
+ }
401
+ reject(
402
+ new BuildError({
403
+ message: `${launcher.display} was terminated by ${terminationSignal}`,
404
+ }),
405
+ );
406
+ return;
407
+ }
408
+
409
+ if (code === 0) {
410
+ resolve({ kind: "ok" });
411
+ return;
412
+ }
413
+ // Exit 127 is the shell's "command not found": the launcher could not
414
+ // exec the tool. Treat it like ENOENT and try the next launcher rather
415
+ // than blaming the user's schema.
416
+ if (code === 127) {
417
+ resolve({ kind: "unavailable" });
418
+ return;
419
+ }
420
+ resolve({ kind: "failed", code: code ?? 1 });
421
+ });
422
+ });
423
+ }
424
+
425
+ function streamLines(
426
+ stream: Readable | null,
427
+ channel: "stdout" | "stderr",
428
+ onLog?: (line: string, stream: "stdout" | "stderr") => void,
429
+ ): () => void {
430
+ if (!stream) {
431
+ return () => {};
432
+ }
433
+
434
+ let buffer = "";
435
+ stream.on("data", (chunk: Buffer) => {
436
+ buffer += chunk.toString("utf8");
437
+ let newline = buffer.indexOf("\n");
438
+ while (newline !== -1) {
439
+ const line = buffer.slice(0, newline);
440
+ if (line.length > 0) {
441
+ onLog?.(line, channel);
442
+ }
443
+ buffer = buffer.slice(newline + 1);
444
+ newline = buffer.indexOf("\n");
445
+ }
446
+ });
447
+
448
+ return () => {
449
+ if (buffer.length > 0) {
450
+ onLog?.(buffer, channel);
451
+ buffer = "";
452
+ }
453
+ };
454
+ }
@@ -7,6 +7,7 @@ import {
7
7
  hasRootFile,
8
8
  runPackageCli,
9
9
  } from "./build-strategy.ts";
10
+ import { defaultHttpPortForBuildType } from "./config/frameworks.ts";
10
11
 
11
12
  const ASTRO_CONFIG_FILENAMES = [
12
13
  "astro.config.js",
@@ -67,7 +68,7 @@ export class AstroBuild implements BuildStrategy {
67
68
  return {
68
69
  directory: artifactDir,
69
70
  entrypoint: "server/entry.mjs",
70
- defaultPortMapping: { http: 4321 },
71
+ defaultPortMapping: { http: defaultHttpPortForBuildType("astro") },
71
72
  cleanup: () => rm(outDir, { recursive: true, force: true }),
72
73
  };
73
74
  } catch (error) {
package/src/bun-build.ts CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  import os from "node:os";
11
11
  import path from "node:path";
12
12
  import type { BuildArtifact, BuildStrategy } from "./build-strategy.ts";
13
+ import { defaultHttpPortForBuildType } from "./config/frameworks.ts";
13
14
 
14
15
  /**
15
16
  * Build strategy that runs `bun build` CLI and manages its own temp output directory.
@@ -59,6 +60,7 @@ export class BunBuild implements BuildStrategy {
59
60
  return {
60
61
  directory: bundleDir,
61
62
  entrypoint: runtimeEntrypoint,
63
+ defaultPortMapping: { http: defaultHttpPortForBuildType("bun") },
62
64
  cleanup: () => rm(outDir, { recursive: true, force: true }),
63
65
  };
64
66
  }
@@ -31,6 +31,8 @@ export interface FrameworkDescriptor {
31
31
  readonly defaultEntrypoint: string | null;
32
32
  /** Has a local dev server (`app run`) in the current preview. */
33
33
  readonly hasLocalDevServer: boolean;
34
+ /** Port the framework's built app listens on by default; the gateway routes here unless overridden. */
35
+ readonly defaultHttpPort: number;
34
36
  }
35
37
 
36
38
  export const NEXT_CONFIG_FILENAMES = [
@@ -68,6 +70,7 @@ export const FRAMEWORKS: readonly FrameworkDescriptor[] = [
68
70
  usesEntrypoint: false,
69
71
  defaultEntrypoint: null,
70
72
  hasLocalDevServer: true,
73
+ defaultHttpPort: 3000,
71
74
  },
72
75
  {
73
76
  key: "nuxt",
@@ -79,6 +82,7 @@ export const FRAMEWORKS: readonly FrameworkDescriptor[] = [
79
82
  usesEntrypoint: false,
80
83
  defaultEntrypoint: null,
81
84
  hasLocalDevServer: false,
85
+ defaultHttpPort: 3000,
82
86
  },
83
87
  {
84
88
  key: "astro",
@@ -90,6 +94,7 @@ export const FRAMEWORKS: readonly FrameworkDescriptor[] = [
90
94
  usesEntrypoint: false,
91
95
  defaultEntrypoint: null,
92
96
  hasLocalDevServer: false,
97
+ defaultHttpPort: 4321,
93
98
  },
94
99
  {
95
100
  key: "hono",
@@ -101,6 +106,7 @@ export const FRAMEWORKS: readonly FrameworkDescriptor[] = [
101
106
  usesEntrypoint: true,
102
107
  defaultEntrypoint: "src/index.ts",
103
108
  hasLocalDevServer: true,
109
+ defaultHttpPort: 3000,
104
110
  },
105
111
  {
106
112
  key: "tanstack-start",
@@ -117,6 +123,7 @@ export const FRAMEWORKS: readonly FrameworkDescriptor[] = [
117
123
  usesEntrypoint: false,
118
124
  defaultEntrypoint: null,
119
125
  hasLocalDevServer: false,
126
+ defaultHttpPort: 3000,
120
127
  },
121
128
  {
122
129
  key: "bun",
@@ -128,6 +135,7 @@ export const FRAMEWORKS: readonly FrameworkDescriptor[] = [
128
135
  usesEntrypoint: true,
129
136
  defaultEntrypoint: null,
130
137
  hasLocalDevServer: true,
138
+ defaultHttpPort: 3000,
131
139
  },
132
140
  ];
133
141
 
@@ -164,6 +172,36 @@ export const LOCAL_DEV_BUILD_TYPES: readonly FrameworkBuildType[] = [
164
172
  ),
165
173
  ];
166
174
 
175
+ const DEFAULT_HTTP_PORT_BY_BUILD_TYPE: Readonly<
176
+ Record<FrameworkBuildType, number>
177
+ > = (() => {
178
+ const ports = new Map<FrameworkBuildType, number>();
179
+ for (const framework of FRAMEWORKS) {
180
+ const existing = ports.get(framework.buildType);
181
+ if (existing !== undefined && existing !== framework.defaultHttpPort) {
182
+ throw new Error(
183
+ `Conflicting defaultHttpPort for build type "${framework.buildType}".`,
184
+ );
185
+ }
186
+ ports.set(framework.buildType, framework.defaultHttpPort);
187
+ }
188
+ return Object.fromEntries(ports) as Record<FrameworkBuildType, number>;
189
+ })();
190
+
191
+ /**
192
+ * Default HTTP port for a build type, sourced from the framework registry so
193
+ * build strategies and deploy front doors agree on where the gateway routes.
194
+ */
195
+ export function defaultHttpPortForBuildType(
196
+ buildType: FrameworkBuildType,
197
+ ): number {
198
+ const port = DEFAULT_HTTP_PORT_BY_BUILD_TYPE[buildType];
199
+ if (port === undefined) {
200
+ throw new Error(`Unknown framework build type "${buildType}".`);
201
+ }
202
+ return port;
203
+ }
204
+
167
205
  export function frameworkByKey(key: ComputeFramework): FrameworkDescriptor {
168
206
  const framework = FRAMEWORKS.find((candidate) => candidate.key === key);
169
207
  if (!framework) {
@@ -11,6 +11,7 @@ export {
11
11
  ASTRO_CONFIG_FILENAMES,
12
12
  CONFIG_BACKED_BUILD_TYPES,
13
13
  type ConfigBackedBuildType,
14
+ defaultHttpPortForBuildType,
14
15
  ENTRYPOINT_BUILD_TYPES,
15
16
  FRAMEWORK_KEYS,
16
17
  FRAMEWORKS,