@gigadrive/network-config 5.0.0 → 5.1.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.
- package/dist/define-config.d.mts +156 -2
- package/dist/define-config.d.ts +156 -2
- package/dist/index.d.mts +483 -80
- package/dist/index.d.ts +483 -80
- package/dist/index.js +1659 -403
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1641 -399
- package/dist/index.mjs.map +1 -1
- package/dist/v4/schema.json +323 -5
- package/package.json +2 -2
- package/src/v4/schema.json +323 -5
package/dist/index.js
CHANGED
|
@@ -33,6 +33,9 @@ __export(src_exports, {
|
|
|
33
33
|
ALLOWED_CONFIG_NAMES: () => ALLOWED_CONFIG_NAMES,
|
|
34
34
|
AVAILABLE_REGIONS: () => AVAILABLE_REGIONS,
|
|
35
35
|
AVAILABLE_RUNTIMES: () => AVAILABLE_RUNTIMES,
|
|
36
|
+
COMPOSE_FILE_NAMES: () => COMPOSE_FILE_NAMES,
|
|
37
|
+
CONTAINER_ENTRYPOINT_PREFIX: () => CONTAINER_ENTRYPOINT_PREFIX,
|
|
38
|
+
CONTAINER_RUNTIME: () => CONTAINER_RUNTIME,
|
|
36
39
|
ConfigFileEmptyError: () => ConfigFileEmptyError,
|
|
37
40
|
ConfigFileNotFoundError: () => ConfigFileNotFoundError,
|
|
38
41
|
ConfigFileParseError: () => ConfigFileParseError,
|
|
@@ -40,7 +43,10 @@ __export(src_exports, {
|
|
|
40
43
|
ConfigModuleLoader: () => ConfigModuleLoader,
|
|
41
44
|
ConfigSchemaValidationError: () => ConfigSchemaValidationError,
|
|
42
45
|
ConfigVersionError: () => ConfigVersionError,
|
|
46
|
+
ContainerConfigError: () => ContainerConfigError,
|
|
47
|
+
DEFAULT_CONTAINER_MEMORY_MB: () => DEFAULT_CONTAINER_MEMORY_MB,
|
|
43
48
|
DEFAULT_FUNCTION_DURATION_SECONDS: () => DEFAULT_FUNCTION_DURATION_SECONDS,
|
|
49
|
+
DEFAULT_SIDECAR_MEMORY_MB: () => DEFAULT_SIDECAR_MEMORY_MB,
|
|
44
50
|
FRAMEWORK_DEFINITIONS: () => FRAMEWORK_DEFINITIONS,
|
|
45
51
|
FrameworkNotDetectedError: () => FrameworkNotDetectedError,
|
|
46
52
|
FunctionConfigError: () => FunctionConfigError,
|
|
@@ -57,6 +63,7 @@ __export(src_exports, {
|
|
|
57
63
|
GigadriveNextServerDescriptorSchema: () => GigadriveNextServerDescriptorSchema,
|
|
58
64
|
GigadriveNextStaticAssetPrefixSchema: () => GigadriveNextStaticAssetPrefixSchema,
|
|
59
65
|
MAX_FUNCTION_DURATION_SECONDS: () => MAX_FUNCTION_DURATION_SECONDS,
|
|
66
|
+
MAX_SIDECARS: () => MAX_SIDECARS,
|
|
60
67
|
ManifestNotFoundError: () => ManifestNotFoundError,
|
|
61
68
|
ManifestParseError: () => ManifestParseError,
|
|
62
69
|
ManifestReadError: () => ManifestReadError,
|
|
@@ -69,20 +76,27 @@ __export(src_exports, {
|
|
|
69
76
|
V4ConfigParser: () => V4ConfigParser,
|
|
70
77
|
VercelBuildOutputParser: () => VercelBuildOutputParser,
|
|
71
78
|
collectAssetFiles: () => collectAssetFiles,
|
|
79
|
+
composeDeclaresApp: () => composeDeclaresApp,
|
|
80
|
+
containerEntrypointPath: () => containerEntrypointPath,
|
|
72
81
|
defineConfig: () => defineConfig,
|
|
82
|
+
detectContainerProject: () => detectContainerProject,
|
|
73
83
|
detectFramework: () => detectFramework,
|
|
74
84
|
detectPackageManager: () => detectPackageManager,
|
|
85
|
+
dockerFunctionContainerName: () => dockerFunctionContainerName,
|
|
75
86
|
filterFunctionsFromAssets: () => filterFunctionsFromAssets,
|
|
76
87
|
generateConfig: () => generateConfig,
|
|
77
88
|
getFunctionSettings: () => getFunctionSettings,
|
|
78
89
|
mergeWithFrameworkDefaults: () => mergeWithFrameworkDefaults,
|
|
90
|
+
normalizeContainers: () => normalizeContainers,
|
|
79
91
|
parseConfig: () => parseConfig,
|
|
80
92
|
parseConfigRaw: () => parseConfigRaw,
|
|
81
93
|
parseGigadriveNextBuildManifest: () => parseGigadriveNextBuildManifest,
|
|
82
94
|
parseGigadriveNextPrerenderManifest: () => parseGigadriveNextPrerenderManifest,
|
|
83
95
|
parseStaticAssetManifest: () => parseStaticAssetManifest,
|
|
84
96
|
postProcessConfig: () => postProcessConfig,
|
|
85
|
-
|
|
97
|
+
readComposeContainers: () => readComposeContainers,
|
|
98
|
+
readDependencies: () => readDependencies,
|
|
99
|
+
splitCommandWords: () => splitCommandWords
|
|
86
100
|
});
|
|
87
101
|
module.exports = __toCommonJS(src_exports);
|
|
88
102
|
|
|
@@ -181,16 +195,824 @@ var collectAssetFiles = import_effect3.Effect.fn("collectAssetFiles")(function*
|
|
|
181
195
|
return files.map((file) => file.replaceAll("\\", "/")).filter((file) => !DISALLOWED_ASSET_EXTENSIONS.some((extension) => file.toLowerCase().endsWith(extension))).sort();
|
|
182
196
|
});
|
|
183
197
|
|
|
198
|
+
// src/containers.ts
|
|
199
|
+
var import_platform2 = require("@effect/platform");
|
|
200
|
+
var import_effect5 = require("effect");
|
|
201
|
+
var import_node_path = require("path");
|
|
202
|
+
var import_yaml = require("yaml");
|
|
203
|
+
|
|
204
|
+
// src/errors.ts
|
|
205
|
+
var import_effect4 = require("effect");
|
|
206
|
+
var ConfigFileNotFoundError = class extends import_effect4.Schema.TaggedError()("ConfigFileNotFoundError", {
|
|
207
|
+
message: import_effect4.Schema.String,
|
|
208
|
+
filePath: import_effect4.Schema.String
|
|
209
|
+
}) {
|
|
210
|
+
};
|
|
211
|
+
var ConfigFileEmptyError = class extends import_effect4.Schema.TaggedError()("ConfigFileEmptyError", {
|
|
212
|
+
message: import_effect4.Schema.String,
|
|
213
|
+
filePath: import_effect4.Schema.String
|
|
214
|
+
}) {
|
|
215
|
+
};
|
|
216
|
+
var ConfigFileParseError = class extends import_effect4.Schema.TaggedError()("ConfigFileParseError", {
|
|
217
|
+
message: import_effect4.Schema.String,
|
|
218
|
+
filePath: import_effect4.Schema.String,
|
|
219
|
+
cause: import_effect4.Schema.optional(import_effect4.Schema.String)
|
|
220
|
+
}) {
|
|
221
|
+
};
|
|
222
|
+
var ConfigModuleLoadError = class extends import_effect4.Schema.TaggedError()("ConfigModuleLoadError", {
|
|
223
|
+
message: import_effect4.Schema.String,
|
|
224
|
+
filePath: import_effect4.Schema.String,
|
|
225
|
+
cause: import_effect4.Schema.optional(import_effect4.Schema.String)
|
|
226
|
+
}) {
|
|
227
|
+
};
|
|
228
|
+
var ConfigVersionError = class extends import_effect4.Schema.TaggedError()("ConfigVersionError", {
|
|
229
|
+
message: import_effect4.Schema.String,
|
|
230
|
+
filePath: import_effect4.Schema.String,
|
|
231
|
+
version: import_effect4.Schema.optional(import_effect4.Schema.Number)
|
|
232
|
+
}) {
|
|
233
|
+
};
|
|
234
|
+
var ConfigSchemaValidationError = class extends import_effect4.Schema.TaggedError()(
|
|
235
|
+
"ConfigSchemaValidationError",
|
|
236
|
+
{
|
|
237
|
+
message: import_effect4.Schema.String,
|
|
238
|
+
filePath: import_effect4.Schema.String,
|
|
239
|
+
validationErrors: import_effect4.Schema.Array(import_effect4.Schema.String)
|
|
240
|
+
}
|
|
241
|
+
) {
|
|
242
|
+
};
|
|
243
|
+
var FunctionConfigError = class extends import_effect4.Schema.TaggedError()("FunctionConfigError", {
|
|
244
|
+
message: import_effect4.Schema.String,
|
|
245
|
+
functionPath: import_effect4.Schema.String
|
|
246
|
+
}) {
|
|
247
|
+
};
|
|
248
|
+
var ContainerConfigError = class extends import_effect4.Schema.TaggedError()("ContainerConfigError", {
|
|
249
|
+
message: import_effect4.Schema.String,
|
|
250
|
+
containerName: import_effect4.Schema.optional(import_effect4.Schema.String),
|
|
251
|
+
filePath: import_effect4.Schema.optional(import_effect4.Schema.String)
|
|
252
|
+
}) {
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
// src/normalized-config.ts
|
|
256
|
+
var DEFAULT_FUNCTION_DURATION_SECONDS = 30;
|
|
257
|
+
var MAX_FUNCTION_DURATION_SECONDS = 28800;
|
|
258
|
+
var CONTAINER_RUNTIME = "docker";
|
|
259
|
+
var CONTAINER_ENTRYPOINT_PREFIX = "container:";
|
|
260
|
+
var DEFAULT_CONTAINER_MEMORY_MB = 512;
|
|
261
|
+
var DEFAULT_SIDECAR_MEMORY_MB = 256;
|
|
262
|
+
var MAX_SIDECARS = 4;
|
|
263
|
+
|
|
264
|
+
// src/containers.ts
|
|
265
|
+
var COMPOSE_FILE_NAMES = ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"];
|
|
266
|
+
var CONTAINER_NAME_PATTERN = /^[a-z][a-z0-9_-]{0,62}$/;
|
|
267
|
+
var CONTAINER_NAME_RULES = "1 to 63 lowercase letters, digits, '-' or '_', starting with a letter, and not 'localhost'";
|
|
268
|
+
var MIN_CONTAINER_MEMORY_MB = 128;
|
|
269
|
+
var MAX_CONTAINER_MEMORY_MB = 3009;
|
|
270
|
+
var MAX_CONTAINER_ENV_VARS = 100;
|
|
271
|
+
var MAX_CONTAINER_ENV_VALUE_LENGTH = 65536;
|
|
272
|
+
var containerEntrypointPath = (name) => `${CONTAINER_ENTRYPOINT_PREFIX}${name}`;
|
|
273
|
+
var toContainerName = (raw) => {
|
|
274
|
+
const cleaned = raw.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^[^a-z0-9]+/, "");
|
|
275
|
+
const name = (cleaned === "" || /^[a-z]/.test(cleaned) ? cleaned : `app-${cleaned}`).slice(0, 63);
|
|
276
|
+
return name === "" || name === "localhost" ? "app" : name;
|
|
277
|
+
};
|
|
278
|
+
var dockerFunctionContainerName = (file) => {
|
|
279
|
+
const { dir, base } = import_node_path.posix.parse(file);
|
|
280
|
+
const variant = base.replace(/^Dockerfile[.-]?/i, "").replace(/[.-]?Dockerfile$/i, "");
|
|
281
|
+
const raw = [import_node_path.posix.basename(dir), variant === base ? import_node_path.posix.parse(base).name : variant].filter((part) => part !== "").join("-");
|
|
282
|
+
return toContainerName(raw);
|
|
283
|
+
};
|
|
284
|
+
var splitCommandWords = (input) => {
|
|
285
|
+
const words = [];
|
|
286
|
+
let current = "";
|
|
287
|
+
let inWord = false;
|
|
288
|
+
let quote;
|
|
289
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
290
|
+
const char = input[index];
|
|
291
|
+
if (quote === "'") {
|
|
292
|
+
if (char === "'") quote = void 0;
|
|
293
|
+
else current += char;
|
|
294
|
+
} else if (char === "\\" && index + 1 < input.length) {
|
|
295
|
+
index += 1;
|
|
296
|
+
current += input[index];
|
|
297
|
+
inWord = true;
|
|
298
|
+
} else if (quote === '"') {
|
|
299
|
+
if (char === '"') quote = void 0;
|
|
300
|
+
else current += char;
|
|
301
|
+
} else if (char === "'" || char === '"') {
|
|
302
|
+
quote = char;
|
|
303
|
+
inWord = true;
|
|
304
|
+
} else if (/\s/.test(char)) {
|
|
305
|
+
if (inWord) words.push(current);
|
|
306
|
+
current = "";
|
|
307
|
+
inWord = false;
|
|
308
|
+
} else {
|
|
309
|
+
current += char;
|
|
310
|
+
inWord = true;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (quote) throw new Error(`Unterminated ${quote} quote`);
|
|
314
|
+
if (inWord) words.push(current);
|
|
315
|
+
return words;
|
|
316
|
+
};
|
|
317
|
+
var normalizeProjectPath = (input) => {
|
|
318
|
+
if (import_node_path.posix.isAbsolute(input)) return void 0;
|
|
319
|
+
const normalized = import_node_path.posix.normalize(input.replace(/\\/g, "/")).replace(/\/+$/, "") || ".";
|
|
320
|
+
if (normalized === ".." || normalized.startsWith("../")) return void 0;
|
|
321
|
+
return normalized;
|
|
322
|
+
};
|
|
323
|
+
var resolveProjectRoot = (projectFolder) => import_effect5.Effect.flatMap(
|
|
324
|
+
import_platform2.FileSystem.FileSystem,
|
|
325
|
+
(fs) => fs.realPath(projectFolder).pipe(import_effect5.Effect.orElseSucceed(() => projectFolder))
|
|
326
|
+
);
|
|
327
|
+
var resolveInsideProject = (projectRoot, projectRelative, subject, context) => import_effect5.Effect.gen(function* () {
|
|
328
|
+
const fs = yield* import_platform2.FileSystem.FileSystem;
|
|
329
|
+
const pathSvc = yield* import_platform2.Path.Path;
|
|
330
|
+
const resolved = yield* fs.realPath(pathSvc.join(projectRoot, projectRelative)).pipe(import_effect5.Effect.option);
|
|
331
|
+
if (import_effect5.Option.isNone(resolved)) return resolved;
|
|
332
|
+
const relative = pathSvc.relative(projectRoot, resolved.value);
|
|
333
|
+
if (relative === ".." || relative.startsWith(`..${pathSvc.sep}`) || pathSvc.isAbsolute(relative)) {
|
|
334
|
+
return yield* new ContainerConfigError({
|
|
335
|
+
message: `${subject} leads through a symbolic link to a location outside the project. Only files inside the project can be deployed.`,
|
|
336
|
+
...context
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
return resolved;
|
|
340
|
+
});
|
|
341
|
+
var readInsideProject = (projectRoot, projectRelative, subject, context) => import_effect5.Effect.gen(function* () {
|
|
342
|
+
const fs = yield* import_platform2.FileSystem.FileSystem;
|
|
343
|
+
const resolved = yield* resolveInsideProject(projectRoot, projectRelative, subject, context);
|
|
344
|
+
if (import_effect5.Option.isNone(resolved)) return import_effect5.Option.none();
|
|
345
|
+
return yield* fs.readFileString(resolved.value).pipe(import_effect5.Effect.option);
|
|
346
|
+
});
|
|
347
|
+
var toArgv = (name, key, value) => value === void 0 ? import_effect5.Effect.succeed(void 0) : Array.isArray(value) ? import_effect5.Effect.succeed(value) : import_effect5.Effect.try({
|
|
348
|
+
try: () => splitCommandWords(value),
|
|
349
|
+
catch: (error) => new ContainerConfigError({
|
|
350
|
+
message: `Container '${name}' has an invalid ${key}: ${error instanceof Error ? error.message : String(error)}`,
|
|
351
|
+
containerName: name
|
|
352
|
+
})
|
|
353
|
+
});
|
|
354
|
+
var isIntegerBetween = (value, min, max) => Number.isInteger(value) && value >= min && value <= max;
|
|
355
|
+
var validateContainer = (name, container) => {
|
|
356
|
+
const build = typeof container.build === "object" ? container.build : void 0;
|
|
357
|
+
const buildArgs = Object.values(build?.args ?? {});
|
|
358
|
+
const env = Object.entries(container.env ?? {});
|
|
359
|
+
const user = container.user === void 0 ? void 0 : String(container.user);
|
|
360
|
+
const badEnvKey = env.find(([key]) => key === "" || key.includes("=") || key.includes("\0"))?.[0];
|
|
361
|
+
const longEnvKey = env.find(([, value]) => value.length > MAX_CONTAINER_ENV_VALUE_LENGTH)?.[0];
|
|
362
|
+
const problem = [
|
|
363
|
+
[
|
|
364
|
+
container.image !== void 0 && !/^\S{1,512}$/.test(container.image),
|
|
365
|
+
"has an invalid image reference. Use 1 to 512 characters without whitespace."
|
|
366
|
+
],
|
|
367
|
+
[
|
|
368
|
+
container.port !== void 0 && !isIntegerBetween(container.port, 1, 65535),
|
|
369
|
+
`listens on port ${container.port}. Use a whole number from 1 to 65535.`
|
|
370
|
+
],
|
|
371
|
+
[
|
|
372
|
+
container.memory !== void 0 && !isIntegerBetween(container.memory, MIN_CONTAINER_MEMORY_MB, MAX_CONTAINER_MEMORY_MB),
|
|
373
|
+
`asks for ${container.memory} MB of memory. Use a whole number from ${MIN_CONTAINER_MEMORY_MB} to ${MAX_CONTAINER_MEMORY_MB}.`
|
|
374
|
+
],
|
|
375
|
+
[
|
|
376
|
+
container.working_dir !== void 0 && !(container.working_dir.startsWith("/") && container.working_dir.length <= 1024),
|
|
377
|
+
`sets working_dir '${container.working_dir}', which must be an absolute path of at most 1024 characters.`
|
|
378
|
+
],
|
|
379
|
+
[
|
|
380
|
+
typeof container.user === "number" && !isIntegerBetween(container.user, 0, Number.MAX_SAFE_INTEGER),
|
|
381
|
+
`sets user ${container.user}. A numeric user must be a non-negative whole number.`
|
|
382
|
+
],
|
|
383
|
+
[
|
|
384
|
+
user !== void 0 && (user.length === 0 || user.length > 256),
|
|
385
|
+
"sets an empty or overlong user. Use 1 to 256 characters: a name, a uid, name:group or uid:gid."
|
|
386
|
+
],
|
|
387
|
+
[
|
|
388
|
+
build?.target !== void 0 && (build.target.length === 0 || build.target.length > 128),
|
|
389
|
+
"has an empty build target or one longer than 128 characters."
|
|
390
|
+
],
|
|
391
|
+
[
|
|
392
|
+
buildArgs.length > MAX_CONTAINER_ENV_VARS || buildArgs.some((value) => value.length > MAX_CONTAINER_ENV_VALUE_LENGTH),
|
|
393
|
+
`sets more than ${MAX_CONTAINER_ENV_VARS} build args, or one longer than ${MAX_CONTAINER_ENV_VALUE_LENGTH} characters.`
|
|
394
|
+
],
|
|
395
|
+
[
|
|
396
|
+
env.length > MAX_CONTAINER_ENV_VARS,
|
|
397
|
+
`sets ${env.length} environment variables. At most ${MAX_CONTAINER_ENV_VARS} are allowed.`
|
|
398
|
+
],
|
|
399
|
+
[
|
|
400
|
+
badEnvKey !== void 0,
|
|
401
|
+
`sets an environment variable named '${badEnvKey}'. Names must be non-empty and contain no '='.`
|
|
402
|
+
],
|
|
403
|
+
[
|
|
404
|
+
longEnvKey !== void 0,
|
|
405
|
+
`sets environment variable '${longEnvKey}' to a value longer than ${MAX_CONTAINER_ENV_VALUE_LENGTH} characters.`
|
|
406
|
+
]
|
|
407
|
+
].find(([failed]) => failed)?.[1];
|
|
408
|
+
return problem === void 0 ? import_effect5.Effect.void : import_effect5.Effect.fail(new ContainerConfigError({ message: `Container '${name}' ${problem}`, containerName: name }));
|
|
409
|
+
};
|
|
410
|
+
var toContainerSpec = import_effect5.Effect.fn("toContainerSpec")(function* (name, container, projectFolder) {
|
|
411
|
+
yield* validateContainer(name, container);
|
|
412
|
+
let source;
|
|
413
|
+
if (container.image !== void 0 && container.build === void 0) {
|
|
414
|
+
source = { type: "registry", reference: container.image };
|
|
415
|
+
} else if (container.build !== void 0 && container.image === void 0) {
|
|
416
|
+
const build = typeof container.build === "string" ? { context: container.build } : container.build;
|
|
417
|
+
const dockerfile = build.dockerfile ?? "Dockerfile";
|
|
418
|
+
const context = normalizeProjectPath(build.context ?? ".");
|
|
419
|
+
const dockerfilePath = context === void 0 || import_node_path.posix.isAbsolute(dockerfile) ? void 0 : normalizeProjectPath(import_node_path.posix.join(context, dockerfile));
|
|
420
|
+
if (context === void 0 || dockerfilePath === void 0) {
|
|
421
|
+
return yield* new ContainerConfigError({
|
|
422
|
+
message: `Container '${name}' has a build context or Dockerfile outside the project.`,
|
|
423
|
+
containerName: name
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
const projectRoot = yield* resolveProjectRoot(projectFolder);
|
|
427
|
+
yield* resolveInsideProject(projectRoot, context, `The build context '${context}' of container '${name}'`, {
|
|
428
|
+
containerName: name
|
|
429
|
+
});
|
|
430
|
+
const dockerfileReal = yield* resolveInsideProject(
|
|
431
|
+
projectRoot,
|
|
432
|
+
dockerfilePath,
|
|
433
|
+
`The Dockerfile '${dockerfilePath}' of container '${name}'`,
|
|
434
|
+
{ containerName: name }
|
|
435
|
+
);
|
|
436
|
+
if (import_effect5.Option.isNone(dockerfileReal)) {
|
|
437
|
+
return yield* new ContainerConfigError({
|
|
438
|
+
message: `Container '${name}' builds '${dockerfilePath}', which does not exist.`,
|
|
439
|
+
containerName: name
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
source = {
|
|
443
|
+
type: "dockerfile",
|
|
444
|
+
context,
|
|
445
|
+
dockerfile: import_node_path.posix.relative(context, dockerfilePath),
|
|
446
|
+
...build.target !== void 0 && { target: build.target },
|
|
447
|
+
...build.args !== void 0 && Object.keys(build.args).length > 0 && { buildArgs: { ...build.args } }
|
|
448
|
+
};
|
|
449
|
+
} else {
|
|
450
|
+
return yield* new ContainerConfigError({
|
|
451
|
+
message: `Container '${name}' must set exactly one of 'image' and 'build'.`,
|
|
452
|
+
containerName: name
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
const entrypoint = yield* toArgv(name, "entrypoint", container.entrypoint);
|
|
456
|
+
const command = yield* toArgv(name, "command", container.command);
|
|
457
|
+
const spec = {
|
|
458
|
+
name,
|
|
459
|
+
source,
|
|
460
|
+
...container.port !== void 0 && { port: container.port },
|
|
461
|
+
...entrypoint !== void 0 && { entrypoint },
|
|
462
|
+
...command !== void 0 && { command },
|
|
463
|
+
...container.working_dir !== void 0 && { workingDirectory: container.working_dir },
|
|
464
|
+
...container.user !== void 0 && { user: String(container.user) },
|
|
465
|
+
...container.env !== void 0 && Object.keys(container.env).length > 0 && { environmentVariables: { ...container.env } }
|
|
466
|
+
};
|
|
467
|
+
return spec;
|
|
468
|
+
});
|
|
469
|
+
var normalizeContainers = import_effect5.Effect.fn("normalizeContainers")(function* (containers, projectFolder) {
|
|
470
|
+
const entrypoints = [];
|
|
471
|
+
const sidecars = [];
|
|
472
|
+
const warnings = [];
|
|
473
|
+
for (const [name, container] of Object.entries(containers)) {
|
|
474
|
+
if (!CONTAINER_NAME_PATTERN.test(name) || name === "localhost") {
|
|
475
|
+
return yield* new ContainerConfigError({
|
|
476
|
+
message: `Container name '${name}' is invalid. The name is also the hostname the function reaches the container by, so it must be ${CONTAINER_NAME_RULES}. Try '${toContainerName(name)}'.`,
|
|
477
|
+
containerName: name
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
const spec = yield* toContainerSpec(name, container, projectFolder);
|
|
481
|
+
if (container.sidecar === true) {
|
|
482
|
+
const ignored = ["max_duration", "streaming", "schedule"].filter(
|
|
483
|
+
(key) => container[key] !== void 0
|
|
484
|
+
);
|
|
485
|
+
if (ignored.length > 0) {
|
|
486
|
+
warnings.push(
|
|
487
|
+
`Sidecar '${name}' ignores ${ignored.join(", ")}: those settings apply to container functions only.`
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
sidecars.push({ ...spec, memory: container.memory ?? DEFAULT_SIDECAR_MEMORY_MB });
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
entrypoints.push({
|
|
494
|
+
path: containerEntrypointPath(name),
|
|
495
|
+
displayName: name,
|
|
496
|
+
runtime: CONTAINER_RUNTIME,
|
|
497
|
+
memory: container.memory ?? DEFAULT_CONTAINER_MEMORY_MB,
|
|
498
|
+
maxDuration: container.max_duration ?? DEFAULT_FUNCTION_DURATION_SECONDS,
|
|
499
|
+
streaming: container.streaming ?? true,
|
|
500
|
+
...container.schedule !== void 0 && { schedule: container.schedule },
|
|
501
|
+
container: spec
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
if (sidecars.length > MAX_SIDECARS) {
|
|
505
|
+
return yield* new ContainerConfigError({
|
|
506
|
+
message: `A deployment may declare at most ${MAX_SIDECARS} sidecars; this one declares ${sidecars.length}.`
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
const sidecarPorts = /* @__PURE__ */ new Map();
|
|
510
|
+
for (const sidecar of sidecars) {
|
|
511
|
+
if (sidecar.port === void 0) continue;
|
|
512
|
+
const owner = sidecarPorts.get(sidecar.port);
|
|
513
|
+
if (owner !== void 0) {
|
|
514
|
+
return yield* new ContainerConfigError({
|
|
515
|
+
message: `Sidecars '${owner}' and '${sidecar.name}' both listen on port ${sidecar.port}. Sidecars share one network namespace, so their ports must differ.`,
|
|
516
|
+
containerName: sidecar.name
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
sidecarPorts.set(sidecar.port, sidecar.name);
|
|
520
|
+
}
|
|
521
|
+
for (const entrypoint of entrypoints) {
|
|
522
|
+
const port = entrypoint.container?.port;
|
|
523
|
+
const sidecar = port === void 0 ? void 0 : sidecarPorts.get(port);
|
|
524
|
+
if (sidecar !== void 0) {
|
|
525
|
+
return yield* new ContainerConfigError({
|
|
526
|
+
message: `Container '${entrypoint.displayName}' and sidecar '${sidecar}' both listen on port ${port}. Sidecars run inside the function's microVM, so their ports must differ.`,
|
|
527
|
+
containerName: sidecar
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return { entrypoints, sidecars, warnings };
|
|
532
|
+
});
|
|
533
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
534
|
+
var isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
535
|
+
var scalarToString = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : void 0;
|
|
536
|
+
var gigadriveExtension = (service) => isRecord(service["x-gigadrive"]) ? service["x-gigadrive"] : {};
|
|
537
|
+
var COMPOSE_OVERRIDE_FILE_NAMES = [
|
|
538
|
+
"compose.override.yaml",
|
|
539
|
+
"compose.override.yml",
|
|
540
|
+
"docker-compose.override.yaml",
|
|
541
|
+
"docker-compose.override.yml"
|
|
542
|
+
];
|
|
543
|
+
var findClosingQuote = (body, quote) => {
|
|
544
|
+
for (let index = 0; index < body.length; index += 1) {
|
|
545
|
+
if (quote === '"' && body[index] === "\\") index += 1;
|
|
546
|
+
else if (body[index] === quote) return index;
|
|
547
|
+
}
|
|
548
|
+
return -1;
|
|
549
|
+
};
|
|
550
|
+
var DOUBLE_QUOTE_ESCAPES = { n: "\n", r: "\r", t: " " };
|
|
551
|
+
var parseDotEnv = (content) => {
|
|
552
|
+
const values = {};
|
|
553
|
+
const lines = content.split(/\r?\n/);
|
|
554
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
555
|
+
const match = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_.-]*)\s*=(.*)$/.exec(lines[index]);
|
|
556
|
+
if (!match) continue;
|
|
557
|
+
const [, key, rest] = match;
|
|
558
|
+
const quote = rest.trimStart()[0];
|
|
559
|
+
if (quote === '"' || quote === "'") {
|
|
560
|
+
let body = rest.trimStart().slice(1);
|
|
561
|
+
let end = index;
|
|
562
|
+
let close = findClosingQuote(body, quote);
|
|
563
|
+
while (close === -1 && end + 1 < lines.length) {
|
|
564
|
+
end += 1;
|
|
565
|
+
body += `
|
|
566
|
+
${lines[end]}`;
|
|
567
|
+
close = findClosingQuote(body, quote);
|
|
568
|
+
}
|
|
569
|
+
if (close !== -1) {
|
|
570
|
+
const raw = body.slice(0, close);
|
|
571
|
+
values[key] = quote === '"' ? raw.replace(/\\([nrt"\\])/g, (_match, char) => DOUBLE_QUOTE_ESCAPES[char] ?? char) : raw;
|
|
572
|
+
index = end;
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
values[key] = rest.replace(/\s+#.*$/, "").trim();
|
|
577
|
+
}
|
|
578
|
+
return values;
|
|
579
|
+
};
|
|
580
|
+
var InterpolationError = class extends Error {
|
|
581
|
+
};
|
|
582
|
+
var findClosingBrace = (value, start) => {
|
|
583
|
+
let depth = 0;
|
|
584
|
+
for (let index = start; index < value.length; index += 1) {
|
|
585
|
+
if (value[index] === "$" && (value[index + 1] === "$" || value[index + 1] === "{")) {
|
|
586
|
+
if (value[index + 1] === "{") depth += 1;
|
|
587
|
+
index += 1;
|
|
588
|
+
} else if (value[index] === "}") {
|
|
589
|
+
if (depth === 0) return index;
|
|
590
|
+
depth -= 1;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return -1;
|
|
594
|
+
};
|
|
595
|
+
var interpolate = (value, variables, missing, where) => {
|
|
596
|
+
let result = "";
|
|
597
|
+
let index = 0;
|
|
598
|
+
while (index < value.length) {
|
|
599
|
+
const dollar = value.indexOf("$", index);
|
|
600
|
+
if (dollar === -1) {
|
|
601
|
+
result += value.slice(index);
|
|
602
|
+
break;
|
|
603
|
+
}
|
|
604
|
+
result += value.slice(index, dollar);
|
|
605
|
+
const next = value[dollar + 1];
|
|
606
|
+
if (next === "$") {
|
|
607
|
+
result += "$";
|
|
608
|
+
index = dollar + 2;
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
if (next === "{") {
|
|
612
|
+
const close = findClosingBrace(value, dollar + 2);
|
|
613
|
+
const expression = close === -1 ? null : /^([A-Za-z_][A-Za-z0-9_]*)(?:(:?[-?+])([\s\S]*))?$/.exec(value.slice(dollar + 2, close));
|
|
614
|
+
if (expression === null) {
|
|
615
|
+
throw new InterpolationError(`has an invalid variable reference in ${where}. Write '$$' for a literal '$'.`);
|
|
616
|
+
}
|
|
617
|
+
const [, name, operator, operand = ""] = expression;
|
|
618
|
+
const current = variables[name];
|
|
619
|
+
const isSet = current !== void 0 && !(operator?.startsWith(":") === true && current === "");
|
|
620
|
+
if (operator === void 0) {
|
|
621
|
+
if (current === void 0) missing.add(name);
|
|
622
|
+
result += current ?? "";
|
|
623
|
+
} else if (operator.endsWith("-")) {
|
|
624
|
+
result += isSet ? current : interpolate(operand, variables, missing, where);
|
|
625
|
+
} else if (operator.endsWith("+")) {
|
|
626
|
+
result += isSet ? interpolate(operand, variables, missing, where) : "";
|
|
627
|
+
} else if (isSet) {
|
|
628
|
+
result += current;
|
|
629
|
+
} else {
|
|
630
|
+
const reason = interpolate(operand, variables, missing, where);
|
|
631
|
+
throw new InterpolationError(
|
|
632
|
+
`needs variable '${name}' in ${where}, which is ${current === void 0 ? "not set" : "empty"}${reason === "" ? "" : `: ${reason}`}. Compose variables come only from the .env file next to the Compose file.`
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
index = close + 1;
|
|
636
|
+
continue;
|
|
637
|
+
}
|
|
638
|
+
const bare = /^[A-Za-z_][A-Za-z0-9_]*/.exec(value.slice(dollar + 1))?.[0];
|
|
639
|
+
if (bare === void 0) {
|
|
640
|
+
result += "$";
|
|
641
|
+
index = dollar + 1;
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
if (variables[bare] === void 0) missing.add(bare);
|
|
645
|
+
result += variables[bare] ?? "";
|
|
646
|
+
index = dollar + 1 + bare.length;
|
|
647
|
+
}
|
|
648
|
+
return result;
|
|
649
|
+
};
|
|
650
|
+
var interpolateDeep = (value, variables, missing, where) => {
|
|
651
|
+
if (typeof value === "string") return interpolate(value, variables, missing, where);
|
|
652
|
+
if (Array.isArray(value)) {
|
|
653
|
+
return value.map((item, index) => interpolateDeep(item, variables, missing, `${where}[${index}]`));
|
|
654
|
+
}
|
|
655
|
+
if (isRecord(value)) {
|
|
656
|
+
return Object.fromEntries(
|
|
657
|
+
Object.entries(value).map(([key, item]) => [
|
|
658
|
+
key,
|
|
659
|
+
interpolateDeep(item, variables, missing, where === "" ? key : `${where}.${key}`)
|
|
660
|
+
])
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
return value;
|
|
664
|
+
};
|
|
665
|
+
var parseComposeMemory = (value) => {
|
|
666
|
+
if (typeof value === "number") {
|
|
667
|
+
return Number.isFinite(value) && value >= 0 ? Math.ceil(value / 1024 ** 2) : void 0;
|
|
668
|
+
}
|
|
669
|
+
if (typeof value !== "string") return void 0;
|
|
670
|
+
const match = /^(\d+(?:\.\d+)?) ?([kmgtp])?i?b?$/i.exec(value.trim());
|
|
671
|
+
if (!match) return void 0;
|
|
672
|
+
const exponent = " kmgtp".indexOf((match[2] ?? " ").toLowerCase());
|
|
673
|
+
return Math.ceil(Number(match[1]) * 1024 ** exponent / 1024 ** 2);
|
|
674
|
+
};
|
|
675
|
+
var parseComposePort = (entry) => {
|
|
676
|
+
let port = entry;
|
|
677
|
+
if (isRecord(entry)) {
|
|
678
|
+
if (typeof entry.protocol === "string" && entry.protocol.toLowerCase() !== "tcp") return void 0;
|
|
679
|
+
port = entry.target;
|
|
680
|
+
} else if (typeof entry === "string") {
|
|
681
|
+
const [withoutProtocol, protocol] = entry.split("/");
|
|
682
|
+
if (protocol !== void 0 && protocol.toLowerCase() !== "tcp") return void 0;
|
|
683
|
+
port = (withoutProtocol.split(":").at(-1) ?? "").split("-")[0];
|
|
684
|
+
}
|
|
685
|
+
const number = typeof port === "number" ? port : typeof port === "string" && /^\d+$/.test(port) ? Number(port) : NaN;
|
|
686
|
+
return isIntegerBetween(number, 1, 65535) ? number : void 0;
|
|
687
|
+
};
|
|
688
|
+
var parseComposeEnvironment = (serviceName, value, warnings) => {
|
|
689
|
+
if (value === void 0 || value === null) return void 0;
|
|
690
|
+
const environment = {};
|
|
691
|
+
if (Array.isArray(value)) {
|
|
692
|
+
for (const item of value) {
|
|
693
|
+
if (typeof item !== "string") continue;
|
|
694
|
+
const separator = item.indexOf("=");
|
|
695
|
+
if (separator === -1) {
|
|
696
|
+
warnings.push(
|
|
697
|
+
`Compose service '${serviceName}' takes '${item}' from the host environment, which deployments do not have. Set it in the console instead.`
|
|
698
|
+
);
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
environment[item.slice(0, separator)] = item.slice(separator + 1);
|
|
702
|
+
}
|
|
703
|
+
} else if (isRecord(value)) {
|
|
704
|
+
for (const [key, item] of Object.entries(value)) {
|
|
705
|
+
const scalar = scalarToString(item);
|
|
706
|
+
if (scalar === void 0) {
|
|
707
|
+
warnings.push(
|
|
708
|
+
`Compose service '${serviceName}' takes '${key}' from the host environment, which deployments do not have. Set it in the console instead.`
|
|
709
|
+
);
|
|
710
|
+
continue;
|
|
711
|
+
}
|
|
712
|
+
environment[key] = scalar;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
return environment;
|
|
716
|
+
};
|
|
717
|
+
var isPublicMarked = (service) => gigadriveExtension(service).public === true;
|
|
718
|
+
var buildsFromSource = (service) => service.build !== void 0 && gigadriveExtension(service).sidecar !== true;
|
|
719
|
+
var loadComposeServices = import_effect5.Effect.fn("loadComposeServices")(function* (composePath, projectFolder) {
|
|
720
|
+
const relativePath = normalizeProjectPath(composePath);
|
|
721
|
+
if (relativePath === void 0) {
|
|
722
|
+
return yield* new ContainerConfigError({
|
|
723
|
+
message: `Compose file '${composePath}' is outside the project.`,
|
|
724
|
+
filePath: composePath
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
const projectRoot = yield* resolveProjectRoot(projectFolder);
|
|
728
|
+
const content = yield* readInsideProject(projectRoot, relativePath, `Compose file '${relativePath}'`, {
|
|
729
|
+
filePath: relativePath
|
|
730
|
+
});
|
|
731
|
+
if (import_effect5.Option.isNone(content)) {
|
|
732
|
+
return yield* new ContainerConfigError({
|
|
733
|
+
message: `Compose file '${relativePath}' could not be read.`,
|
|
734
|
+
filePath: relativePath
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
const document = yield* import_effect5.Effect.try({
|
|
738
|
+
try: () => (0, import_yaml.parse)(content.value),
|
|
739
|
+
catch: (error) => {
|
|
740
|
+
const position = error instanceof import_yaml.YAMLError ? error.linePos?.[0] : void 0;
|
|
741
|
+
return new ContainerConfigError({
|
|
742
|
+
message: `Compose file '${relativePath}' is not valid YAML${position ? ` (line ${position.line}, column ${position.col})` : ""}.`,
|
|
743
|
+
filePath: relativePath
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
});
|
|
747
|
+
if (!isRecord(document) || !isRecord(document.services) || Object.keys(document.services).length === 0) {
|
|
748
|
+
return yield* new ContainerConfigError({
|
|
749
|
+
message: `Compose file '${relativePath}' declares no services.`,
|
|
750
|
+
filePath: relativePath
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
const services = Object.entries(document.services).filter(
|
|
754
|
+
(entry) => isRecord(entry[1]) && !(isStringArray(entry[1].profiles) && entry[1].profiles.length > 0) && gigadriveExtension(entry[1]).skip !== true
|
|
755
|
+
);
|
|
756
|
+
return { relativePath, projectRoot, services };
|
|
757
|
+
});
|
|
758
|
+
var composeDeclaresApp = import_effect5.Effect.fn("composeDeclaresApp")(function* (composePath, projectFolder) {
|
|
759
|
+
const { services } = yield* loadComposeServices(composePath, projectFolder);
|
|
760
|
+
return services.some(([, service]) => isPublicMarked(service) || buildsFromSource(service));
|
|
761
|
+
});
|
|
762
|
+
var readComposeContainers = import_effect5.Effect.fn("readComposeContainers")(function* (composePath, projectFolder) {
|
|
763
|
+
const fs = yield* import_platform2.FileSystem.FileSystem;
|
|
764
|
+
const pathSvc = yield* import_platform2.Path.Path;
|
|
765
|
+
const { relativePath, projectRoot, services } = yield* loadComposeServices(composePath, projectFolder);
|
|
766
|
+
const composeDirectory = import_node_path.posix.dirname(relativePath);
|
|
767
|
+
const warnings = [];
|
|
768
|
+
for (const [name] of services) {
|
|
769
|
+
if (!CONTAINER_NAME_PATTERN.test(name) || name === "localhost") {
|
|
770
|
+
return yield* new ContainerConfigError({
|
|
771
|
+
message: `Compose service '${name}' cannot be imported under that name. The service name becomes the hostname the function reaches it by, so it must be ${CONTAINER_NAME_RULES}. Rename the service to '${toContainerName(name)}' in '${relativePath}'.`,
|
|
772
|
+
containerName: name,
|
|
773
|
+
filePath: relativePath
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
const marked = services.filter(([, service]) => isPublicMarked(service)).map(([name]) => name);
|
|
778
|
+
const built = services.filter(([, service]) => buildsFromSource(service)).map(([name]) => name);
|
|
779
|
+
if (marked.length > 1) {
|
|
780
|
+
return yield* new ContainerConfigError({
|
|
781
|
+
message: `Compose file '${relativePath}' marks ${marked.map((name) => `'${name}'`).join(", ")} as public. One service serves HTTP: keep 'x-gigadrive: { public: true }' on that one only.`,
|
|
782
|
+
filePath: relativePath
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
const publicService = marked[0] ?? (built.length === 1 ? built[0] : void 0);
|
|
786
|
+
if (publicService === void 0) {
|
|
787
|
+
return yield* new ContainerConfigError({
|
|
788
|
+
message: built.length === 0 ? `Compose file '${relativePath}' has no service that builds from source, so it is unclear which service serves HTTP. Mark it with 'x-gigadrive: { public: true }'.` : `Compose file '${relativePath}' builds ${built.map((name) => `'${name}'`).join(", ")} from source, so it is unclear which service serves HTTP. Mark it with 'x-gigadrive: { public: true }'.`,
|
|
789
|
+
filePath: relativePath
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
if (COMPOSE_FILE_NAMES.includes(import_node_path.posix.basename(relativePath))) {
|
|
793
|
+
for (const overrideName of COMPOSE_OVERRIDE_FILE_NAMES) {
|
|
794
|
+
const overridePath = import_node_path.posix.join(composeDirectory, overrideName);
|
|
795
|
+
const overrideExists = yield* fs.exists(pathSvc.join(projectRoot, overridePath)).pipe(import_effect5.Effect.orElseSucceed(() => false));
|
|
796
|
+
if (overrideExists) {
|
|
797
|
+
warnings.push(
|
|
798
|
+
`Compose file '${relativePath}' has the override file '${overridePath}' next to it, which is not merged. Move its settings into '${relativePath}' or gigadrive.yaml.`
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
const dotEnv = yield* readInsideProject(
|
|
804
|
+
projectRoot,
|
|
805
|
+
import_node_path.posix.join(composeDirectory, ".env"),
|
|
806
|
+
`The .env file next to '${relativePath}'`,
|
|
807
|
+
{ filePath: relativePath }
|
|
808
|
+
);
|
|
809
|
+
const variables = import_effect5.Option.isSome(dotEnv) ? parseDotEnv(dotEnv.value) : {};
|
|
810
|
+
const missing = /* @__PURE__ */ new Set();
|
|
811
|
+
const containers = {};
|
|
812
|
+
for (const [name, rawService] of services) {
|
|
813
|
+
const isPublic = name === publicService;
|
|
814
|
+
const service = yield* import_effect5.Effect.try({
|
|
815
|
+
try: () => interpolateDeep(rawService, variables, missing, ""),
|
|
816
|
+
catch: (error) => new ContainerConfigError({
|
|
817
|
+
message: `Compose service '${name}' ${error instanceof InterpolationError ? error.message : "could not be interpolated."}`,
|
|
818
|
+
containerName: name,
|
|
819
|
+
filePath: relativePath
|
|
820
|
+
})
|
|
821
|
+
});
|
|
822
|
+
const container = {};
|
|
823
|
+
if (service.extends !== void 0) {
|
|
824
|
+
warnings.push(
|
|
825
|
+
`Compose service '${name}' uses 'extends', which is not supported. The service is deployed as written, without the settings it would inherit.`
|
|
826
|
+
);
|
|
827
|
+
}
|
|
828
|
+
if (typeof service.image === "string" && service.build === void 0) {
|
|
829
|
+
container.image = service.image;
|
|
830
|
+
} else if (typeof service.build === "string" || isRecord(service.build)) {
|
|
831
|
+
const build = typeof service.build === "string" ? { context: service.build } : service.build;
|
|
832
|
+
if (build.dockerfile_inline !== void 0) {
|
|
833
|
+
return yield* new ContainerConfigError({
|
|
834
|
+
message: `Compose service '${name}' uses build.dockerfile_inline, which is not supported. Commit the Dockerfile and point build.dockerfile at it.`,
|
|
835
|
+
containerName: name,
|
|
836
|
+
filePath: relativePath
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
const rawContext = typeof build.context === "string" ? build.context : ".";
|
|
840
|
+
const context = import_node_path.posix.isAbsolute(rawContext) ? rawContext : import_node_path.posix.join(composeDirectory, rawContext);
|
|
841
|
+
const args = Array.isArray(build.args) ? Object.fromEntries(
|
|
842
|
+
build.args.filter((item) => typeof item === "string" && item.includes("=")).map((item) => [item.slice(0, item.indexOf("=")), item.slice(item.indexOf("=") + 1)])
|
|
843
|
+
) : isRecord(build.args) ? Object.fromEntries(Object.entries(build.args).map(([key, item]) => [key, scalarToString(item) ?? ""])) : void 0;
|
|
844
|
+
container.build = {
|
|
845
|
+
context,
|
|
846
|
+
...typeof build.dockerfile === "string" && { dockerfile: build.dockerfile },
|
|
847
|
+
...typeof build.target === "string" && { target: build.target },
|
|
848
|
+
...args !== void 0 && Object.keys(args).length > 0 && { args }
|
|
849
|
+
};
|
|
850
|
+
} else {
|
|
851
|
+
return yield* new ContainerConfigError({
|
|
852
|
+
message: `Compose service '${name}' has neither an image nor a build.`,
|
|
853
|
+
containerName: name,
|
|
854
|
+
filePath: relativePath
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
if (!isPublic) container.sidecar = true;
|
|
858
|
+
const ports = [
|
|
859
|
+
...isPublic && Array.isArray(service.ports) ? service.ports : [],
|
|
860
|
+
...Array.isArray(service.expose) ? service.expose : [],
|
|
861
|
+
...!isPublic && Array.isArray(service.ports) ? service.ports : []
|
|
862
|
+
];
|
|
863
|
+
const port = ports.map(parseComposePort).find((value) => value !== void 0);
|
|
864
|
+
if (port !== void 0) container.port = port;
|
|
865
|
+
for (const key of ["entrypoint", "command"]) {
|
|
866
|
+
const value = service[key];
|
|
867
|
+
if (typeof value === "string" || isStringArray(value)) container[key] = value;
|
|
868
|
+
}
|
|
869
|
+
const environment = {};
|
|
870
|
+
const envFiles = (typeof service.env_file === "string" ? [service.env_file] : Array.isArray(service.env_file) ? service.env_file : []).flatMap(
|
|
871
|
+
(entry) => typeof entry === "string" ? [{ path: entry }] : isRecord(entry) && typeof entry.path === "string" ? [{ path: entry.path, ...typeof entry.required === "boolean" && { required: entry.required } }] : []
|
|
872
|
+
);
|
|
873
|
+
for (const envFile of envFiles) {
|
|
874
|
+
const envFilePath = import_node_path.posix.isAbsolute(envFile.path) ? void 0 : normalizeProjectPath(import_node_path.posix.join(composeDirectory, envFile.path));
|
|
875
|
+
const envContent = envFilePath === void 0 ? import_effect5.Option.none() : yield* readInsideProject(
|
|
876
|
+
projectRoot,
|
|
877
|
+
envFilePath,
|
|
878
|
+
`The env_file '${envFile.path}' of Compose service '${name}'`,
|
|
879
|
+
{ containerName: name, filePath: relativePath }
|
|
880
|
+
);
|
|
881
|
+
if (import_effect5.Option.isSome(envContent)) {
|
|
882
|
+
Object.assign(environment, parseDotEnv(envContent.value));
|
|
883
|
+
} else if (envFile.required === true) {
|
|
884
|
+
return yield* new ContainerConfigError({
|
|
885
|
+
message: `Compose service '${name}' requires env_file '${envFile.path}', which is not in the deployed source. Commit it, mark it 'required: false', or set those variables in the console.`,
|
|
886
|
+
containerName: name,
|
|
887
|
+
filePath: relativePath
|
|
888
|
+
});
|
|
889
|
+
} else if (envFile.required === void 0) {
|
|
890
|
+
warnings.push(
|
|
891
|
+
`Compose service '${name}' reads env_file '${envFile.path}', which is not in the deployed source. Set those variables in the console instead.`
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
Object.assign(environment, parseComposeEnvironment(name, service.environment, warnings));
|
|
896
|
+
if (Object.keys(environment).length > 0) container.env = environment;
|
|
897
|
+
if (typeof service.working_dir === "string") container.working_dir = service.working_dir;
|
|
898
|
+
if (typeof service.user === "string" || typeof service.user === "number") container.user = String(service.user);
|
|
899
|
+
const deploy = isRecord(service.deploy) ? service.deploy : {};
|
|
900
|
+
const resources = isRecord(deploy.resources) ? deploy.resources : {};
|
|
901
|
+
const limits = isRecord(resources.limits) ? resources.limits : {};
|
|
902
|
+
const memoryLimit = limits.memory ?? service.mem_limit;
|
|
903
|
+
if (memoryLimit !== void 0 && memoryLimit !== null) {
|
|
904
|
+
const memory = parseComposeMemory(memoryLimit);
|
|
905
|
+
if (memory === void 0) {
|
|
906
|
+
warnings.push(
|
|
907
|
+
`Compose service '${name}' sets the memory limit ${JSON.stringify(memoryLimit)}, which is not a size Docker accepts. The default is used instead.`
|
|
908
|
+
);
|
|
909
|
+
} else if (memory >= MIN_CONTAINER_MEMORY_MB && memory <= MAX_CONTAINER_MEMORY_MB) {
|
|
910
|
+
container.memory = memory;
|
|
911
|
+
} else if (memory > 0) {
|
|
912
|
+
warnings.push(
|
|
913
|
+
`Compose service '${name}' asks for ${memory} MB of memory, outside the supported ${MIN_CONTAINER_MEMORY_MB} to ${MAX_CONTAINER_MEMORY_MB} MB. The default is used instead.`
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
if (service.volumes !== void 0) {
|
|
918
|
+
warnings.push(
|
|
919
|
+
`Compose service '${name}' declares volumes. Containers on Gigadrive Network have no persistent volumes, so anything written there is lost when the instance stops.`
|
|
920
|
+
);
|
|
921
|
+
}
|
|
922
|
+
containers[name] = container;
|
|
923
|
+
}
|
|
924
|
+
if (missing.size > 0) {
|
|
925
|
+
warnings.push(
|
|
926
|
+
`Compose file '${relativePath}' uses ${[...missing].sort().join(", ")}, which ${missing.size === 1 ? "is" : "are"} not set. ${missing.size === 1 ? "It was" : "They were"} replaced with an empty string.`
|
|
927
|
+
);
|
|
928
|
+
}
|
|
929
|
+
return { containers, publicService, warnings };
|
|
930
|
+
});
|
|
931
|
+
|
|
184
932
|
// src/define-config.ts
|
|
185
933
|
var defineConfig = (config) => config;
|
|
186
934
|
|
|
935
|
+
// src/detection/detect-container-project.ts
|
|
936
|
+
var import_platform3 = require("@effect/platform");
|
|
937
|
+
var import_effect6 = require("effect");
|
|
938
|
+
|
|
939
|
+
// src/regions.ts
|
|
940
|
+
var REGION_DEFINITIONS = [
|
|
941
|
+
"us-east-1",
|
|
942
|
+
"us-east-2",
|
|
943
|
+
"us-west-1",
|
|
944
|
+
"us-west-2",
|
|
945
|
+
"ap-south-1",
|
|
946
|
+
"ap-northeast-3",
|
|
947
|
+
"ap-northeast-2",
|
|
948
|
+
"ap-southeast-1",
|
|
949
|
+
"ap-southeast-2",
|
|
950
|
+
"ap-northeast-1",
|
|
951
|
+
"ca-central-1",
|
|
952
|
+
"eu-central-1",
|
|
953
|
+
"eu-west-1",
|
|
954
|
+
"eu-west-2",
|
|
955
|
+
"eu-west-3",
|
|
956
|
+
"eu-north-1",
|
|
957
|
+
"sa-east-1"
|
|
958
|
+
];
|
|
959
|
+
var AVAILABLE_REGIONS = [...REGION_DEFINITIONS];
|
|
960
|
+
|
|
961
|
+
// src/detection/detect-container-project.ts
|
|
962
|
+
var detectContainerProject = import_effect6.Effect.fn("detectContainerProject")(function* (projectFolder) {
|
|
963
|
+
const fs = yield* import_platform3.FileSystem.FileSystem;
|
|
964
|
+
const pathSvc = yield* import_platform3.Path.Path;
|
|
965
|
+
const exists = (file) => fs.exists(pathSvc.join(projectFolder, file)).pipe(import_effect6.Effect.catchAll(() => import_effect6.Effect.succeed(false)));
|
|
966
|
+
let detection;
|
|
967
|
+
const warnings = [];
|
|
968
|
+
const composeFile = yield* import_effect6.Effect.findFirst(COMPOSE_FILE_NAMES, exists);
|
|
969
|
+
if (composeFile._tag === "Some" && (yield* composeDeclaresApp(composeFile.value, projectFolder))) {
|
|
970
|
+
const imported = yield* readComposeContainers(composeFile.value, projectFolder);
|
|
971
|
+
warnings.push(...imported.warnings);
|
|
972
|
+
detection = { kind: "compose", file: composeFile.value, containers: imported.containers };
|
|
973
|
+
} else if (yield* exists("Dockerfile")) {
|
|
974
|
+
detection = { kind: "dockerfile", file: "Dockerfile", containers: { app: { build: "." } } };
|
|
975
|
+
} else {
|
|
976
|
+
return void 0;
|
|
977
|
+
}
|
|
978
|
+
const {
|
|
979
|
+
entrypoints,
|
|
980
|
+
sidecars,
|
|
981
|
+
warnings: containerWarnings
|
|
982
|
+
} = yield* normalizeContainers(detection.containers, projectFolder);
|
|
983
|
+
const [publicContainer] = entrypoints;
|
|
984
|
+
const config = {
|
|
985
|
+
regions: [...AVAILABLE_REGIONS],
|
|
986
|
+
environmentVariables: {},
|
|
987
|
+
commands: [],
|
|
988
|
+
entrypoints,
|
|
989
|
+
...sidecars.length > 0 && { sidecars },
|
|
990
|
+
routes: publicContainer ? [
|
|
991
|
+
{
|
|
992
|
+
path: "/*",
|
|
993
|
+
destination: publicContainer.path,
|
|
994
|
+
handler: "SERVERLESS_FUNCTION_STREAMING",
|
|
995
|
+
methods: ["ANY"],
|
|
996
|
+
headers: {}
|
|
997
|
+
}
|
|
998
|
+
] : [],
|
|
999
|
+
warnings: [
|
|
1000
|
+
`Auto-detected ${detection.kind === "compose" ? "Docker Compose" : "Dockerfile"} project (${detection.file}). Create a gigadrive.yaml to customize.`,
|
|
1001
|
+
...warnings,
|
|
1002
|
+
...containerWarnings
|
|
1003
|
+
],
|
|
1004
|
+
errors: []
|
|
1005
|
+
};
|
|
1006
|
+
return { kind: detection.kind, file: detection.file, config };
|
|
1007
|
+
});
|
|
1008
|
+
|
|
187
1009
|
// src/detection/detect-framework.ts
|
|
188
|
-
var
|
|
189
|
-
var
|
|
1010
|
+
var import_platform11 = require("@effect/platform");
|
|
1011
|
+
var import_effect17 = require("effect");
|
|
190
1012
|
|
|
191
1013
|
// src/detection/detect-package-manager.ts
|
|
192
|
-
var
|
|
193
|
-
var
|
|
1014
|
+
var import_platform4 = require("@effect/platform");
|
|
1015
|
+
var import_effect7 = require("effect");
|
|
194
1016
|
var LOCKFILE_MAP = [
|
|
195
1017
|
{ files: ["bun.lockb", "bun.lock"], pm: "bun" },
|
|
196
1018
|
{ files: ["pnpm-lock.yaml"], pm: "pnpm" },
|
|
@@ -198,19 +1020,19 @@ var LOCKFILE_MAP = [
|
|
|
198
1020
|
{ files: ["package-lock.json"], pm: "npm" },
|
|
199
1021
|
{ files: ["composer.lock"], pm: "composer" }
|
|
200
1022
|
];
|
|
201
|
-
var detectPackageManager =
|
|
202
|
-
const fs = yield*
|
|
203
|
-
const pathService = yield*
|
|
1023
|
+
var detectPackageManager = import_effect7.Effect.fn("detectPackageManager")(function* (projectFolder) {
|
|
1024
|
+
const fs = yield* import_platform4.FileSystem.FileSystem;
|
|
1025
|
+
const pathService = yield* import_platform4.Path.Path;
|
|
204
1026
|
for (const { files, pm } of LOCKFILE_MAP) {
|
|
205
1027
|
for (const file of files) {
|
|
206
|
-
const exists = yield* fs.exists(pathService.join(projectFolder, file)).pipe(
|
|
1028
|
+
const exists = yield* fs.exists(pathService.join(projectFolder, file)).pipe(import_effect7.Effect.catchAll(() => import_effect7.Effect.succeed(false)));
|
|
207
1029
|
if (exists) {
|
|
208
|
-
yield*
|
|
1030
|
+
yield* import_effect7.Effect.logDebug(`Detected package manager: ${pm} (via ${file})`);
|
|
209
1031
|
return pm;
|
|
210
1032
|
}
|
|
211
1033
|
}
|
|
212
1034
|
}
|
|
213
|
-
yield*
|
|
1035
|
+
yield* import_effect7.Effect.logDebug("No lockfile found, defaulting to npm");
|
|
214
1036
|
return "npm";
|
|
215
1037
|
});
|
|
216
1038
|
|
|
@@ -236,8 +1058,8 @@ var astro = {
|
|
|
236
1058
|
};
|
|
237
1059
|
|
|
238
1060
|
// src/detection/frameworks/resolve-node-entrypoint.ts
|
|
239
|
-
var
|
|
240
|
-
var
|
|
1061
|
+
var import_platform5 = require("@effect/platform");
|
|
1062
|
+
var import_effect8 = require("effect");
|
|
241
1063
|
var SCRIPT_RUNNERS = /* @__PURE__ */ new Set(["node", "bun", "tsx", "ts-node"]);
|
|
242
1064
|
var COMMON_ENTRYPOINT_CANDIDATES = [
|
|
243
1065
|
"index.js",
|
|
@@ -253,11 +1075,11 @@ var COMMON_ENTRYPOINT_CANDIDATES = [
|
|
|
253
1075
|
"server.ts",
|
|
254
1076
|
"src/server.ts"
|
|
255
1077
|
];
|
|
256
|
-
var
|
|
1078
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null;
|
|
257
1079
|
var parsePackageJson = (content) => {
|
|
258
1080
|
try {
|
|
259
1081
|
const parsed = JSON.parse(content);
|
|
260
|
-
if (!
|
|
1082
|
+
if (!isRecord2(parsed)) return void 0;
|
|
261
1083
|
return parsed;
|
|
262
1084
|
} catch {
|
|
263
1085
|
return void 0;
|
|
@@ -285,14 +1107,14 @@ var applyEntrypoint = (defaults, entrypoint) => ({
|
|
|
285
1107
|
(route) => route.destination === defaults.entrypoint ? { ...route, destination: entrypoint } : route
|
|
286
1108
|
)
|
|
287
1109
|
});
|
|
288
|
-
var resolveNodeServerEntrypoint = (defaults, projectFolder) =>
|
|
289
|
-
const fs = yield*
|
|
290
|
-
const pathService = yield*
|
|
1110
|
+
var resolveNodeServerEntrypoint = (defaults, projectFolder) => import_effect8.Effect.gen(function* () {
|
|
1111
|
+
const fs = yield* import_platform5.FileSystem.FileSystem;
|
|
1112
|
+
const pathService = yield* import_platform5.Path.Path;
|
|
291
1113
|
const isFile = (relativePath) => fs.stat(pathService.join(projectFolder, relativePath)).pipe(
|
|
292
|
-
|
|
293
|
-
|
|
1114
|
+
import_effect8.Effect.map((info) => info.type === "File"),
|
|
1115
|
+
import_effect8.Effect.catchAll(() => import_effect8.Effect.succeed(false))
|
|
294
1116
|
);
|
|
295
|
-
const content = yield* fs.readFileString(pathService.join(projectFolder, "package.json")).pipe(
|
|
1117
|
+
const content = yield* fs.readFileString(pathService.join(projectFolder, "package.json")).pipe(import_effect8.Effect.catchAll(() => import_effect8.Effect.succeed(void 0)));
|
|
296
1118
|
const manifest = content ? parsePackageJson(content) : void 0;
|
|
297
1119
|
const startScript = typeof manifest?.scripts?.start === "string" ? manifest.scripts.start : void 0;
|
|
298
1120
|
const candidates = [
|
|
@@ -424,13 +1246,13 @@ var laravel = {
|
|
|
424
1246
|
};
|
|
425
1247
|
|
|
426
1248
|
// src/detection/frameworks/nestjs.ts
|
|
427
|
-
var
|
|
428
|
-
var
|
|
429
|
-
var
|
|
1249
|
+
var import_platform6 = require("@effect/platform");
|
|
1250
|
+
var import_effect9 = require("effect");
|
|
1251
|
+
var isRecord3 = (value) => typeof value === "object" && value !== null;
|
|
430
1252
|
var parseNestCliJson = (content) => {
|
|
431
1253
|
try {
|
|
432
1254
|
const parsed = JSON.parse(content);
|
|
433
|
-
if (!
|
|
1255
|
+
if (!isRecord3(parsed)) return void 0;
|
|
434
1256
|
return parsed;
|
|
435
1257
|
} catch {
|
|
436
1258
|
return void 0;
|
|
@@ -476,9 +1298,9 @@ var nestjs = {
|
|
|
476
1298
|
detectors: [{ matchPackage: "@nestjs/core" }],
|
|
477
1299
|
priority: 90,
|
|
478
1300
|
getDefaultConfig: () => createNestConfig("dist"),
|
|
479
|
-
refineDefaultConfig: (defaults, projectFolder) =>
|
|
480
|
-
const fs = yield*
|
|
481
|
-
const content = yield* fs.readFileString(`${projectFolder}/nest-cli.json`).pipe(
|
|
1301
|
+
refineDefaultConfig: (defaults, projectFolder) => import_effect9.Effect.gen(function* () {
|
|
1302
|
+
const fs = yield* import_platform6.FileSystem.FileSystem;
|
|
1303
|
+
const content = yield* fs.readFileString(`${projectFolder}/nest-cli.json`).pipe(import_effect9.Effect.catchAll(() => import_effect9.Effect.succeed(void 0)));
|
|
482
1304
|
if (!content) return defaults;
|
|
483
1305
|
const nestConfig = parseNestCliJson(content);
|
|
484
1306
|
const outputPath = nestConfig ? getProjectOutputPath(nestConfig) : void 0;
|
|
@@ -487,28 +1309,28 @@ var nestjs = {
|
|
|
487
1309
|
};
|
|
488
1310
|
|
|
489
1311
|
// src/detection/frameworks/nextjs.ts
|
|
490
|
-
var
|
|
491
|
-
var
|
|
1312
|
+
var import_platform8 = require("@effect/platform");
|
|
1313
|
+
var import_effect12 = require("effect");
|
|
492
1314
|
|
|
493
1315
|
// src/build-output-v3/get-default-path-map.ts
|
|
494
|
-
var
|
|
495
|
-
var
|
|
496
|
-
var getDefaultPathMap =
|
|
497
|
-
const fs = yield*
|
|
498
|
-
const pathService = yield*
|
|
1316
|
+
var import_platform7 = require("@effect/platform");
|
|
1317
|
+
var import_effect10 = require("effect");
|
|
1318
|
+
var getDefaultPathMap = import_effect10.Effect.fn("getDefaultPathMap")(function* (directory) {
|
|
1319
|
+
const fs = yield* import_platform7.FileSystem.FileSystem;
|
|
1320
|
+
const pathService = yield* import_platform7.Path.Path;
|
|
499
1321
|
const result = {};
|
|
500
|
-
const exists = yield* fs.exists(directory).pipe(
|
|
1322
|
+
const exists = yield* fs.exists(directory).pipe(import_effect10.Effect.catchAll(() => import_effect10.Effect.succeed(false)));
|
|
501
1323
|
if (!exists) {
|
|
502
1324
|
return result;
|
|
503
1325
|
}
|
|
504
1326
|
const MAX_DEPTH = 100;
|
|
505
|
-
const processDirectory = (currentPath, basePath = "", depth = 0) =>
|
|
1327
|
+
const processDirectory = (currentPath, basePath = "", depth = 0) => import_effect10.Effect.gen(function* () {
|
|
506
1328
|
if (depth > MAX_DEPTH) return;
|
|
507
|
-
const entries = yield* fs.readDirectory(currentPath).pipe(
|
|
1329
|
+
const entries = yield* fs.readDirectory(currentPath).pipe(import_effect10.Effect.catchAll(() => import_effect10.Effect.succeed([])));
|
|
508
1330
|
for (const name of entries) {
|
|
509
1331
|
const fullPath = pathService.join(currentPath, name);
|
|
510
1332
|
const relativePath = basePath ? pathService.join(basePath, name) : name;
|
|
511
|
-
const stat = yield* fs.stat(fullPath).pipe(
|
|
1333
|
+
const stat = yield* fs.stat(fullPath).pipe(import_effect10.Effect.catchAll(() => import_effect10.Effect.succeed(null)));
|
|
512
1334
|
if (!stat) continue;
|
|
513
1335
|
if (stat.type === "Directory") {
|
|
514
1336
|
yield* processDirectory(fullPath, relativePath, depth + 1);
|
|
@@ -525,291 +1347,269 @@ var getDefaultPathMap = import_effect7.Effect.fn("getDefaultPathMap")(function*
|
|
|
525
1347
|
var MAXIMUM_ENTRY_PAGE_PATHS = 50;
|
|
526
1348
|
|
|
527
1349
|
// src/nextjs-manifest.ts
|
|
528
|
-
var
|
|
529
|
-
var StringArraySchema =
|
|
530
|
-
var StringRecordSchema =
|
|
531
|
-
var JsonValueSchema =
|
|
532
|
-
() =>
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
1350
|
+
var import_effect11 = require("effect");
|
|
1351
|
+
var StringArraySchema = import_effect11.Schema.mutable(import_effect11.Schema.Array(import_effect11.Schema.String));
|
|
1352
|
+
var StringRecordSchema = import_effect11.Schema.mutable(import_effect11.Schema.Record({ key: import_effect11.Schema.String, value: import_effect11.Schema.String }));
|
|
1353
|
+
var JsonValueSchema = import_effect11.Schema.suspend(
|
|
1354
|
+
() => import_effect11.Schema.Union(
|
|
1355
|
+
import_effect11.Schema.Null,
|
|
1356
|
+
import_effect11.Schema.Boolean,
|
|
1357
|
+
import_effect11.Schema.Number,
|
|
1358
|
+
import_effect11.Schema.String,
|
|
1359
|
+
import_effect11.Schema.mutable(import_effect11.Schema.Array(JsonValueSchema)),
|
|
1360
|
+
import_effect11.Schema.mutable(import_effect11.Schema.Record({ key: import_effect11.Schema.String, value: JsonValueSchema }))
|
|
539
1361
|
)
|
|
540
1362
|
);
|
|
541
|
-
var ImageLocalPatternSchema =
|
|
542
|
-
|
|
543
|
-
pathname:
|
|
544
|
-
search:
|
|
1363
|
+
var ImageLocalPatternSchema = import_effect11.Schema.mutable(
|
|
1364
|
+
import_effect11.Schema.Struct({
|
|
1365
|
+
pathname: import_effect11.Schema.optional(import_effect11.Schema.String),
|
|
1366
|
+
search: import_effect11.Schema.optional(import_effect11.Schema.String)
|
|
545
1367
|
})
|
|
546
1368
|
);
|
|
547
|
-
var ImageRemotePatternSchema =
|
|
548
|
-
|
|
549
|
-
protocol:
|
|
550
|
-
hostname:
|
|
551
|
-
port:
|
|
552
|
-
pathname:
|
|
553
|
-
search:
|
|
1369
|
+
var ImageRemotePatternSchema = import_effect11.Schema.mutable(
|
|
1370
|
+
import_effect11.Schema.Struct({
|
|
1371
|
+
protocol: import_effect11.Schema.optional(import_effect11.Schema.Literal("http", "https")),
|
|
1372
|
+
hostname: import_effect11.Schema.String,
|
|
1373
|
+
port: import_effect11.Schema.optional(import_effect11.Schema.String),
|
|
1374
|
+
pathname: import_effect11.Schema.optional(import_effect11.Schema.String),
|
|
1375
|
+
search: import_effect11.Schema.optional(import_effect11.Schema.String)
|
|
554
1376
|
})
|
|
555
1377
|
);
|
|
556
|
-
var ImageVariantSchema =
|
|
557
|
-
|
|
558
|
-
width:
|
|
559
|
-
height:
|
|
560
|
-
quality:
|
|
561
|
-
format:
|
|
562
|
-
fit:
|
|
1378
|
+
var ImageVariantSchema = import_effect11.Schema.mutable(
|
|
1379
|
+
import_effect11.Schema.Struct({
|
|
1380
|
+
width: import_effect11.Schema.optional(import_effect11.Schema.Number),
|
|
1381
|
+
height: import_effect11.Schema.optional(import_effect11.Schema.Number),
|
|
1382
|
+
quality: import_effect11.Schema.optional(import_effect11.Schema.Number),
|
|
1383
|
+
format: import_effect11.Schema.optional(import_effect11.Schema.Literal("image/avif", "image/webp", "image/jpeg", "image/png")),
|
|
1384
|
+
fit: import_effect11.Schema.optional(import_effect11.Schema.Literal("contain", "cover", "fill", "inside", "outside"))
|
|
563
1385
|
})
|
|
564
1386
|
);
|
|
565
|
-
var PositiveIntSchema =
|
|
566
|
-
var ImagePolicySchema =
|
|
567
|
-
|
|
568
|
-
localPatterns:
|
|
569
|
-
remotePatterns:
|
|
570
|
-
widths:
|
|
571
|
-
heights:
|
|
572
|
-
qualities:
|
|
573
|
-
formats:
|
|
574
|
-
minimumCacheTTL:
|
|
575
|
-
dangerouslyAllowSVG:
|
|
576
|
-
contentSecurityPolicy:
|
|
577
|
-
contentDispositionType:
|
|
578
|
-
maximumRedirects:
|
|
579
|
-
maximumResponseBody:
|
|
580
|
-
variants:
|
|
1387
|
+
var PositiveIntSchema = import_effect11.Schema.Int.pipe(import_effect11.Schema.greaterThan(0));
|
|
1388
|
+
var ImagePolicySchema = import_effect11.Schema.mutable(
|
|
1389
|
+
import_effect11.Schema.Struct({
|
|
1390
|
+
localPatterns: import_effect11.Schema.mutable(import_effect11.Schema.Array(ImageLocalPatternSchema)),
|
|
1391
|
+
remotePatterns: import_effect11.Schema.mutable(import_effect11.Schema.Array(ImageRemotePatternSchema)),
|
|
1392
|
+
widths: import_effect11.Schema.mutable(import_effect11.Schema.Array(PositiveIntSchema)),
|
|
1393
|
+
heights: import_effect11.Schema.mutable(import_effect11.Schema.Array(PositiveIntSchema)),
|
|
1394
|
+
qualities: import_effect11.Schema.mutable(import_effect11.Schema.Array(import_effect11.Schema.Number.pipe(import_effect11.Schema.between(1, 100)))),
|
|
1395
|
+
formats: import_effect11.Schema.mutable(import_effect11.Schema.Array(import_effect11.Schema.Literal("image/avif", "image/webp", "image/jpeg", "image/png"))),
|
|
1396
|
+
minimumCacheTTL: import_effect11.Schema.Number,
|
|
1397
|
+
dangerouslyAllowSVG: import_effect11.Schema.Boolean,
|
|
1398
|
+
contentSecurityPolicy: import_effect11.Schema.String,
|
|
1399
|
+
contentDispositionType: import_effect11.Schema.Literal("inline", "attachment"),
|
|
1400
|
+
maximumRedirects: import_effect11.Schema.Number,
|
|
1401
|
+
maximumResponseBody: import_effect11.Schema.Number,
|
|
1402
|
+
variants: import_effect11.Schema.mutable(import_effect11.Schema.Record({ key: import_effect11.Schema.String, value: ImageVariantSchema }))
|
|
581
1403
|
})
|
|
582
1404
|
);
|
|
583
1405
|
var GigadriveNextPrerenderOutputFields = {
|
|
584
|
-
id:
|
|
585
|
-
type:
|
|
1406
|
+
id: import_effect11.Schema.String,
|
|
1407
|
+
type: import_effect11.Schema.Literal("PRERENDER"),
|
|
586
1408
|
pathname: UrlPathnameSchema,
|
|
587
|
-
route:
|
|
588
|
-
parentOutputId:
|
|
589
|
-
groupId:
|
|
590
|
-
pprChain:
|
|
591
|
-
parentFallbackMode:
|
|
592
|
-
fallback:
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
filePath:
|
|
596
|
-
initialStatus:
|
|
597
|
-
initialHeaders:
|
|
598
|
-
initialExpiration:
|
|
599
|
-
initialRevalidate:
|
|
600
|
-
postponedState:
|
|
1409
|
+
route: import_effect11.Schema.optional(UrlPathnameSchema),
|
|
1410
|
+
parentOutputId: import_effect11.Schema.String,
|
|
1411
|
+
groupId: import_effect11.Schema.Number,
|
|
1412
|
+
pprChain: import_effect11.Schema.optional(import_effect11.Schema.mutable(import_effect11.Schema.Struct({ headers: HttpSingleValueHeadersSchema }))),
|
|
1413
|
+
parentFallbackMode: import_effect11.Schema.optional(JsonValueSchema),
|
|
1414
|
+
fallback: import_effect11.Schema.optional(
|
|
1415
|
+
import_effect11.Schema.mutable(
|
|
1416
|
+
import_effect11.Schema.Struct({
|
|
1417
|
+
filePath: import_effect11.Schema.optional(PortableRelativePathSchema),
|
|
1418
|
+
initialStatus: import_effect11.Schema.optional(import_effect11.Schema.Int.pipe(import_effect11.Schema.between(100, 599))),
|
|
1419
|
+
initialHeaders: import_effect11.Schema.optional(HttpHeadersSchema),
|
|
1420
|
+
initialExpiration: import_effect11.Schema.optional(import_effect11.Schema.Number),
|
|
1421
|
+
initialRevalidate: import_effect11.Schema.optional(import_effect11.Schema.Union(import_effect11.Schema.Number, import_effect11.Schema.Literal(false))),
|
|
1422
|
+
postponedState: import_effect11.Schema.optional(import_effect11.Schema.String)
|
|
601
1423
|
})
|
|
602
1424
|
)
|
|
603
1425
|
),
|
|
604
|
-
config:
|
|
605
|
-
|
|
606
|
-
allowQuery:
|
|
607
|
-
allowHeader:
|
|
608
|
-
bypassFor:
|
|
609
|
-
renderingMode:
|
|
610
|
-
partialFallback:
|
|
611
|
-
bypassToken:
|
|
1426
|
+
config: import_effect11.Schema.mutable(
|
|
1427
|
+
import_effect11.Schema.Struct({
|
|
1428
|
+
allowQuery: import_effect11.Schema.optional(StringArraySchema),
|
|
1429
|
+
allowHeader: import_effect11.Schema.optional(StringArraySchema),
|
|
1430
|
+
bypassFor: import_effect11.Schema.optional(import_effect11.Schema.mutable(import_effect11.Schema.Array(JsonValueSchema))),
|
|
1431
|
+
renderingMode: import_effect11.Schema.optional(import_effect11.Schema.String),
|
|
1432
|
+
partialFallback: import_effect11.Schema.optional(import_effect11.Schema.Boolean),
|
|
1433
|
+
bypassToken: import_effect11.Schema.optional(import_effect11.Schema.String)
|
|
612
1434
|
})
|
|
613
1435
|
)
|
|
614
1436
|
};
|
|
615
|
-
var GigadriveNextPrerenderClassificationSchema =
|
|
616
|
-
routeType:
|
|
617
|
-
response:
|
|
618
|
-
compute:
|
|
619
|
-
htmlSize:
|
|
1437
|
+
var GigadriveNextPrerenderClassificationSchema = import_effect11.Schema.Struct({
|
|
1438
|
+
routeType: import_effect11.Schema.Literal("route", "fallback", "shell", "page"),
|
|
1439
|
+
response: import_effect11.Schema.Literal("empty", "initial", "complete"),
|
|
1440
|
+
compute: import_effect11.Schema.Literal("blocking", "resuming", "static"),
|
|
1441
|
+
htmlSize: import_effect11.Schema.optional(import_effect11.Schema.Number)
|
|
620
1442
|
});
|
|
621
|
-
var GigadriveNextPrerenderWithoutClassificationSchema =
|
|
622
|
-
routeType:
|
|
623
|
-
response:
|
|
624
|
-
compute:
|
|
625
|
-
htmlSize:
|
|
1443
|
+
var GigadriveNextPrerenderWithoutClassificationSchema = import_effect11.Schema.Struct({
|
|
1444
|
+
routeType: import_effect11.Schema.optional(import_effect11.Schema.Never),
|
|
1445
|
+
response: import_effect11.Schema.optional(import_effect11.Schema.Never),
|
|
1446
|
+
compute: import_effect11.Schema.optional(import_effect11.Schema.Never),
|
|
1447
|
+
htmlSize: import_effect11.Schema.optional(import_effect11.Schema.Never)
|
|
626
1448
|
});
|
|
627
|
-
var GigadriveNextPrerenderOutputSchema =
|
|
628
|
-
|
|
629
|
-
|
|
1449
|
+
var GigadriveNextPrerenderOutputSchema = import_effect11.Schema.Union(
|
|
1450
|
+
import_effect11.Schema.mutable(
|
|
1451
|
+
import_effect11.Schema.Struct({ ...GigadriveNextPrerenderOutputFields, ...GigadriveNextPrerenderClassificationSchema.fields })
|
|
630
1452
|
),
|
|
631
|
-
|
|
632
|
-
|
|
1453
|
+
import_effect11.Schema.mutable(
|
|
1454
|
+
import_effect11.Schema.Struct({
|
|
633
1455
|
...GigadriveNextPrerenderOutputFields,
|
|
634
1456
|
...GigadriveNextPrerenderWithoutClassificationSchema.fields
|
|
635
1457
|
})
|
|
636
1458
|
)
|
|
637
1459
|
);
|
|
638
|
-
var GigadriveNextStaticAssetPrefixSchema =
|
|
639
|
-
|
|
1460
|
+
var GigadriveNextStaticAssetPrefixSchema = import_effect11.Schema.mutable(
|
|
1461
|
+
import_effect11.Schema.Struct({
|
|
640
1462
|
sourceDir: PortableRelativePathSchema,
|
|
641
1463
|
urlPrefix: PortableRelativePathSchema,
|
|
642
|
-
immutable:
|
|
1464
|
+
immutable: import_effect11.Schema.Boolean
|
|
643
1465
|
})
|
|
644
1466
|
);
|
|
645
|
-
var GigadriveNextRouteConditionSchema =
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
type:
|
|
649
|
-
key:
|
|
650
|
-
value:
|
|
1467
|
+
var GigadriveNextRouteConditionSchema = import_effect11.Schema.Union(
|
|
1468
|
+
import_effect11.Schema.mutable(
|
|
1469
|
+
import_effect11.Schema.Struct({
|
|
1470
|
+
type: import_effect11.Schema.Literal("header", "cookie", "query"),
|
|
1471
|
+
key: import_effect11.Schema.String,
|
|
1472
|
+
value: import_effect11.Schema.optional(import_effect11.Schema.String)
|
|
651
1473
|
})
|
|
652
1474
|
),
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
type:
|
|
656
|
-
value:
|
|
1475
|
+
import_effect11.Schema.mutable(
|
|
1476
|
+
import_effect11.Schema.Struct({
|
|
1477
|
+
type: import_effect11.Schema.Literal("host"),
|
|
1478
|
+
value: import_effect11.Schema.String
|
|
657
1479
|
})
|
|
658
1480
|
)
|
|
659
1481
|
);
|
|
660
|
-
var GigadriveNextMiddlewareMatcherSchema =
|
|
661
|
-
|
|
662
|
-
source:
|
|
663
|
-
sourceRegex:
|
|
664
|
-
has:
|
|
665
|
-
missing:
|
|
1482
|
+
var GigadriveNextMiddlewareMatcherSchema = import_effect11.Schema.mutable(
|
|
1483
|
+
import_effect11.Schema.Struct({
|
|
1484
|
+
source: import_effect11.Schema.String,
|
|
1485
|
+
sourceRegex: import_effect11.Schema.String,
|
|
1486
|
+
has: import_effect11.Schema.optional(import_effect11.Schema.mutable(import_effect11.Schema.Array(GigadriveNextRouteConditionSchema))),
|
|
1487
|
+
missing: import_effect11.Schema.optional(import_effect11.Schema.mutable(import_effect11.Schema.Array(GigadriveNextRouteConditionSchema)))
|
|
666
1488
|
})
|
|
667
1489
|
);
|
|
668
|
-
var GigadriveNextMiddlewareDescriptorSchema =
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
present:
|
|
672
|
-
matchers:
|
|
1490
|
+
var GigadriveNextMiddlewareDescriptorSchema = import_effect11.Schema.Union(
|
|
1491
|
+
import_effect11.Schema.mutable(
|
|
1492
|
+
import_effect11.Schema.Struct({
|
|
1493
|
+
present: import_effect11.Schema.Literal(true),
|
|
1494
|
+
matchers: import_effect11.Schema.mutable(import_effect11.Schema.Array(GigadriveNextMiddlewareMatcherSchema))
|
|
673
1495
|
})
|
|
674
1496
|
),
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
present:
|
|
678
|
-
matchers:
|
|
1497
|
+
import_effect11.Schema.mutable(
|
|
1498
|
+
import_effect11.Schema.Struct({
|
|
1499
|
+
present: import_effect11.Schema.Literal(false),
|
|
1500
|
+
matchers: import_effect11.Schema.mutable(import_effect11.Schema.Tuple())
|
|
679
1501
|
})
|
|
680
1502
|
)
|
|
681
1503
|
);
|
|
682
|
-
var GigadriveNextServerDescriptorSchema =
|
|
683
|
-
|
|
684
|
-
maxDuration:
|
|
685
|
-
preferredRegion:
|
|
686
|
-
env:
|
|
1504
|
+
var GigadriveNextServerDescriptorSchema = import_effect11.Schema.mutable(
|
|
1505
|
+
import_effect11.Schema.Struct({
|
|
1506
|
+
maxDuration: import_effect11.Schema.optional(import_effect11.Schema.Number),
|
|
1507
|
+
preferredRegion: import_effect11.Schema.optional(import_effect11.Schema.Union(import_effect11.Schema.String, StringArraySchema)),
|
|
1508
|
+
env: import_effect11.Schema.optional(StringRecordSchema)
|
|
687
1509
|
})
|
|
688
1510
|
);
|
|
689
|
-
var PrerenderArraySchema =
|
|
690
|
-
var StaticAssetArraySchema =
|
|
691
|
-
var JsonValueArraySchema =
|
|
692
|
-
var GigadriveNextPrerenderSeedMethodsSchema =
|
|
693
|
-
|
|
1511
|
+
var PrerenderArraySchema = import_effect11.Schema.mutable(import_effect11.Schema.Array(GigadriveNextPrerenderOutputSchema));
|
|
1512
|
+
var StaticAssetArraySchema = import_effect11.Schema.mutable(import_effect11.Schema.Array(GigadriveNextStaticAssetPrefixSchema));
|
|
1513
|
+
var JsonValueArraySchema = import_effect11.Schema.mutable(import_effect11.Schema.Array(JsonValueSchema));
|
|
1514
|
+
var GigadriveNextPrerenderSeedMethodsSchema = import_effect11.Schema.mutable(
|
|
1515
|
+
import_effect11.Schema.Tuple(import_effect11.Schema.Literal("GET"), import_effect11.Schema.Literal("HEAD"))
|
|
694
1516
|
);
|
|
695
|
-
var GigadriveNextBuildManifestV1Schema =
|
|
696
|
-
|
|
697
|
-
version:
|
|
698
|
-
output:
|
|
1517
|
+
var GigadriveNextBuildManifestV1Schema = import_effect11.Schema.mutable(
|
|
1518
|
+
import_effect11.Schema.Struct({
|
|
1519
|
+
version: import_effect11.Schema.Literal(1),
|
|
1520
|
+
output: import_effect11.Schema.Literal("standalone", "export"),
|
|
699
1521
|
distDir: PortableRelativePathSchema,
|
|
700
1522
|
repoRootToProject: RepositoryRelativePathSchema,
|
|
701
|
-
nextVersion:
|
|
702
|
-
buildId:
|
|
1523
|
+
nextVersion: import_effect11.Schema.String,
|
|
1524
|
+
buildId: import_effect11.Schema.String
|
|
703
1525
|
})
|
|
704
1526
|
);
|
|
705
|
-
var GigadriveNextBuildManifestV2ExportSchema =
|
|
706
|
-
|
|
707
|
-
version:
|
|
708
|
-
mode:
|
|
1527
|
+
var GigadriveNextBuildManifestV2ExportSchema = import_effect11.Schema.mutable(
|
|
1528
|
+
import_effect11.Schema.Struct({
|
|
1529
|
+
version: import_effect11.Schema.Literal(2),
|
|
1530
|
+
mode: import_effect11.Schema.Literal("export"),
|
|
709
1531
|
distDir: PortableRelativePathSchema,
|
|
710
1532
|
repoRootToProject: RepositoryRelativePathSchema,
|
|
711
|
-
nextVersion:
|
|
712
|
-
buildId:
|
|
1533
|
+
nextVersion: import_effect11.Schema.String,
|
|
1534
|
+
buildId: import_effect11.Schema.String
|
|
713
1535
|
})
|
|
714
1536
|
);
|
|
715
|
-
var GigadriveNextBuildManifestV2StandaloneSchema =
|
|
716
|
-
|
|
717
|
-
version:
|
|
718
|
-
mode:
|
|
1537
|
+
var GigadriveNextBuildManifestV2StandaloneSchema = import_effect11.Schema.mutable(
|
|
1538
|
+
import_effect11.Schema.Struct({
|
|
1539
|
+
version: import_effect11.Schema.Literal(2),
|
|
1540
|
+
mode: import_effect11.Schema.Literal("standalone-v2"),
|
|
719
1541
|
distDir: PortableRelativePathSchema,
|
|
720
1542
|
repoRootToProject: RepositoryRelativePathSchema,
|
|
721
|
-
nextVersion:
|
|
722
|
-
buildId:
|
|
1543
|
+
nextVersion: import_effect11.Schema.String,
|
|
1544
|
+
buildId: import_effect11.Schema.String,
|
|
723
1545
|
server: GigadriveNextServerDescriptorSchema,
|
|
724
|
-
config:
|
|
725
|
-
|
|
726
|
-
basePath:
|
|
727
|
-
trailingSlash:
|
|
728
|
-
cacheComponents:
|
|
729
|
-
i18n:
|
|
730
|
-
images:
|
|
1546
|
+
config: import_effect11.Schema.mutable(
|
|
1547
|
+
import_effect11.Schema.Struct({
|
|
1548
|
+
basePath: import_effect11.Schema.String,
|
|
1549
|
+
trailingSlash: import_effect11.Schema.Boolean,
|
|
1550
|
+
cacheComponents: import_effect11.Schema.Boolean,
|
|
1551
|
+
i18n: import_effect11.Schema.optional(JsonValueSchema),
|
|
1552
|
+
images: import_effect11.Schema.optional(ImagePolicySchema)
|
|
731
1553
|
})
|
|
732
1554
|
),
|
|
733
|
-
routing:
|
|
734
|
-
|
|
1555
|
+
routing: import_effect11.Schema.mutable(
|
|
1556
|
+
import_effect11.Schema.Struct({
|
|
735
1557
|
beforeMiddleware: JsonValueArraySchema,
|
|
736
1558
|
beforeFiles: JsonValueArraySchema,
|
|
737
1559
|
afterFiles: JsonValueArraySchema,
|
|
738
1560
|
dynamicRoutes: JsonValueArraySchema,
|
|
739
1561
|
onMatch: JsonValueArraySchema,
|
|
740
1562
|
fallback: JsonValueArraySchema,
|
|
741
|
-
shouldNormalizeNextData:
|
|
1563
|
+
shouldNormalizeNextData: import_effect11.Schema.Boolean,
|
|
742
1564
|
rsc: JsonValueSchema
|
|
743
1565
|
})
|
|
744
1566
|
),
|
|
745
|
-
outputs:
|
|
746
|
-
|
|
1567
|
+
outputs: import_effect11.Schema.mutable(
|
|
1568
|
+
import_effect11.Schema.Struct({
|
|
747
1569
|
prerenders: PrerenderArraySchema,
|
|
748
|
-
prerenderManifest:
|
|
749
|
-
assetManifest:
|
|
750
|
-
entryPagePaths:
|
|
1570
|
+
prerenderManifest: import_effect11.Schema.optional(PortableRelativePathSchema),
|
|
1571
|
+
assetManifest: import_effect11.Schema.optional(PortableRelativePathSchema),
|
|
1572
|
+
entryPagePaths: import_effect11.Schema.optional(import_effect11.Schema.mutable(import_effect11.Schema.Array(UrlPathnameSchema))),
|
|
751
1573
|
staticAssets: StaticAssetArraySchema,
|
|
752
|
-
middleware:
|
|
1574
|
+
middleware: import_effect11.Schema.optional(GigadriveNextMiddlewareDescriptorSchema)
|
|
753
1575
|
})
|
|
754
1576
|
)
|
|
755
1577
|
})
|
|
756
1578
|
);
|
|
757
|
-
var GigadriveNextBuildManifestSchema =
|
|
1579
|
+
var GigadriveNextBuildManifestSchema = import_effect11.Schema.Union(
|
|
758
1580
|
GigadriveNextBuildManifestV1Schema,
|
|
759
1581
|
GigadriveNextBuildManifestV2ExportSchema,
|
|
760
1582
|
GigadriveNextBuildManifestV2StandaloneSchema
|
|
761
1583
|
);
|
|
762
|
-
var GigadriveNextPrerenderManifestV1Schema =
|
|
763
|
-
|
|
764
|
-
version:
|
|
765
|
-
seedMethods:
|
|
1584
|
+
var GigadriveNextPrerenderManifestV1Schema = import_effect11.Schema.mutable(
|
|
1585
|
+
import_effect11.Schema.Struct({
|
|
1586
|
+
version: import_effect11.Schema.Literal(1),
|
|
1587
|
+
seedMethods: import_effect11.Schema.optional(GigadriveNextPrerenderSeedMethodsSchema),
|
|
766
1588
|
prerenders: PrerenderArraySchema
|
|
767
1589
|
})
|
|
768
1590
|
);
|
|
769
1591
|
var parseGigadriveNextBuildManifest = (content) => decodeJson(GigadriveNextBuildManifestSchema, content);
|
|
770
1592
|
var parseGigadriveNextPrerenderManifest = (content) => decodeJson(GigadriveNextPrerenderManifestV1Schema, content);
|
|
771
1593
|
|
|
772
|
-
// src/regions.ts
|
|
773
|
-
var REGION_DEFINITIONS = [
|
|
774
|
-
"us-east-1",
|
|
775
|
-
"us-east-2",
|
|
776
|
-
"us-west-1",
|
|
777
|
-
"us-west-2",
|
|
778
|
-
"ap-south-1",
|
|
779
|
-
"ap-northeast-3",
|
|
780
|
-
"ap-northeast-2",
|
|
781
|
-
"ap-southeast-1",
|
|
782
|
-
"ap-southeast-2",
|
|
783
|
-
"ap-northeast-1",
|
|
784
|
-
"ca-central-1",
|
|
785
|
-
"eu-central-1",
|
|
786
|
-
"eu-west-1",
|
|
787
|
-
"eu-west-2",
|
|
788
|
-
"eu-west-3",
|
|
789
|
-
"eu-north-1",
|
|
790
|
-
"sa-east-1"
|
|
791
|
-
];
|
|
792
|
-
var AVAILABLE_REGIONS = [...REGION_DEFINITIONS];
|
|
793
|
-
|
|
794
1594
|
// src/detection/frameworks/nextjs.ts
|
|
795
1595
|
var toPortablePath = (value) => value.replaceAll("\\", "/");
|
|
796
1596
|
var STANDALONE_SERVER_MEMORY_MB = 1024;
|
|
797
|
-
var resolveStandaloneServer =
|
|
798
|
-
const fs = yield*
|
|
799
|
-
const pathService = yield*
|
|
1597
|
+
var resolveStandaloneServer = import_effect12.Effect.fn("nextjs.resolveStandaloneServer")(function* (projectFolder, distDir, repoRootToProject) {
|
|
1598
|
+
const fs = yield* import_platform8.FileSystem.FileSystem;
|
|
1599
|
+
const pathService = yield* import_platform8.Path.Path;
|
|
800
1600
|
const standaloneRoot = pathService.join(projectFolder, distDir, "standalone");
|
|
801
1601
|
const monorepoServer = pathService.join(standaloneRoot, repoRootToProject, "server.js");
|
|
802
1602
|
const rootServer = pathService.join(standaloneRoot, "server.js");
|
|
803
|
-
const monorepoServerExists = yield* fs.exists(monorepoServer).pipe(
|
|
1603
|
+
const monorepoServerExists = yield* fs.exists(monorepoServer).pipe(import_effect12.Effect.catchAll(() => import_effect12.Effect.succeed(false)));
|
|
804
1604
|
const serverPath = monorepoServerExists ? monorepoServer : rootServer;
|
|
805
|
-
const serverExists = yield* fs.exists(serverPath).pipe(
|
|
1605
|
+
const serverExists = yield* fs.exists(serverPath).pipe(import_effect12.Effect.catchAll(() => import_effect12.Effect.succeed(false)));
|
|
806
1606
|
if (!serverExists) return void 0;
|
|
807
1607
|
const serverDirectory = pathService.dirname(serverPath);
|
|
808
1608
|
const entrypoint = toPortablePath(pathService.relative(standaloneRoot, serverPath));
|
|
809
1609
|
return { standaloneRoot, serverDirectory, entrypoint };
|
|
810
1610
|
});
|
|
811
|
-
var buildStandalonePublicAssets =
|
|
812
|
-
const pathService = yield*
|
|
1611
|
+
var buildStandalonePublicAssets = import_effect12.Effect.fn("nextjs.buildStandalonePublicAssets")(function* (projectFolder, standaloneRoot, serverDirectory) {
|
|
1612
|
+
const pathService = yield* import_platform8.Path.Path;
|
|
813
1613
|
const publicFiles = yield* getDefaultPathMap(pathService.join(projectFolder, "public"));
|
|
814
1614
|
const assetPaths = [];
|
|
815
1615
|
const assetOverrides = {};
|
|
@@ -825,8 +1625,8 @@ var buildStandalonePublicAssets = import_effect9.Effect.fn("nextjs.buildStandalo
|
|
|
825
1625
|
}
|
|
826
1626
|
return { assetPaths, assetOverrides, filePathMap };
|
|
827
1627
|
});
|
|
828
|
-
var createStaticExportConfig =
|
|
829
|
-
const pathService = yield*
|
|
1628
|
+
var createStaticExportConfig = import_effect12.Effect.fn("nextjs.createStaticExportConfig")(function* (defaults, projectFolder) {
|
|
1629
|
+
const pathService = yield* import_platform8.Path.Path;
|
|
830
1630
|
const outputDirectory = pathService.join(projectFolder, "out");
|
|
831
1631
|
const files = yield* getDefaultPathMap(outputDirectory);
|
|
832
1632
|
const assetPaths = [];
|
|
@@ -849,8 +1649,8 @@ var createStaticExportConfig = import_effect9.Effect.fn("nextjs.createStaticExpo
|
|
|
849
1649
|
package: void 0
|
|
850
1650
|
};
|
|
851
1651
|
});
|
|
852
|
-
var createStandaloneConfig =
|
|
853
|
-
const pathService = yield*
|
|
1652
|
+
var createStandaloneConfig = import_effect12.Effect.fn("nextjs.createStandaloneConfig")(function* (defaults, projectFolder, manifest) {
|
|
1653
|
+
const pathService = yield* import_platform8.Path.Path;
|
|
854
1654
|
const resolved = yield* resolveStandaloneServer(projectFolder, manifest.distDir, manifest.repoRootToProject);
|
|
855
1655
|
if (!resolved) return defaults;
|
|
856
1656
|
const { standaloneRoot, serverDirectory, entrypoint } = resolved;
|
|
@@ -883,7 +1683,7 @@ var createStandaloneConfig = import_effect9.Effect.fn("nextjs.createStandaloneCo
|
|
|
883
1683
|
}
|
|
884
1684
|
};
|
|
885
1685
|
});
|
|
886
|
-
var createStandaloneV2Config =
|
|
1686
|
+
var createStandaloneV2Config = import_effect12.Effect.fn("nextjs.createStandaloneV2Config")(function* (defaults, projectFolder, manifest) {
|
|
887
1687
|
const resolved = yield* resolveStandaloneServer(projectFolder, manifest.distDir, manifest.repoRootToProject);
|
|
888
1688
|
if (!resolved) return defaults;
|
|
889
1689
|
const { standaloneRoot, serverDirectory, entrypoint } = resolved;
|
|
@@ -991,9 +1791,9 @@ var nextjs = {
|
|
|
991
1791
|
routes: [{ source: "/*", destination: ".next/standalone/server.js" }],
|
|
992
1792
|
environmentVariables: { NODE_ENV: "production" }
|
|
993
1793
|
}),
|
|
994
|
-
refineDefaultConfig: (defaults, projectFolder) =>
|
|
995
|
-
const fs = yield*
|
|
996
|
-
const manifestContent = yield* fs.readFileString(`${projectFolder}/.gigadrive/nextjs.json`).pipe(
|
|
1794
|
+
refineDefaultConfig: (defaults, projectFolder) => import_effect12.Effect.gen(function* () {
|
|
1795
|
+
const fs = yield* import_platform8.FileSystem.FileSystem;
|
|
1796
|
+
const manifestContent = yield* fs.readFileString(`${projectFolder}/.gigadrive/nextjs.json`).pipe(import_effect12.Effect.catchAll(() => import_effect12.Effect.succeed(void 0)));
|
|
997
1797
|
const manifest = manifestContent ? parseGigadriveNextBuildManifest(manifestContent) : void 0;
|
|
998
1798
|
if (!manifest) return defaults;
|
|
999
1799
|
if (manifest.version === 2) {
|
|
@@ -1004,8 +1804,8 @@ var nextjs = {
|
|
|
1004
1804
|
};
|
|
1005
1805
|
|
|
1006
1806
|
// src/detection/frameworks/nuxt.ts
|
|
1007
|
-
var
|
|
1008
|
-
var
|
|
1807
|
+
var import_platform9 = require("@effect/platform");
|
|
1808
|
+
var import_effect13 = require("effect");
|
|
1009
1809
|
var isVercelBuildOutputV3 = (content) => {
|
|
1010
1810
|
try {
|
|
1011
1811
|
const config = JSON.parse(content);
|
|
@@ -1032,9 +1832,9 @@ var nuxt = {
|
|
|
1032
1832
|
routes: [{ source: "/*", destination: ".output/server/index.mjs" }],
|
|
1033
1833
|
environmentVariables: { NODE_ENV: "production", NITRO_PRESET: "node-server" }
|
|
1034
1834
|
}),
|
|
1035
|
-
refineDefaultConfig: (defaults, projectFolder) =>
|
|
1036
|
-
const fs = yield*
|
|
1037
|
-
const buildOutputConfig = yield* fs.readFileString(`${projectFolder}/.vercel/output/config.json`).pipe(
|
|
1835
|
+
refineDefaultConfig: (defaults, projectFolder) => import_effect13.Effect.gen(function* () {
|
|
1836
|
+
const fs = yield* import_platform9.FileSystem.FileSystem;
|
|
1837
|
+
const buildOutputConfig = yield* fs.readFileString(`${projectFolder}/.vercel/output/config.json`).pipe(import_effect13.Effect.catchAll(() => import_effect13.Effect.succeed(void 0)));
|
|
1038
1838
|
if (!buildOutputConfig || !isVercelBuildOutputV3(buildOutputConfig)) {
|
|
1039
1839
|
return defaults;
|
|
1040
1840
|
}
|
|
@@ -1157,7 +1957,7 @@ var FRAMEWORK_DEFINITIONS = [
|
|
|
1157
1957
|
].sort((a, b) => b.priority - a.priority);
|
|
1158
1958
|
|
|
1159
1959
|
// src/detection/generate-config.ts
|
|
1160
|
-
var
|
|
1960
|
+
var import_effect14 = require("effect");
|
|
1161
1961
|
var getInstallCommand = (pm) => {
|
|
1162
1962
|
switch (pm) {
|
|
1163
1963
|
case "bun":
|
|
@@ -1173,11 +1973,11 @@ var getInstallCommand = (pm) => {
|
|
|
1173
1973
|
return "npm install";
|
|
1174
1974
|
}
|
|
1175
1975
|
};
|
|
1176
|
-
var generateConfig =
|
|
1976
|
+
var generateConfig = import_effect14.Effect.fn("generateConfig")(function* (framework, packageManager, projectFolder, refinedDefaults) {
|
|
1177
1977
|
const defaults = refinedDefaults ?? framework.getDefaultConfig(packageManager);
|
|
1178
1978
|
const installCmd = defaults.installCommand ?? getInstallCommand(packageManager);
|
|
1179
1979
|
const commands = [installCmd, ...defaults.commands];
|
|
1180
|
-
yield*
|
|
1980
|
+
yield* import_effect14.Effect.logDebug(`Generating config for ${framework.name}`, {
|
|
1181
1981
|
runtime: defaults.runtime,
|
|
1182
1982
|
entrypoint: defaults.entrypoint,
|
|
1183
1983
|
commands
|
|
@@ -1242,31 +2042,31 @@ var generateConfig = import_effect11.Effect.fn("generateConfig")(function* (fram
|
|
|
1242
2042
|
});
|
|
1243
2043
|
|
|
1244
2044
|
// src/detection/read-dependencies.ts
|
|
1245
|
-
var
|
|
1246
|
-
var
|
|
2045
|
+
var import_platform10 = require("@effect/platform");
|
|
2046
|
+
var import_effect16 = require("effect");
|
|
1247
2047
|
|
|
1248
2048
|
// src/detection/types.ts
|
|
1249
|
-
var
|
|
1250
|
-
var ManifestNotFoundError = class extends
|
|
1251
|
-
message:
|
|
1252
|
-
filePath:
|
|
2049
|
+
var import_effect15 = require("effect");
|
|
2050
|
+
var ManifestNotFoundError = class extends import_effect15.Schema.TaggedError()("ManifestNotFoundError", {
|
|
2051
|
+
message: import_effect15.Schema.String,
|
|
2052
|
+
filePath: import_effect15.Schema.String
|
|
1253
2053
|
}) {
|
|
1254
2054
|
};
|
|
1255
|
-
var ManifestReadError = class extends
|
|
1256
|
-
message:
|
|
1257
|
-
filePath:
|
|
2055
|
+
var ManifestReadError = class extends import_effect15.Schema.TaggedError()("ManifestReadError", {
|
|
2056
|
+
message: import_effect15.Schema.String,
|
|
2057
|
+
filePath: import_effect15.Schema.String
|
|
1258
2058
|
}) {
|
|
1259
2059
|
};
|
|
1260
|
-
var ManifestParseError = class extends
|
|
1261
|
-
message:
|
|
1262
|
-
filePath:
|
|
2060
|
+
var ManifestParseError = class extends import_effect15.Schema.TaggedError()("ManifestParseError", {
|
|
2061
|
+
message: import_effect15.Schema.String,
|
|
2062
|
+
filePath: import_effect15.Schema.String
|
|
1263
2063
|
}) {
|
|
1264
2064
|
};
|
|
1265
|
-
var FrameworkNotDetectedError = class extends
|
|
2065
|
+
var FrameworkNotDetectedError = class extends import_effect15.Schema.TaggedError()(
|
|
1266
2066
|
"FrameworkNotDetectedError",
|
|
1267
2067
|
{
|
|
1268
|
-
message:
|
|
1269
|
-
directory:
|
|
2068
|
+
message: import_effect15.Schema.String,
|
|
2069
|
+
directory: import_effect15.Schema.String
|
|
1270
2070
|
}
|
|
1271
2071
|
) {
|
|
1272
2072
|
};
|
|
@@ -1276,25 +2076,25 @@ var MANIFEST_CONFIG = {
|
|
|
1276
2076
|
node: { file: "package.json", depKeys: ["dependencies", "devDependencies"] },
|
|
1277
2077
|
php: { file: "composer.json", depKeys: ["require", "require-dev"] }
|
|
1278
2078
|
};
|
|
1279
|
-
var readManifest =
|
|
1280
|
-
const fs = yield*
|
|
1281
|
-
const exists = yield* fs.exists(filePath).pipe(
|
|
2079
|
+
var readManifest = import_effect16.Effect.fn("readManifest")(function* (filePath) {
|
|
2080
|
+
const fs = yield* import_platform10.FileSystem.FileSystem;
|
|
2081
|
+
const exists = yield* fs.exists(filePath).pipe(import_effect16.Effect.catchAll(() => import_effect16.Effect.succeed(false)));
|
|
1282
2082
|
if (!exists) {
|
|
1283
|
-
return yield*
|
|
2083
|
+
return yield* import_effect16.Effect.fail(new ManifestNotFoundError({ message: "Manifest not found", filePath }));
|
|
1284
2084
|
}
|
|
1285
|
-
const content = yield* fs.readFileString(filePath).pipe(
|
|
1286
|
-
const parsed = yield*
|
|
2085
|
+
const content = yield* fs.readFileString(filePath).pipe(import_effect16.Effect.mapError(() => new ManifestReadError({ message: "Failed to read manifest", filePath })));
|
|
2086
|
+
const parsed = yield* import_effect16.Effect.try({
|
|
1287
2087
|
try: () => JSON.parse(content),
|
|
1288
2088
|
catch: () => new ManifestParseError({ message: "Failed to parse manifest JSON", filePath })
|
|
1289
2089
|
});
|
|
1290
2090
|
return parsed;
|
|
1291
2091
|
});
|
|
1292
|
-
var readDependencies =
|
|
1293
|
-
const pathService = yield*
|
|
2092
|
+
var readDependencies = import_effect16.Effect.fn("readDependencies")(function* (projectFolder, language) {
|
|
2093
|
+
const pathService = yield* import_platform10.Path.Path;
|
|
1294
2094
|
const config = MANIFEST_CONFIG[language];
|
|
1295
2095
|
const filePath = pathService.join(projectFolder, config.file);
|
|
1296
2096
|
const manifest = yield* readManifest(filePath).pipe(
|
|
1297
|
-
|
|
2097
|
+
import_effect16.Effect.catchTag("ManifestNotFoundError", () => import_effect16.Effect.succeed(null))
|
|
1298
2098
|
);
|
|
1299
2099
|
if (!manifest) {
|
|
1300
2100
|
return /* @__PURE__ */ new Set();
|
|
@@ -1312,9 +2112,9 @@ var readDependencies = import_effect13.Effect.fn("readDependencies")(function* (
|
|
|
1312
2112
|
});
|
|
1313
2113
|
|
|
1314
2114
|
// src/detection/detect-framework.ts
|
|
1315
|
-
var matchesDetectionItem =
|
|
1316
|
-
const fs = yield*
|
|
1317
|
-
const pathService = yield*
|
|
2115
|
+
var matchesDetectionItem = import_effect17.Effect.fn("matchesDetectionItem")(function* (item, projectFolder, framework, cachedReadDeps) {
|
|
2116
|
+
const fs = yield* import_platform11.FileSystem.FileSystem;
|
|
2117
|
+
const pathService = yield* import_platform11.Path.Path;
|
|
1318
2118
|
if (item.matchPackage != null) {
|
|
1319
2119
|
const deps = yield* cachedReadDeps(`${projectFolder}\0${framework.language}`);
|
|
1320
2120
|
if (!deps.has(item.matchPackage)) {
|
|
@@ -1323,12 +2123,12 @@ var matchesDetectionItem = import_effect14.Effect.fn("matchesDetectionItem")(fun
|
|
|
1323
2123
|
}
|
|
1324
2124
|
if (item.path != null) {
|
|
1325
2125
|
const filePath = pathService.join(projectFolder, item.path);
|
|
1326
|
-
const exists = yield* fs.exists(filePath).pipe(
|
|
2126
|
+
const exists = yield* fs.exists(filePath).pipe(import_effect17.Effect.catchAll(() => import_effect17.Effect.succeed(false)));
|
|
1327
2127
|
if (!exists) {
|
|
1328
2128
|
return false;
|
|
1329
2129
|
}
|
|
1330
2130
|
if (item.matchContent != null) {
|
|
1331
|
-
const content = yield* fs.readFileString(filePath).pipe(
|
|
2131
|
+
const content = yield* fs.readFileString(filePath).pipe(import_effect17.Effect.catchAll(() => import_effect17.Effect.succeed("")));
|
|
1332
2132
|
let regexMatch = false;
|
|
1333
2133
|
try {
|
|
1334
2134
|
regexMatch = new RegExp(item.matchContent).test(content);
|
|
@@ -1341,7 +2141,7 @@ var matchesDetectionItem = import_effect14.Effect.fn("matchesDetectionItem")(fun
|
|
|
1341
2141
|
}
|
|
1342
2142
|
return true;
|
|
1343
2143
|
});
|
|
1344
|
-
var matchesFramework =
|
|
2144
|
+
var matchesFramework = import_effect17.Effect.fn("matchesFramework")(function* (framework, projectFolder, cachedReadDeps) {
|
|
1345
2145
|
for (const detector of framework.detectors) {
|
|
1346
2146
|
const matches = yield* matchesDetectionItem(detector, projectFolder, framework, cachedReadDeps);
|
|
1347
2147
|
if (!matches) {
|
|
@@ -1350,9 +2150,9 @@ var matchesFramework = import_effect14.Effect.fn("matchesFramework")(function* (
|
|
|
1350
2150
|
}
|
|
1351
2151
|
return true;
|
|
1352
2152
|
});
|
|
1353
|
-
var detectFramework =
|
|
1354
|
-
yield*
|
|
1355
|
-
const cachedReadDeps = yield*
|
|
2153
|
+
var detectFramework = import_effect17.Effect.fn("detectFramework")(function* (projectFolder) {
|
|
2154
|
+
yield* import_effect17.Effect.logDebug(`Detecting framework in ${projectFolder}`);
|
|
2155
|
+
const cachedReadDeps = yield* import_effect17.Effect.cachedFunction((key) => {
|
|
1356
2156
|
const sepIndex = key.lastIndexOf("\0");
|
|
1357
2157
|
const folder = key.slice(0, sepIndex);
|
|
1358
2158
|
const language = key.slice(sepIndex + 1);
|
|
@@ -1361,7 +2161,7 @@ var detectFramework = import_effect14.Effect.fn("detectFramework")(function* (pr
|
|
|
1361
2161
|
for (const framework of FRAMEWORK_DEFINITIONS) {
|
|
1362
2162
|
const matches = yield* matchesFramework(framework, projectFolder, cachedReadDeps);
|
|
1363
2163
|
if (matches) {
|
|
1364
|
-
yield*
|
|
2164
|
+
yield* import_effect17.Effect.log(`Detected framework: ${framework.name}`, { slug: framework.slug });
|
|
1365
2165
|
const detectedPackageManager = yield* detectPackageManager(projectFolder);
|
|
1366
2166
|
const packageManager = framework.language === "php" ? "composer" : detectedPackageManager;
|
|
1367
2167
|
const defaults = framework.getDefaultConfig(packageManager);
|
|
@@ -1370,7 +2170,7 @@ var detectFramework = import_effect14.Effect.fn("detectFramework")(function* (pr
|
|
|
1370
2170
|
return { framework, packageManager, config };
|
|
1371
2171
|
}
|
|
1372
2172
|
}
|
|
1373
|
-
return yield*
|
|
2173
|
+
return yield* import_effect17.Effect.fail(
|
|
1374
2174
|
new FrameworkNotDetectedError({
|
|
1375
2175
|
message: `No framework detected in project directory`,
|
|
1376
2176
|
directory: projectFolder
|
|
@@ -1379,15 +2179,22 @@ var detectFramework = import_effect14.Effect.fn("detectFramework")(function* (pr
|
|
|
1379
2179
|
});
|
|
1380
2180
|
|
|
1381
2181
|
// src/detection/merge-config.ts
|
|
1382
|
-
var
|
|
1383
|
-
var mergeWithFrameworkDefaults =
|
|
1384
|
-
yield*
|
|
2182
|
+
var import_effect18 = require("effect");
|
|
2183
|
+
var mergeWithFrameworkDefaults = import_effect18.Effect.fn("mergeWithFrameworkDefaults")(function* (userConfig, frameworkConfig) {
|
|
2184
|
+
yield* import_effect18.Effect.logDebug("Merging user config with framework defaults");
|
|
1385
2185
|
const userHasAssets = (userConfig.assets?.paths?.length ?? 0) > 0 || (userConfig.assets?.prefixes?.length ?? 0) > 0 || (userConfig.assets?.manifests?.length ?? 0) > 0;
|
|
2186
|
+
const isContainer = (entrypoint) => entrypoint.runtime === CONTAINER_RUNTIME;
|
|
2187
|
+
const userFileFunctions = userConfig.entrypoints.filter((entrypoint) => !isContainer(entrypoint));
|
|
2188
|
+
const containerPaths = new Set(userConfig.entrypoints.filter(isContainer).map((entrypoint) => entrypoint.path));
|
|
2189
|
+
const targetsContainer = (route) => containerPaths.has(route.destination.replace(/^\/+/, ""));
|
|
1386
2190
|
const merged = {
|
|
1387
2191
|
regions: userConfig.regions,
|
|
1388
2192
|
commands: userConfig.commands.length > 0 ? userConfig.commands : frameworkConfig.commands,
|
|
1389
|
-
entrypoints:
|
|
1390
|
-
|
|
2193
|
+
entrypoints: [
|
|
2194
|
+
...userFileFunctions.length > 0 ? userFileFunctions : frameworkConfig.entrypoints,
|
|
2195
|
+
...userConfig.entrypoints.filter(isContainer)
|
|
2196
|
+
],
|
|
2197
|
+
routes: containerPaths.size > 0 && userConfig.routes.every(targetsContainer) ? [...userConfig.routes, ...frameworkConfig.routes] : userConfig.routes.length > 0 ? userConfig.routes : frameworkConfig.routes,
|
|
1391
2198
|
assets: userHasAssets ? userConfig.assets : frameworkConfig.assets,
|
|
1392
2199
|
environmentVariables: {
|
|
1393
2200
|
...frameworkConfig.environmentVariables,
|
|
@@ -1395,6 +2202,7 @@ var mergeWithFrameworkDefaults = import_effect15.Effect.fn("mergeWithFrameworkDe
|
|
|
1395
2202
|
},
|
|
1396
2203
|
excludeFiles: userConfig.excludeFiles && userConfig.excludeFiles.length > 0 ? userConfig.excludeFiles : frameworkConfig.excludeFiles,
|
|
1397
2204
|
services: userConfig.services,
|
|
2205
|
+
...userConfig.sidecars !== void 0 && { sidecars: userConfig.sidecars },
|
|
1398
2206
|
userArchive: userConfig.userArchive,
|
|
1399
2207
|
warnings: [...frameworkConfig.warnings, ...userConfig.warnings],
|
|
1400
2208
|
errors: [...frameworkConfig.errors, ...userConfig.errors]
|
|
@@ -1402,51 +2210,6 @@ var mergeWithFrameworkDefaults = import_effect15.Effect.fn("mergeWithFrameworkDe
|
|
|
1402
2210
|
return merged;
|
|
1403
2211
|
});
|
|
1404
2212
|
|
|
1405
|
-
// src/errors.ts
|
|
1406
|
-
var import_effect16 = require("effect");
|
|
1407
|
-
var ConfigFileNotFoundError = class extends import_effect16.Schema.TaggedError()("ConfigFileNotFoundError", {
|
|
1408
|
-
message: import_effect16.Schema.String,
|
|
1409
|
-
filePath: import_effect16.Schema.String
|
|
1410
|
-
}) {
|
|
1411
|
-
};
|
|
1412
|
-
var ConfigFileEmptyError = class extends import_effect16.Schema.TaggedError()("ConfigFileEmptyError", {
|
|
1413
|
-
message: import_effect16.Schema.String,
|
|
1414
|
-
filePath: import_effect16.Schema.String
|
|
1415
|
-
}) {
|
|
1416
|
-
};
|
|
1417
|
-
var ConfigFileParseError = class extends import_effect16.Schema.TaggedError()("ConfigFileParseError", {
|
|
1418
|
-
message: import_effect16.Schema.String,
|
|
1419
|
-
filePath: import_effect16.Schema.String,
|
|
1420
|
-
cause: import_effect16.Schema.optional(import_effect16.Schema.String)
|
|
1421
|
-
}) {
|
|
1422
|
-
};
|
|
1423
|
-
var ConfigModuleLoadError = class extends import_effect16.Schema.TaggedError()("ConfigModuleLoadError", {
|
|
1424
|
-
message: import_effect16.Schema.String,
|
|
1425
|
-
filePath: import_effect16.Schema.String,
|
|
1426
|
-
cause: import_effect16.Schema.optional(import_effect16.Schema.String)
|
|
1427
|
-
}) {
|
|
1428
|
-
};
|
|
1429
|
-
var ConfigVersionError = class extends import_effect16.Schema.TaggedError()("ConfigVersionError", {
|
|
1430
|
-
message: import_effect16.Schema.String,
|
|
1431
|
-
filePath: import_effect16.Schema.String,
|
|
1432
|
-
version: import_effect16.Schema.optional(import_effect16.Schema.Number)
|
|
1433
|
-
}) {
|
|
1434
|
-
};
|
|
1435
|
-
var ConfigSchemaValidationError = class extends import_effect16.Schema.TaggedError()(
|
|
1436
|
-
"ConfigSchemaValidationError",
|
|
1437
|
-
{
|
|
1438
|
-
message: import_effect16.Schema.String,
|
|
1439
|
-
filePath: import_effect16.Schema.String,
|
|
1440
|
-
validationErrors: import_effect16.Schema.Array(import_effect16.Schema.String)
|
|
1441
|
-
}
|
|
1442
|
-
) {
|
|
1443
|
-
};
|
|
1444
|
-
var FunctionConfigError = class extends import_effect16.Schema.TaggedError()("FunctionConfigError", {
|
|
1445
|
-
message: import_effect16.Schema.String,
|
|
1446
|
-
functionPath: import_effect16.Schema.String
|
|
1447
|
-
}) {
|
|
1448
|
-
};
|
|
1449
|
-
|
|
1450
2213
|
// src/filter-functions-from-assets.ts
|
|
1451
2214
|
var filterFunctionsFromAssets = (config) => {
|
|
1452
2215
|
return {
|
|
@@ -1458,28 +2221,24 @@ var filterFunctionsFromAssets = (config) => {
|
|
|
1458
2221
|
};
|
|
1459
2222
|
};
|
|
1460
2223
|
|
|
1461
|
-
// src/normalized-config.ts
|
|
1462
|
-
var DEFAULT_FUNCTION_DURATION_SECONDS = 30;
|
|
1463
|
-
var MAX_FUNCTION_DURATION_SECONDS = 28800;
|
|
1464
|
-
|
|
1465
2224
|
// src/parse-config.ts
|
|
1466
|
-
var
|
|
2225
|
+
var import_effect24 = require("effect");
|
|
1467
2226
|
|
|
1468
2227
|
// src/services/raw-config-reader.ts
|
|
1469
|
-
var
|
|
1470
|
-
var
|
|
1471
|
-
var
|
|
2228
|
+
var import_platform12 = require("@effect/platform");
|
|
2229
|
+
var import_effect20 = require("effect");
|
|
2230
|
+
var import_yaml2 = require("yaml");
|
|
1472
2231
|
|
|
1473
2232
|
// src/services/config-module-loader.ts
|
|
1474
|
-
var
|
|
2233
|
+
var import_effect19 = require("effect");
|
|
1475
2234
|
var import_jiti = require("jiti");
|
|
1476
2235
|
var MISSING_DEFAULT_EXPORT = /* @__PURE__ */ Symbol("MissingDefaultExport");
|
|
1477
2236
|
var STRICT_DEFAULT_EXPORT_EXTENSIONS = [".ts", ".mts", ".mjs"];
|
|
1478
|
-
var ConfigModuleLoader = class extends
|
|
1479
|
-
effect:
|
|
1480
|
-
const loadConfigModule =
|
|
2237
|
+
var ConfigModuleLoader = class extends import_effect19.Effect.Service()("ConfigModuleLoader", {
|
|
2238
|
+
effect: import_effect19.Effect.gen(function* () {
|
|
2239
|
+
const loadConfigModule = import_effect19.Effect.fn("ConfigModuleLoader.loadConfigModule")(function* (filePath) {
|
|
1481
2240
|
const extension = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
|
|
1482
|
-
const mod = yield*
|
|
2241
|
+
const mod = yield* import_effect19.Effect.tryPromise({
|
|
1483
2242
|
try: async () => {
|
|
1484
2243
|
const jiti = (0, import_jiti.createJiti)(filePath, { fsCache: false, interopDefault: true, moduleCache: false });
|
|
1485
2244
|
const namespace = await jiti.import(filePath);
|
|
@@ -1498,7 +2257,7 @@ var ConfigModuleLoader = class extends import_effect17.Effect.Service()("ConfigM
|
|
|
1498
2257
|
})
|
|
1499
2258
|
});
|
|
1500
2259
|
if (mod === MISSING_DEFAULT_EXPORT) {
|
|
1501
|
-
return yield*
|
|
2260
|
+
return yield* import_effect19.Effect.fail(
|
|
1502
2261
|
new ConfigModuleLoadError({
|
|
1503
2262
|
message: `Config module at ${filePath} does not have a default export. Export the config object as the default export (or via module.exports for CommonJS files), optionally wrapped in defineConfig.`,
|
|
1504
2263
|
filePath
|
|
@@ -1506,7 +2265,7 @@ var ConfigModuleLoader = class extends import_effect17.Effect.Service()("ConfigM
|
|
|
1506
2265
|
);
|
|
1507
2266
|
}
|
|
1508
2267
|
if (typeof mod === "function") {
|
|
1509
|
-
return yield*
|
|
2268
|
+
return yield* import_effect19.Effect.fail(
|
|
1510
2269
|
new ConfigModuleLoadError({
|
|
1511
2270
|
message: `Config module at ${filePath} default-exports a function; config factories are not supported. Export a config object instead (optionally wrapped in defineConfig).`,
|
|
1512
2271
|
filePath
|
|
@@ -1514,7 +2273,7 @@ var ConfigModuleLoader = class extends import_effect17.Effect.Service()("ConfigM
|
|
|
1514
2273
|
);
|
|
1515
2274
|
}
|
|
1516
2275
|
if (typeof mod !== "object" || mod === null || Array.isArray(mod)) {
|
|
1517
|
-
return yield*
|
|
2276
|
+
return yield* import_effect19.Effect.fail(
|
|
1518
2277
|
new ConfigModuleLoadError({
|
|
1519
2278
|
message: `Config module at ${filePath} must default-export a config object.`,
|
|
1520
2279
|
filePath
|
|
@@ -1544,36 +2303,36 @@ var ALLOWED_CONFIG_NAMES = [
|
|
|
1544
2303
|
"nebula.json"
|
|
1545
2304
|
];
|
|
1546
2305
|
var MODULE_EXTENSIONS = [".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"];
|
|
1547
|
-
var RawConfigReader = class extends
|
|
2306
|
+
var RawConfigReader = class extends import_effect20.Effect.Service()("RawConfigReader", {
|
|
1548
2307
|
dependencies: [ConfigModuleLoader.Default],
|
|
1549
|
-
effect:
|
|
1550
|
-
const fs = yield*
|
|
1551
|
-
const pathService = yield*
|
|
2308
|
+
effect: import_effect20.Effect.gen(function* () {
|
|
2309
|
+
const fs = yield* import_platform12.FileSystem.FileSystem;
|
|
2310
|
+
const pathService = yield* import_platform12.Path.Path;
|
|
1552
2311
|
const moduleLoader = yield* ConfigModuleLoader;
|
|
1553
|
-
const findConfig =
|
|
2312
|
+
const findConfig = import_effect20.Effect.fn("RawConfigReader.findConfig")(function* (projectFolder) {
|
|
1554
2313
|
for (const name of ALLOWED_CONFIG_NAMES) {
|
|
1555
2314
|
const filePath = pathService.join(projectFolder, name);
|
|
1556
|
-
const exists = yield* fs.exists(filePath).pipe(
|
|
2315
|
+
const exists = yield* fs.exists(filePath).pipe(import_effect20.Effect.catchAll(() => import_effect20.Effect.succeed(false)));
|
|
1557
2316
|
if (exists) {
|
|
1558
2317
|
return filePath;
|
|
1559
2318
|
}
|
|
1560
2319
|
}
|
|
1561
2320
|
return null;
|
|
1562
2321
|
});
|
|
1563
|
-
const readRawConfig =
|
|
1564
|
-
const exists = yield* fs.exists(filePath).pipe(
|
|
2322
|
+
const readRawConfig = import_effect20.Effect.fn("RawConfigReader.readRawConfig")(function* (filePath, options) {
|
|
2323
|
+
const exists = yield* fs.exists(filePath).pipe(import_effect20.Effect.catchAll(() => import_effect20.Effect.succeed(false)));
|
|
1565
2324
|
if (!exists) {
|
|
1566
|
-
return yield*
|
|
2325
|
+
return yield* import_effect20.Effect.fail(
|
|
1567
2326
|
new ConfigFileNotFoundError({ message: `Config file not found at ${filePath}`, filePath })
|
|
1568
2327
|
);
|
|
1569
2328
|
}
|
|
1570
2329
|
const fileContents = yield* fs.readFileString(filePath).pipe(
|
|
1571
|
-
|
|
2330
|
+
import_effect20.Effect.mapError(
|
|
1572
2331
|
() => new ConfigFileParseError({ message: `Failed to read config file at ${filePath}`, filePath })
|
|
1573
2332
|
)
|
|
1574
2333
|
);
|
|
1575
2334
|
if (fileContents.length === 0) {
|
|
1576
|
-
return yield*
|
|
2335
|
+
return yield* import_effect20.Effect.fail(
|
|
1577
2336
|
new ConfigFileEmptyError({ message: `Config file is empty at ${filePath}`, filePath })
|
|
1578
2337
|
);
|
|
1579
2338
|
}
|
|
@@ -1586,10 +2345,10 @@ var RawConfigReader = class extends import_effect18.Effect.Service()("RawConfigR
|
|
|
1586
2345
|
if (fileExtension === ".json") {
|
|
1587
2346
|
parsed = JSON.parse(fileContents);
|
|
1588
2347
|
} else {
|
|
1589
|
-
parsed = (0,
|
|
2348
|
+
parsed = (0, import_yaml2.parse)(fileContents);
|
|
1590
2349
|
}
|
|
1591
2350
|
} catch (error) {
|
|
1592
|
-
return yield*
|
|
2351
|
+
return yield* import_effect20.Effect.fail(
|
|
1593
2352
|
new ConfigFileParseError({
|
|
1594
2353
|
message: `Failed to parse config file at ${filePath}: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1595
2354
|
filePath,
|
|
@@ -1599,21 +2358,21 @@ var RawConfigReader = class extends import_effect18.Effect.Service()("RawConfigR
|
|
|
1599
2358
|
}
|
|
1600
2359
|
}
|
|
1601
2360
|
if (parsed == null) {
|
|
1602
|
-
return yield*
|
|
2361
|
+
return yield* import_effect20.Effect.fail(
|
|
1603
2362
|
new ConfigFileParseError({ message: `Config file could not be parsed at ${filePath}`, filePath })
|
|
1604
2363
|
);
|
|
1605
2364
|
}
|
|
1606
2365
|
if (!options?.disableVersionCheck && typeof parsed.version !== "number") {
|
|
1607
|
-
return yield*
|
|
2366
|
+
return yield* import_effect20.Effect.fail(
|
|
1608
2367
|
new ConfigVersionError({ message: `Config file is missing version at ${filePath}`, filePath })
|
|
1609
2368
|
);
|
|
1610
2369
|
}
|
|
1611
2370
|
return parsed;
|
|
1612
2371
|
});
|
|
1613
2372
|
const readConfigFile = (configFilePath) => readRawConfig(configFilePath, { disableVersionCheck: true }).pipe(
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
2373
|
+
import_effect20.Effect.map((parsed) => parsed),
|
|
2374
|
+
import_effect20.Effect.catchTag("ConfigFileNotFoundError", () => import_effect20.Effect.succeed(null)),
|
|
2375
|
+
import_effect20.Effect.withSpan("RawConfigReader.readConfigFile")
|
|
1617
2376
|
);
|
|
1618
2377
|
return { findConfig, readRawConfig, readConfigFile };
|
|
1619
2378
|
})
|
|
@@ -1623,17 +2382,17 @@ var RawConfigReader = class extends import_effect18.Effect.Service()("RawConfigR
|
|
|
1623
2382
|
// src/services/schema-validator.ts
|
|
1624
2383
|
var import_ajv = __toESM(require("ajv"));
|
|
1625
2384
|
var import_ajv_formats = __toESM(require("ajv-formats"));
|
|
1626
|
-
var
|
|
1627
|
-
var SchemaValidator = class extends
|
|
1628
|
-
effect:
|
|
2385
|
+
var import_effect21 = require("effect");
|
|
2386
|
+
var SchemaValidator = class extends import_effect21.Effect.Service()("SchemaValidator", {
|
|
2387
|
+
effect: import_effect21.Effect.gen(function* () {
|
|
1629
2388
|
const ajv = new import_ajv.default();
|
|
1630
2389
|
(0, import_ajv_formats.default)(ajv);
|
|
1631
|
-
const validate =
|
|
2390
|
+
const validate = import_effect21.Effect.fn("SchemaValidator.validate")(function* (config, schema, filePath) {
|
|
1632
2391
|
const compiledValidate = ajv.compile(schema);
|
|
1633
2392
|
const valid = compiledValidate(config);
|
|
1634
2393
|
if (!valid) {
|
|
1635
2394
|
const errors = compiledValidate.errors?.map((e) => `${e.instancePath || "/"} ${e.message ?? ""}`.trim()) ?? [];
|
|
1636
|
-
return yield*
|
|
2395
|
+
return yield* import_effect21.Effect.fail(
|
|
1637
2396
|
new ConfigSchemaValidationError({
|
|
1638
2397
|
message: `Config file at ${filePath} is invalid: ${ajv.errorsText(compiledValidate.errors)}`,
|
|
1639
2398
|
filePath,
|
|
@@ -1689,8 +2448,9 @@ var getFilesForPattern = async (pattern, projectFolder, excludeFiles = []) => {
|
|
|
1689
2448
|
};
|
|
1690
2449
|
|
|
1691
2450
|
// src/services/v4-config-parser.ts
|
|
1692
|
-
var
|
|
2451
|
+
var import_effect22 = require("effect");
|
|
1693
2452
|
var import_minimatch2 = require("minimatch");
|
|
2453
|
+
var import_node_path2 = require("path");
|
|
1694
2454
|
var import_safe_regex2 = __toESM(require("safe-regex2"));
|
|
1695
2455
|
var DEFAULT_FUNCTION_SETTINGS = {
|
|
1696
2456
|
memory: 128,
|
|
@@ -1723,6 +2483,46 @@ var normalizeImagePolicy = (images) => {
|
|
|
1723
2483
|
variants: images.variants ?? {}
|
|
1724
2484
|
};
|
|
1725
2485
|
};
|
|
2486
|
+
var DURATION_UNIT_SECONDS = { s: 1, m: 60, h: 3600, d: 86400 };
|
|
2487
|
+
var queueDurationSeconds = (value) => {
|
|
2488
|
+
if (value === void 0) return void 0;
|
|
2489
|
+
if (typeof value === "number") return value;
|
|
2490
|
+
const match = /^(\d+(?:\.\d+)?)(s|m|h|d)$/.exec(value);
|
|
2491
|
+
if (!match)
|
|
2492
|
+
throw new Error(`Invalid queue duration "${value}". Use seconds or a string such as 30s, 10m, 1.5h or 4d.`);
|
|
2493
|
+
return Math.ceil(Number(match[1]) * DURATION_UNIT_SECONDS[match[2]]);
|
|
2494
|
+
};
|
|
2495
|
+
var byName = (left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0;
|
|
2496
|
+
var definedOnly = (value) => Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
|
|
2497
|
+
var normalizeQueue = (name, queue) => {
|
|
2498
|
+
if (queue === null) return { name };
|
|
2499
|
+
const schedules = queue.schedules ? Object.entries(queue.schedules).map(
|
|
2500
|
+
([scheduleName, schedule]) => definedOnly({
|
|
2501
|
+
name: scheduleName,
|
|
2502
|
+
cron: schedule.cron,
|
|
2503
|
+
timezone: schedule.timezone,
|
|
2504
|
+
body: schedule.body === void 0 || typeof schedule.body === "string" ? schedule.body : JSON.stringify(schedule.body),
|
|
2505
|
+
// A plain-text body labelled JSON would fail to decode on every fire.
|
|
2506
|
+
contentType: schedule.contentType ?? (typeof schedule.body === "string" ? "text/plain; charset=utf-8" : void 0),
|
|
2507
|
+
headers: schedule.headers,
|
|
2508
|
+
enabled: schedule.enabled
|
|
2509
|
+
})
|
|
2510
|
+
).sort(byName) : void 0;
|
|
2511
|
+
return definedOnly({
|
|
2512
|
+
name,
|
|
2513
|
+
consumer: queue.consumer,
|
|
2514
|
+
visibilityTimeoutSeconds: queueDurationSeconds(queue.visibilityTimeout),
|
|
2515
|
+
retentionSeconds: queueDurationSeconds(queue.retention),
|
|
2516
|
+
maxAttempts: queue.maxAttempts,
|
|
2517
|
+
retryBackoffMinSeconds: queueDurationSeconds(queue.retryBackoff?.min),
|
|
2518
|
+
retryBackoffMaxSeconds: queueDurationSeconds(queue.retryBackoff?.max),
|
|
2519
|
+
deduplicationWindowSeconds: queueDurationSeconds(queue.deduplicationWindow),
|
|
2520
|
+
concurrency: queue.concurrency,
|
|
2521
|
+
rateLimit: queue.rateLimit == null ? queue.rateLimit : { count: queue.rateLimit.count, periodSeconds: queueDurationSeconds(queue.rateLimit.period) ?? 1 },
|
|
2522
|
+
deadLetter: queue.deadLetter,
|
|
2523
|
+
schedules
|
|
2524
|
+
});
|
|
2525
|
+
};
|
|
1726
2526
|
var normalizeServices = (services) => {
|
|
1727
2527
|
if (services == null) return void 0;
|
|
1728
2528
|
const normalized = [];
|
|
@@ -1735,7 +2535,13 @@ var normalizeServices = (services) => {
|
|
|
1735
2535
|
if (services.storage !== void 0) {
|
|
1736
2536
|
normalized.push({
|
|
1737
2537
|
type: "storage",
|
|
1738
|
-
buckets: Object.entries(services.storage.buckets).map(([name, bucket]) => ({ name, visibility: bucket?.visibility ?? "private" })).sort(
|
|
2538
|
+
buckets: Object.entries(services.storage.buckets).map(([name, bucket]) => ({ name, visibility: bucket?.visibility ?? "private" })).sort(byName)
|
|
2539
|
+
});
|
|
2540
|
+
}
|
|
2541
|
+
if (services.queues !== void 0) {
|
|
2542
|
+
normalized.push({
|
|
2543
|
+
type: "queues",
|
|
2544
|
+
queues: Object.entries(services.queues).map(([name, queue]) => normalizeQueue(name, queue)).sort(byName)
|
|
1739
2545
|
});
|
|
1740
2546
|
}
|
|
1741
2547
|
return normalized.length > 0 ? normalized : void 0;
|
|
@@ -1793,9 +2599,10 @@ var mapRoute = (route, entrypoints) => ({
|
|
|
1793
2599
|
negativeRequirements: route.missing,
|
|
1794
2600
|
status: route.statusCode
|
|
1795
2601
|
});
|
|
1796
|
-
var parseEntrypoints =
|
|
2602
|
+
var parseEntrypoints = import_effect22.Effect.fn("parseEntrypoints")(function* (config, projectFolder) {
|
|
1797
2603
|
const entrypoints = [];
|
|
1798
|
-
|
|
2604
|
+
const dockerFunctions = [];
|
|
2605
|
+
if (config.functions == null) return { entrypoints, dockerFunctions };
|
|
1799
2606
|
for (const [fnPath, func] of Object.entries(config.functions)) {
|
|
1800
2607
|
if (getFunctionSettings(fnPath, config) == null) {
|
|
1801
2608
|
return yield* new FunctionConfigError({
|
|
@@ -1803,7 +2610,7 @@ var parseEntrypoints = import_effect20.Effect.fn("parseEntrypoints")(function* (
|
|
|
1803
2610
|
functionPath: fnPath
|
|
1804
2611
|
});
|
|
1805
2612
|
}
|
|
1806
|
-
const matchedFiles = yield*
|
|
2613
|
+
const matchedFiles = yield* import_effect22.Effect.tryPromise({
|
|
1807
2614
|
try: () => getFilesForPattern(fnPath, projectFolder, func.excludeFiles),
|
|
1808
2615
|
catch: (error) => new FunctionConfigError({
|
|
1809
2616
|
message: `Failed to resolve files for function pattern '${fnPath}': ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -1820,6 +2627,35 @@ var parseEntrypoints = import_effect20.Effect.fn("parseEntrypoints")(function* (
|
|
|
1820
2627
|
functionPath: file
|
|
1821
2628
|
});
|
|
1822
2629
|
}
|
|
2630
|
+
if (settings.runtime === CONTAINER_RUNTIME) {
|
|
2631
|
+
const unsupported = ["symlinks", "includeFiles"].filter((key) => settings[key] !== void 0);
|
|
2632
|
+
if (unsupported.length > 0) {
|
|
2633
|
+
return yield* new FunctionConfigError({
|
|
2634
|
+
message: `Function '${file}' runs a Dockerfile, so ${unsupported.join(" and ")} do not apply. Copy files in the Dockerfile instead.`,
|
|
2635
|
+
functionPath: file
|
|
2636
|
+
});
|
|
2637
|
+
}
|
|
2638
|
+
const declared = Object.entries(config.functions).filter(([pattern]) => matchesPattern(file, pattern)).reduce((merged, [, value]) => ({ ...merged, ...value }), {});
|
|
2639
|
+
dockerFunctions.push({
|
|
2640
|
+
file,
|
|
2641
|
+
name: dockerFunctionContainerName(file),
|
|
2642
|
+
container: {
|
|
2643
|
+
build: { context: import_node_path2.posix.dirname(file), dockerfile: import_node_path2.posix.basename(file) },
|
|
2644
|
+
...declared.port !== void 0 && { port: declared.port },
|
|
2645
|
+
...declared.memory !== void 0 && { memory: declared.memory },
|
|
2646
|
+
...declared.max_duration !== void 0 && { max_duration: declared.max_duration },
|
|
2647
|
+
...declared.streaming !== void 0 && { streaming: declared.streaming },
|
|
2648
|
+
...func.schedule !== void 0 && { schedule: func.schedule }
|
|
2649
|
+
}
|
|
2650
|
+
});
|
|
2651
|
+
continue;
|
|
2652
|
+
}
|
|
2653
|
+
if (settings.port !== void 0) {
|
|
2654
|
+
return yield* new FunctionConfigError({
|
|
2655
|
+
message: `Function '${file}' sets port, which only applies to 'runtime: docker'.`,
|
|
2656
|
+
functionPath: file
|
|
2657
|
+
});
|
|
2658
|
+
}
|
|
1823
2659
|
const runtime = settings.runtime ?? "node-20";
|
|
1824
2660
|
const streaming = settings.streaming ?? runtimeStreamsByDefault(runtime);
|
|
1825
2661
|
entrypoints.push({
|
|
@@ -1837,25 +2673,84 @@ var parseEntrypoints = import_effect20.Effect.fn("parseEntrypoints")(function* (
|
|
|
1837
2673
|
});
|
|
1838
2674
|
}
|
|
1839
2675
|
}
|
|
1840
|
-
|
|
2676
|
+
dockerFunctions.sort((left, right) => left.file < right.file ? -1 : left.file > right.file ? 1 : 0);
|
|
2677
|
+
for (const [index, { file, name }] of dockerFunctions.entries()) {
|
|
2678
|
+
const clash = dockerFunctions.slice(0, index).find((candidate) => candidate.name === name);
|
|
2679
|
+
if (clash !== void 0) {
|
|
2680
|
+
return yield* new FunctionConfigError({
|
|
2681
|
+
message: `Functions '${clash.file}' and '${file}' would both be named '${name}'. Declare one of them under 'containers' with an explicit name.`,
|
|
2682
|
+
functionPath: file
|
|
2683
|
+
});
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
return { entrypoints, dockerFunctions };
|
|
1841
2687
|
});
|
|
1842
|
-
var collectAssets =
|
|
2688
|
+
var collectAssets = import_effect22.Effect.fn("collectAssets")(function* (config, projectFolder) {
|
|
1843
2689
|
if (config.assets == null) return [];
|
|
1844
2690
|
const assetNames = yield* collectAssetFiles(projectFolder, config.assets);
|
|
1845
2691
|
return assetNames.filter((assetName) => getFunctionSettings(`${config.assets}/${assetName}`, config) == null).map((assetName) => `${config.assets}/${assetName}`);
|
|
1846
2692
|
});
|
|
1847
|
-
var
|
|
2693
|
+
var reservedRuntimePorts = (entrypoint) => entrypoint.runtime === CONTAINER_RUNTIME ? [] : entrypoint.runtime.startsWith("php-") ? [8080, 9e3] : [8080];
|
|
2694
|
+
var parseContainers = import_effect22.Effect.fn("parseContainers")(function* (config, projectFolder, fileEntrypoints, dockerFunctions) {
|
|
2695
|
+
const warnings = [];
|
|
2696
|
+
let containers = {};
|
|
2697
|
+
if (config.compose != null) {
|
|
2698
|
+
const imported = yield* readComposeContainers(config.compose, projectFolder);
|
|
2699
|
+
containers = imported.containers;
|
|
2700
|
+
warnings.push(...imported.warnings);
|
|
2701
|
+
}
|
|
2702
|
+
containers = { ...containers, ...config.containers ?? {} };
|
|
2703
|
+
for (const { file, name, container } of dockerFunctions) {
|
|
2704
|
+
if (containers[name] !== void 0) {
|
|
2705
|
+
return yield* new ContainerConfigError({
|
|
2706
|
+
message: `Function '${file}' runs as container '${name}', which 'containers' or the Compose file already declares. Rename one of them.`,
|
|
2707
|
+
containerName: name
|
|
2708
|
+
});
|
|
2709
|
+
}
|
|
2710
|
+
containers[name] = container;
|
|
2711
|
+
}
|
|
2712
|
+
const result = yield* normalizeContainers(containers, projectFolder);
|
|
2713
|
+
warnings.push(...result.warnings);
|
|
2714
|
+
for (const entrypoint of fileEntrypoints) {
|
|
2715
|
+
for (const port of reservedRuntimePorts(entrypoint)) {
|
|
2716
|
+
const sidecar = result.sidecars.find((candidate) => candidate.port === port);
|
|
2717
|
+
if (sidecar !== void 0) {
|
|
2718
|
+
return yield* new ContainerConfigError({
|
|
2719
|
+
message: `Sidecar '${sidecar.name}' listens on port ${port}, which the ${entrypoint.runtime} runtime of '${entrypoint.path}' uses inside the same microVM. Choose another port.`,
|
|
2720
|
+
containerName: sidecar.name
|
|
2721
|
+
});
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
return { ...result, warnings };
|
|
2726
|
+
});
|
|
2727
|
+
var V4ConfigParser = class extends import_effect22.Effect.Service()("V4ConfigParser", {
|
|
1848
2728
|
accessors: true,
|
|
1849
|
-
effect:
|
|
2729
|
+
effect: import_effect22.Effect.succeed({
|
|
1850
2730
|
/**
|
|
1851
2731
|
* Parses a ConfigV4 into a NormalizedConfig.
|
|
1852
2732
|
*
|
|
1853
2733
|
* @param config - The raw V4 config object
|
|
1854
2734
|
* @param projectFolder - Absolute path to the project root
|
|
1855
2735
|
*/
|
|
1856
|
-
parse:
|
|
1857
|
-
const entrypoints = yield* parseEntrypoints(config, projectFolder);
|
|
2736
|
+
parse: import_effect22.Effect.fn("V4ConfigParser.parse")(function* (config, projectFolder) {
|
|
2737
|
+
const { entrypoints: fileEntrypoints, dockerFunctions } = yield* parseEntrypoints(config, projectFolder);
|
|
2738
|
+
const containers = yield* parseContainers(config, projectFolder, fileEntrypoints, dockerFunctions);
|
|
2739
|
+
const entrypoints = [...fileEntrypoints, ...containers.entrypoints];
|
|
1858
2740
|
const assets = yield* collectAssets(config, projectFolder);
|
|
2741
|
+
const dockerFunctionPaths = new Map(
|
|
2742
|
+
dockerFunctions.map(({ file, name }) => [file, containerEntrypointPath(name)])
|
|
2743
|
+
);
|
|
2744
|
+
const routes = (config.routes ?? []).map(
|
|
2745
|
+
(route) => mapRoute(
|
|
2746
|
+
{
|
|
2747
|
+
...route,
|
|
2748
|
+
destination: dockerFunctionPaths.get(normalizeRouteDestination(route.destination)) ?? route.destination
|
|
2749
|
+
},
|
|
2750
|
+
entrypoints
|
|
2751
|
+
)
|
|
2752
|
+
);
|
|
2753
|
+
const warnings = [...containers.warnings];
|
|
1859
2754
|
return {
|
|
1860
2755
|
regions: resolveRegions(config.regions),
|
|
1861
2756
|
assets: {
|
|
@@ -1868,10 +2763,11 @@ var V4ConfigParser = class extends import_effect20.Effect.Service()("V4ConfigPar
|
|
|
1868
2763
|
commands: config.build_commands ?? [],
|
|
1869
2764
|
images: normalizeImagePolicy(config.images),
|
|
1870
2765
|
services: normalizeServices(config.services),
|
|
2766
|
+
...containers.sidecars.length > 0 && { sidecars: containers.sidecars },
|
|
1871
2767
|
entrypoints,
|
|
1872
2768
|
errors: [],
|
|
1873
|
-
warnings
|
|
1874
|
-
routes
|
|
2769
|
+
warnings,
|
|
2770
|
+
routes
|
|
1875
2771
|
};
|
|
1876
2772
|
})
|
|
1877
2773
|
})
|
|
@@ -1879,7 +2775,7 @@ var V4ConfigParser = class extends import_effect20.Effect.Service()("V4ConfigPar
|
|
|
1879
2775
|
};
|
|
1880
2776
|
|
|
1881
2777
|
// src/services/vercel-build-output-parser.ts
|
|
1882
|
-
var
|
|
2778
|
+
var import_platform13 = require("@effect/platform");
|
|
1883
2779
|
|
|
1884
2780
|
// ../commons/src/deep-merge.ts
|
|
1885
2781
|
var deepMerge = (target, ...partials) => {
|
|
@@ -1908,7 +2804,7 @@ var deepMerge = (target, ...partials) => {
|
|
|
1908
2804
|
};
|
|
1909
2805
|
|
|
1910
2806
|
// src/services/vercel-build-output-parser.ts
|
|
1911
|
-
var
|
|
2807
|
+
var import_effect23 = require("effect");
|
|
1912
2808
|
|
|
1913
2809
|
// src/build-output-v3/determine-repo-root.ts
|
|
1914
2810
|
var import_path = __toESM(require("path"));
|
|
@@ -2004,11 +2900,11 @@ var translateVercelRuntime = (runtime) => {
|
|
|
2004
2900
|
var CONFIG_PATH = ".vercel/output/config.json";
|
|
2005
2901
|
var FUNCTIONS_FOLDER = ".vercel/output/functions";
|
|
2006
2902
|
var FUNCTION_CONFIGS_PATTERN = `${FUNCTIONS_FOLDER}/**/*.func/.vc-config.json`;
|
|
2007
|
-
var VercelBuildOutputParser = class extends
|
|
2008
|
-
effect:
|
|
2903
|
+
var VercelBuildOutputParser = class extends import_effect23.Effect.Service()("VercelBuildOutputParser", {
|
|
2904
|
+
effect: import_effect23.Effect.gen(function* () {
|
|
2009
2905
|
const rawConfigReader = yield* RawConfigReader;
|
|
2010
|
-
const pathService = yield*
|
|
2011
|
-
const parse =
|
|
2906
|
+
const pathService = yield* import_platform13.Path.Path;
|
|
2907
|
+
const parse = import_effect23.Effect.fn("VercelBuildOutputParser.parse")(function* (parseResult, projectFolder) {
|
|
2012
2908
|
const config = yield* rawConfigReader.readConfigFile(pathService.join(projectFolder, CONFIG_PATH));
|
|
2013
2909
|
if (!config || typeof config.version !== "number" || config.version < 3) {
|
|
2014
2910
|
return parseResult;
|
|
@@ -2020,8 +2916,8 @@ var VercelBuildOutputParser = class extends import_effect21.Effect.Service()("Ve
|
|
|
2020
2916
|
merged.regions = [...new Set(merged.regions)];
|
|
2021
2917
|
return merged;
|
|
2022
2918
|
});
|
|
2023
|
-
const loadFunctions =
|
|
2024
|
-
const functionConfigs = yield*
|
|
2919
|
+
const loadFunctions = import_effect23.Effect.fn("VercelBuildOutputParser.loadFunctions")(function* (config, parseResult, projectFolder) {
|
|
2920
|
+
const functionConfigs = yield* import_effect23.Effect.tryPromise({
|
|
2025
2921
|
try: () => getFilesForPattern(FUNCTION_CONFIGS_PATTERN, projectFolder),
|
|
2026
2922
|
catch: (error) => new ConfigFileParseError({
|
|
2027
2923
|
message: `Failed to scan for function configs: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -2307,17 +3203,22 @@ var schema_default = {
|
|
|
2307
3203
|
minimum: 1
|
|
2308
3204
|
},
|
|
2309
3205
|
runtime: {
|
|
2310
|
-
$ref: "#/$defs/runtimes",
|
|
2311
|
-
description: "The runtime to use for the function."
|
|
3206
|
+
anyOf: [{ $ref: "#/$defs/runtimes" }, { const: "docker" }],
|
|
3207
|
+
description: "The runtime to use for the function. `docker` builds the matched file as a Dockerfile, with its directory as the build context, and runs the image as the function."
|
|
3208
|
+
},
|
|
3209
|
+
port: {
|
|
3210
|
+
type: "integer",
|
|
3211
|
+
minimum: 1,
|
|
3212
|
+
maximum: 65535,
|
|
3213
|
+
description: "TCP port the image listens on. Only for `runtime: docker`. Defaults to the first exposed port of the image, then 8080."
|
|
2312
3214
|
},
|
|
2313
3215
|
streaming: {
|
|
2314
3216
|
type: "boolean",
|
|
2315
3217
|
description: "Enable function response streaming. When omitted, Node and Bun runtimes stream by default."
|
|
2316
3218
|
},
|
|
2317
3219
|
schedule: {
|
|
2318
|
-
|
|
2319
|
-
description: "An expression to schedule the function to run at specific times."
|
|
2320
|
-
pattern: "^(?:rate[(](?:(?:1[ ]+(hour|minute|day))|(?:[0-9]+[ ]+(hours|minutes|days)))[)])|(?:cron[(](?:(?:(?:[0-5]?[0-9])|[*])(?:(?:[-](?:(?:[0-5]?[0-9])|[*]))|(?:[/][0-9]+))?(?:[,](?:(?:[0-5]?[0-9])|[*])(?:(?:[-](?:(?:[0-5]?[0-9])|[*]))|(?:[/][0-9]+))?)*)[ ]+(?:(?:(?:[0-2]?[0-9])|[*])(?:(?:[-](?:(?:[0-2]?[0-9])|[*]))|(?:[/][0-9]+))?(?:[,](?:(?:[0-2]?[0-9])|[*])(?:(?:[-](?:(?:[0-2]?[0-9])|[*]))|(?:[/][0-9]+))?)*)[ ]+(?:(?:[?][ ]+(?:(?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:(?:[-](?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:[/][0-9]+)?)|(?:[/][0-9]+))?(?:[,](?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:(?:[-](?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:[/][0-9]+)?)|(?:[/][0-9]+))?)*)[ ]+(?:(?:(?:[1-7]|(?:SUN|MON|TUE|WED|THU|FRI|SAT))[#][0-5])|(?:(?:(?:(?:[1-7]|(?:SUN|MON|TUE|WED|THU|FRI|SAT))L?)|[L*])(?:(?:[-](?:(?:(?:[1-7]|(?:SUN|MON|TUE|WED|THU|FRI|SAT))L?)|[L*]))|(?:[/][0-9]+))?(?:[,](?:(?:(?:[1-7]|(?:SUN|MON|TUE|WED|THU|FRI|SAT))L?)|[L*])(?:(?:[-](?:(?:(?:[1-7]|(?:SUN|MON|TUE|WED|THU|FRI|SAT))L?)|[L*]))|(?:[/][0-9]+))?)*)))|(?:(?:(?:(?:(?:[1-3]?[0-9])W?)|LW|[L*])(?:(?:[-](?:(?:(?:[1-3]?[0-9])W?)|LW|[L*]))|(?:[/][0-9]+))?(?:[,](?:(?:(?:[1-3]?[0-9])W?)|LW|[L*])(?:(?:[-](?:(?:(?:[1-3]?[0-9])W?)|LW|[L*]))|(?:[/][0-9]+))?)*)[ ]+(?:(?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:(?:[-](?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:[/][0-9]+)?)|(?:[/][0-9]+))?(?:[,](?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:(?:[-](?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:[/][0-9]+)?)|(?:[/][0-9]+))?)*)[ ]+[?]))[ ]+(?:(?:(?:[12][0-9]{3})|[*])(?:(?:[-](?:(?:[12][0-9]{3})|[*]))|(?:[/][0-9]+))?(?:[,](?:(?:[12][0-9]{3})|[*])(?:(?:[-](?:(?:[12][0-9]{3})|[*]))|(?:[/][0-9]+))?)*)[)])$"
|
|
3220
|
+
$ref: "#/$defs/schedule",
|
|
3221
|
+
description: "An expression to schedule the function to run at specific times."
|
|
2321
3222
|
},
|
|
2322
3223
|
symlinks: {
|
|
2323
3224
|
type: "object",
|
|
@@ -2409,6 +3310,151 @@ var schema_default = {
|
|
|
2409
3310
|
}
|
|
2410
3311
|
}
|
|
2411
3312
|
},
|
|
3313
|
+
compose: {
|
|
3314
|
+
type: ["string", "null"],
|
|
3315
|
+
minLength: 1,
|
|
3316
|
+
maxLength: 1024,
|
|
3317
|
+
description: "Project-relative path of a Compose file whose services are imported as containers. Entries in `containers` win over imported services of the same name."
|
|
3318
|
+
},
|
|
3319
|
+
containers: {
|
|
3320
|
+
type: ["object", "null"],
|
|
3321
|
+
description: "Container images to run, keyed by name. A container runs as a function unless `sidecar` is true; routes target it with `destination: container:<name>`. A sidecar runs next to every function instance and answers at `<name>:<port>`.",
|
|
3322
|
+
maxProperties: 16,
|
|
3323
|
+
propertyNames: {
|
|
3324
|
+
pattern: "^[a-z][a-z0-9_-]{0,62}$",
|
|
3325
|
+
not: {
|
|
3326
|
+
enum: ["localhost"]
|
|
3327
|
+
}
|
|
3328
|
+
},
|
|
3329
|
+
additionalProperties: {
|
|
3330
|
+
type: "object",
|
|
3331
|
+
additionalProperties: false,
|
|
3332
|
+
oneOf: [
|
|
3333
|
+
{
|
|
3334
|
+
required: ["image"]
|
|
3335
|
+
},
|
|
3336
|
+
{
|
|
3337
|
+
required: ["build"]
|
|
3338
|
+
}
|
|
3339
|
+
],
|
|
3340
|
+
properties: {
|
|
3341
|
+
image: {
|
|
3342
|
+
type: "string",
|
|
3343
|
+
minLength: 1,
|
|
3344
|
+
maxLength: 512,
|
|
3345
|
+
pattern: "^[^\\s]+$",
|
|
3346
|
+
description: "Registry image reference, e.g. `redis:7-alpine` or `ghcr.io/acme/api:1.4`."
|
|
3347
|
+
},
|
|
3348
|
+
build: {
|
|
3349
|
+
description: "Build context directory, or the full build settings, for a Dockerfile in the repository.",
|
|
3350
|
+
oneOf: [
|
|
3351
|
+
{
|
|
3352
|
+
type: "string",
|
|
3353
|
+
minLength: 1,
|
|
3354
|
+
maxLength: 1024
|
|
3355
|
+
},
|
|
3356
|
+
{
|
|
3357
|
+
type: "object",
|
|
3358
|
+
additionalProperties: false,
|
|
3359
|
+
properties: {
|
|
3360
|
+
context: {
|
|
3361
|
+
type: "string",
|
|
3362
|
+
minLength: 1,
|
|
3363
|
+
maxLength: 1024
|
|
3364
|
+
},
|
|
3365
|
+
dockerfile: {
|
|
3366
|
+
type: "string",
|
|
3367
|
+
minLength: 1,
|
|
3368
|
+
maxLength: 1024
|
|
3369
|
+
},
|
|
3370
|
+
target: {
|
|
3371
|
+
type: "string",
|
|
3372
|
+
minLength: 1,
|
|
3373
|
+
maxLength: 128
|
|
3374
|
+
},
|
|
3375
|
+
args: {
|
|
3376
|
+
type: "object",
|
|
3377
|
+
maxProperties: 100,
|
|
3378
|
+
additionalProperties: {
|
|
3379
|
+
type: "string",
|
|
3380
|
+
maxLength: 65536
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
}
|
|
3385
|
+
]
|
|
3386
|
+
},
|
|
3387
|
+
sidecar: {
|
|
3388
|
+
type: "boolean",
|
|
3389
|
+
description: "Run next to every function instance instead of serving routes. Defaults to false."
|
|
3390
|
+
},
|
|
3391
|
+
port: {
|
|
3392
|
+
type: "integer",
|
|
3393
|
+
minimum: 1,
|
|
3394
|
+
maximum: 65535,
|
|
3395
|
+
description: "TCP port the container listens on. Defaults to the first exposed port of the image, then 8080."
|
|
3396
|
+
},
|
|
3397
|
+
entrypoint: {
|
|
3398
|
+
$ref: "#/$defs/stringOrStringArray",
|
|
3399
|
+
description: "Replaces the image ENTRYPOINT. A string is split into words the way Compose splits it."
|
|
3400
|
+
},
|
|
3401
|
+
command: {
|
|
3402
|
+
$ref: "#/$defs/stringOrStringArray",
|
|
3403
|
+
description: "Replaces the image CMD. A string is split into words the way Compose splits it."
|
|
3404
|
+
},
|
|
3405
|
+
env: {
|
|
3406
|
+
type: "object",
|
|
3407
|
+
maxProperties: 100,
|
|
3408
|
+
additionalProperties: {
|
|
3409
|
+
type: "string",
|
|
3410
|
+
maxLength: 65536
|
|
3411
|
+
},
|
|
3412
|
+
description: "Environment variables baked into the container, merged over the image ENV."
|
|
3413
|
+
},
|
|
3414
|
+
working_dir: {
|
|
3415
|
+
type: "string",
|
|
3416
|
+
minLength: 1,
|
|
3417
|
+
maxLength: 1024,
|
|
3418
|
+
pattern: "^/",
|
|
3419
|
+
description: "Replaces the image WORKDIR. Must be absolute."
|
|
3420
|
+
},
|
|
3421
|
+
user: {
|
|
3422
|
+
oneOf: [
|
|
3423
|
+
{
|
|
3424
|
+
type: "string",
|
|
3425
|
+
minLength: 1,
|
|
3426
|
+
maxLength: 256
|
|
3427
|
+
},
|
|
3428
|
+
{
|
|
3429
|
+
type: "integer",
|
|
3430
|
+
minimum: 0
|
|
3431
|
+
}
|
|
3432
|
+
],
|
|
3433
|
+
description: "Replaces the image USER: a name, a uid, `name:group` or `uid:gid`. A bare uid may be a number."
|
|
3434
|
+
},
|
|
3435
|
+
memory: {
|
|
3436
|
+
type: "integer",
|
|
3437
|
+
minimum: 128,
|
|
3438
|
+
maximum: 3009,
|
|
3439
|
+
description: "Memory in MB. Defaults to 512 for a container function and 256 for a sidecar."
|
|
3440
|
+
},
|
|
3441
|
+
max_duration: {
|
|
3442
|
+
type: "number",
|
|
3443
|
+
minimum: 1,
|
|
3444
|
+
maximum: 28800,
|
|
3445
|
+
description: "Maximum lifetime in seconds of one request. Container functions only."
|
|
3446
|
+
},
|
|
3447
|
+
streaming: {
|
|
3448
|
+
type: "boolean",
|
|
3449
|
+
description: "Stream responses. Defaults to true. Container functions only."
|
|
3450
|
+
},
|
|
3451
|
+
schedule: {
|
|
3452
|
+
$ref: "#/$defs/schedule",
|
|
3453
|
+
description: "An expression to run the container function at specific times. Container functions only."
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
},
|
|
2412
3458
|
services: {
|
|
2413
3459
|
type: "object",
|
|
2414
3460
|
description: "Managed services to provision for the deployment environment.",
|
|
@@ -2559,11 +3605,179 @@ var schema_default = {
|
|
|
2559
3605
|
}
|
|
2560
3606
|
}
|
|
2561
3607
|
}
|
|
3608
|
+
},
|
|
3609
|
+
queues: {
|
|
3610
|
+
type: "object",
|
|
3611
|
+
description: "Queues to provision in the deployment environment, keyed by name. Use null for a pull queue with default settings. Queues you stop declaring are kept, with their messages.",
|
|
3612
|
+
propertyNames: {
|
|
3613
|
+
maxLength: 255,
|
|
3614
|
+
pattern: "^[A-Za-z0-9_][A-Za-z0-9_.~:@+=-]*$"
|
|
3615
|
+
},
|
|
3616
|
+
additionalProperties: {
|
|
3617
|
+
oneOf: [
|
|
3618
|
+
{
|
|
3619
|
+
type: "null"
|
|
3620
|
+
},
|
|
3621
|
+
{
|
|
3622
|
+
type: "object",
|
|
3623
|
+
additionalProperties: false,
|
|
3624
|
+
properties: {
|
|
3625
|
+
consumer: {
|
|
3626
|
+
type: ["string", "null"],
|
|
3627
|
+
pattern: "^/(?!/)\\S*$",
|
|
3628
|
+
maxLength: 2048,
|
|
3629
|
+
description: "Deployment-relative path that receives each message as a signed POST, for example /api/queues/emails. Omit it for a pull queue that you drain with receive."
|
|
3630
|
+
},
|
|
3631
|
+
visibilityTimeout: {
|
|
3632
|
+
$ref: "#/$defs/queueDuration",
|
|
3633
|
+
description: "How long a push delivery may run, or how long a received message stays leased. Defaults to 60 seconds, at most 12 hours."
|
|
3634
|
+
},
|
|
3635
|
+
retention: {
|
|
3636
|
+
$ref: "#/$defs/queueDuration",
|
|
3637
|
+
description: "How long an undelivered message is kept. Defaults to 4 days, at most 14 days."
|
|
3638
|
+
},
|
|
3639
|
+
maxAttempts: {
|
|
3640
|
+
type: "integer",
|
|
3641
|
+
minimum: 1,
|
|
3642
|
+
maximum: 100,
|
|
3643
|
+
description: "Deliveries per message before it moves to the dead-letter list. Defaults to 10."
|
|
3644
|
+
},
|
|
3645
|
+
retryBackoff: {
|
|
3646
|
+
type: "object",
|
|
3647
|
+
additionalProperties: false,
|
|
3648
|
+
description: "Exponential backoff between failed deliveries. Defaults to 5 seconds, doubling up to 15 minutes.",
|
|
3649
|
+
properties: {
|
|
3650
|
+
min: {
|
|
3651
|
+
$ref: "#/$defs/queueDuration"
|
|
3652
|
+
},
|
|
3653
|
+
max: {
|
|
3654
|
+
$ref: "#/$defs/queueDuration"
|
|
3655
|
+
}
|
|
3656
|
+
}
|
|
3657
|
+
},
|
|
3658
|
+
deduplicationWindow: {
|
|
3659
|
+
$ref: "#/$defs/queueDuration",
|
|
3660
|
+
description: "How long a deduplication key is remembered. Defaults to 24 hours, at most 7 days."
|
|
3661
|
+
},
|
|
3662
|
+
concurrency: {
|
|
3663
|
+
type: ["integer", "null"],
|
|
3664
|
+
minimum: 1,
|
|
3665
|
+
maximum: 1e3,
|
|
3666
|
+
description: "Most push deliveries in flight at once. Defaults to 100."
|
|
3667
|
+
},
|
|
3668
|
+
rateLimit: {
|
|
3669
|
+
oneOf: [
|
|
3670
|
+
{
|
|
3671
|
+
type: "null"
|
|
3672
|
+
},
|
|
3673
|
+
{
|
|
3674
|
+
type: "object",
|
|
3675
|
+
required: ["count"],
|
|
3676
|
+
additionalProperties: false,
|
|
3677
|
+
properties: {
|
|
3678
|
+
count: {
|
|
3679
|
+
type: "integer",
|
|
3680
|
+
minimum: 1,
|
|
3681
|
+
maximum: 1e6
|
|
3682
|
+
},
|
|
3683
|
+
period: {
|
|
3684
|
+
$ref: "#/$defs/queueDuration"
|
|
3685
|
+
}
|
|
3686
|
+
}
|
|
3687
|
+
}
|
|
3688
|
+
],
|
|
3689
|
+
description: "Most deliveries started per period. The period defaults to one second."
|
|
3690
|
+
},
|
|
3691
|
+
deadLetter: {
|
|
3692
|
+
type: "boolean",
|
|
3693
|
+
description: "Keep messages that run out of attempts so you can inspect and redrive them. Defaults to true."
|
|
3694
|
+
},
|
|
3695
|
+
schedules: {
|
|
3696
|
+
type: "object",
|
|
3697
|
+
description: "Cron schedules that send a message into this queue, keyed by schedule name.",
|
|
3698
|
+
propertyNames: {
|
|
3699
|
+
maxLength: 128,
|
|
3700
|
+
pattern: "^[A-Za-z0-9_][A-Za-z0-9_.-]*$"
|
|
3701
|
+
},
|
|
3702
|
+
additionalProperties: {
|
|
3703
|
+
type: "object",
|
|
3704
|
+
required: ["cron"],
|
|
3705
|
+
additionalProperties: false,
|
|
3706
|
+
properties: {
|
|
3707
|
+
cron: {
|
|
3708
|
+
type: "string",
|
|
3709
|
+
minLength: 1,
|
|
3710
|
+
maxLength: 255,
|
|
3711
|
+
description: "Five-field cron expression, or a macro such as @hourly or @daily."
|
|
3712
|
+
},
|
|
3713
|
+
timezone: {
|
|
3714
|
+
type: "string",
|
|
3715
|
+
description: "IANA time zone the expression is evaluated in. Defaults to UTC."
|
|
3716
|
+
},
|
|
3717
|
+
body: {
|
|
3718
|
+
description: "Message body. Strings are sent as is; any other value is sent as JSON."
|
|
3719
|
+
},
|
|
3720
|
+
contentType: {
|
|
3721
|
+
type: "string",
|
|
3722
|
+
description: "Content type of the body. Defaults to text/plain for a string body and application/json otherwise."
|
|
3723
|
+
},
|
|
3724
|
+
headers: {
|
|
3725
|
+
type: "object",
|
|
3726
|
+
additionalProperties: {
|
|
3727
|
+
type: "string"
|
|
3728
|
+
},
|
|
3729
|
+
description: "Headers delivered with every message from this schedule."
|
|
3730
|
+
},
|
|
3731
|
+
enabled: {
|
|
3732
|
+
type: "boolean",
|
|
3733
|
+
description: "Set to false to keep the schedule without sending. Defaults to true."
|
|
3734
|
+
}
|
|
3735
|
+
}
|
|
3736
|
+
}
|
|
3737
|
+
}
|
|
3738
|
+
}
|
|
3739
|
+
}
|
|
3740
|
+
]
|
|
3741
|
+
}
|
|
2562
3742
|
}
|
|
2563
3743
|
}
|
|
2564
3744
|
}
|
|
2565
3745
|
},
|
|
2566
3746
|
$defs: {
|
|
3747
|
+
schedule: {
|
|
3748
|
+
type: "string",
|
|
3749
|
+
pattern: "^(?:rate[(](?:(?:1[ ]+(hour|minute|day))|(?:[0-9]+[ ]+(hours|minutes|days)))[)])|(?:cron[(](?:(?:(?:[0-5]?[0-9])|[*])(?:(?:[-](?:(?:[0-5]?[0-9])|[*]))|(?:[/][0-9]+))?(?:[,](?:(?:[0-5]?[0-9])|[*])(?:(?:[-](?:(?:[0-5]?[0-9])|[*]))|(?:[/][0-9]+))?)*)[ ]+(?:(?:(?:[0-2]?[0-9])|[*])(?:(?:[-](?:(?:[0-2]?[0-9])|[*]))|(?:[/][0-9]+))?(?:[,](?:(?:[0-2]?[0-9])|[*])(?:(?:[-](?:(?:[0-2]?[0-9])|[*]))|(?:[/][0-9]+))?)*)[ ]+(?:(?:[?][ ]+(?:(?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:(?:[-](?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:[/][0-9]+)?)|(?:[/][0-9]+))?(?:[,](?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:(?:[-](?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:[/][0-9]+)?)|(?:[/][0-9]+))?)*)[ ]+(?:(?:(?:[1-7]|(?:SUN|MON|TUE|WED|THU|FRI|SAT))[#][0-5])|(?:(?:(?:(?:[1-7]|(?:SUN|MON|TUE|WED|THU|FRI|SAT))L?)|[L*])(?:(?:[-](?:(?:(?:[1-7]|(?:SUN|MON|TUE|WED|THU|FRI|SAT))L?)|[L*]))|(?:[/][0-9]+))?(?:[,](?:(?:(?:[1-7]|(?:SUN|MON|TUE|WED|THU|FRI|SAT))L?)|[L*])(?:(?:[-](?:(?:(?:[1-7]|(?:SUN|MON|TUE|WED|THU|FRI|SAT))L?)|[L*]))|(?:[/][0-9]+))?)*)))|(?:(?:(?:(?:(?:[1-3]?[0-9])W?)|LW|[L*])(?:(?:[-](?:(?:(?:[1-3]?[0-9])W?)|LW|[L*]))|(?:[/][0-9]+))?(?:[,](?:(?:(?:[1-3]?[0-9])W?)|LW|[L*])(?:(?:[-](?:(?:(?:[1-3]?[0-9])W?)|LW|[L*]))|(?:[/][0-9]+))?)*)[ ]+(?:(?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:(?:[-](?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:[/][0-9]+)?)|(?:[/][0-9]+))?(?:[,](?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:(?:[-](?:(?:[1]?[0-9])|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)|[*])(?:[/][0-9]+)?)|(?:[/][0-9]+))?)*)[ ]+[?]))[ ]+(?:(?:(?:[12][0-9]{3})|[*])(?:(?:[-](?:(?:[12][0-9]{3})|[*]))|(?:[/][0-9]+))?(?:[,](?:(?:[12][0-9]{3})|[*])(?:(?:[-](?:(?:[12][0-9]{3})|[*]))|(?:[/][0-9]+))?)*)[)])$"
|
|
3750
|
+
},
|
|
3751
|
+
stringOrStringArray: {
|
|
3752
|
+
oneOf: [
|
|
3753
|
+
{
|
|
3754
|
+
type: "string",
|
|
3755
|
+
minLength: 1,
|
|
3756
|
+
maxLength: 4096
|
|
3757
|
+
},
|
|
3758
|
+
{
|
|
3759
|
+
type: "array",
|
|
3760
|
+
maxItems: 256,
|
|
3761
|
+
items: {
|
|
3762
|
+
type: "string",
|
|
3763
|
+
maxLength: 4096
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
]
|
|
3767
|
+
},
|
|
3768
|
+
queueDuration: {
|
|
3769
|
+
oneOf: [
|
|
3770
|
+
{
|
|
3771
|
+
type: "integer",
|
|
3772
|
+
minimum: 0
|
|
3773
|
+
},
|
|
3774
|
+
{
|
|
3775
|
+
type: "string",
|
|
3776
|
+
pattern: "^[0-9]+(\\.[0-9]+)?(s|m|h|d)$"
|
|
3777
|
+
}
|
|
3778
|
+
],
|
|
3779
|
+
description: "A duration in seconds, or a string such as 30s, 10m, 1.5h or 4d."
|
|
3780
|
+
},
|
|
2567
3781
|
runtimes: {
|
|
2568
3782
|
type: "string",
|
|
2569
3783
|
enum: ["php-84", "php-83", "php-81", "node-22", "node-20", "node-18", "node-16", "bun-1"]
|
|
@@ -2620,7 +3834,7 @@ var schema_default = {
|
|
|
2620
3834
|
};
|
|
2621
3835
|
|
|
2622
3836
|
// src/parse-config.ts
|
|
2623
|
-
var parseConfigRaw =
|
|
3837
|
+
var parseConfigRaw = import_effect24.Effect.fn("parseConfigRaw")(function* (filePath, projectFolder) {
|
|
2624
3838
|
const rawReader = yield* RawConfigReader;
|
|
2625
3839
|
const validator = yield* SchemaValidator;
|
|
2626
3840
|
const v4Parser = yield* V4ConfigParser;
|
|
@@ -2631,7 +3845,7 @@ var parseConfigRaw = import_effect22.Effect.fn("parseConfigRaw")(function* (file
|
|
|
2631
3845
|
};
|
|
2632
3846
|
const schema = schemaMap[version];
|
|
2633
3847
|
if (!schema) {
|
|
2634
|
-
return yield*
|
|
3848
|
+
return yield* import_effect24.Effect.fail(
|
|
2635
3849
|
new ConfigVersionError({
|
|
2636
3850
|
message: `Config file at ${filePath} has an unsupported version: ${version}`,
|
|
2637
3851
|
filePath,
|
|
@@ -2642,14 +3856,42 @@ var parseConfigRaw = import_effect22.Effect.fn("parseConfigRaw")(function* (file
|
|
|
2642
3856
|
yield* validator.validate(parsed, schema, filePath);
|
|
2643
3857
|
return yield* v4Parser.parse(parsed, projectFolder);
|
|
2644
3858
|
});
|
|
2645
|
-
var parseConfig =
|
|
3859
|
+
var parseConfig = import_effect24.Effect.fn("parseConfig")(function* (filePath, projectFolder) {
|
|
2646
3860
|
const parseResult = yield* parseConfigRaw(filePath, projectFolder);
|
|
2647
3861
|
return yield* postProcessConfig(parseResult, projectFolder);
|
|
2648
3862
|
});
|
|
2649
|
-
var postProcessConfig =
|
|
3863
|
+
var postProcessConfig = import_effect24.Effect.fn("postProcessConfig")(function* (config, projectFolder) {
|
|
2650
3864
|
const vercelParser = yield* VercelBuildOutputParser;
|
|
2651
3865
|
let result = yield* vercelParser.parse(config, projectFolder);
|
|
2652
3866
|
const hasAssets = (result.assets?.paths?.length ?? 0) > 0 || (result.assets?.prefixes?.length ?? 0) > 0 || (result.assets?.manifests?.length ?? 0) > 0;
|
|
3867
|
+
const containerFunctions = result.entrypoints.filter((entrypoint) => entrypoint.runtime === CONTAINER_RUNTIME);
|
|
3868
|
+
const [onlyFunction] = result.entrypoints;
|
|
3869
|
+
if (onlyFunction !== void 0 && onlyFunction.runtime === CONTAINER_RUNTIME && result.entrypoints.length === 1 && result.routes.length === 0 && !hasAssets) {
|
|
3870
|
+
result = {
|
|
3871
|
+
...result,
|
|
3872
|
+
routes: [
|
|
3873
|
+
{
|
|
3874
|
+
path: "/*",
|
|
3875
|
+
destination: onlyFunction.path,
|
|
3876
|
+
handler: onlyFunction.streaming === true ? "SERVERLESS_FUNCTION_STREAMING" : "SERVERLESS_FUNCTION",
|
|
3877
|
+
methods: ["ANY"],
|
|
3878
|
+
headers: {}
|
|
3879
|
+
}
|
|
3880
|
+
]
|
|
3881
|
+
};
|
|
3882
|
+
} else {
|
|
3883
|
+
for (const entrypoint of containerFunctions) {
|
|
3884
|
+
const routed = result.routes.some((route) => route.destination.replace(/^\/+/, "") === entrypoint.path);
|
|
3885
|
+
if (!routed && entrypoint.schedule === void 0) {
|
|
3886
|
+
result.warnings.push(
|
|
3887
|
+
`Container function '${entrypoint.displayName ?? entrypoint.path}' has no route and no schedule, so nothing reaches it. Add a route with destination '${entrypoint.path}'.`
|
|
3888
|
+
);
|
|
3889
|
+
}
|
|
3890
|
+
}
|
|
3891
|
+
}
|
|
3892
|
+
if ((result.sidecars?.length ?? 0) > 0 && result.entrypoints.length === 0) {
|
|
3893
|
+
result.warnings.push("Sidecars run next to functions, and this deployment has none, so no sidecar will start.");
|
|
3894
|
+
}
|
|
2653
3895
|
if (result.entrypoints.length === 0 && !hasAssets && result.routes.length === 0) {
|
|
2654
3896
|
result.errors.push(
|
|
2655
3897
|
"The current project config does not resolve to any functions, assets or routes and can not be deployed."
|
|
@@ -2675,19 +3917,22 @@ var RUNTIME_DEFINITIONS = [
|
|
|
2675
3917
|
var AVAILABLE_RUNTIMES = [...RUNTIME_DEFINITIONS];
|
|
2676
3918
|
|
|
2677
3919
|
// src/services/index.ts
|
|
2678
|
-
var
|
|
2679
|
-
var BaseLayers =
|
|
3920
|
+
var import_effect25 = require("effect");
|
|
3921
|
+
var BaseLayers = import_effect25.Layer.mergeAll(
|
|
2680
3922
|
ConfigModuleLoader.Default,
|
|
2681
3923
|
RawConfigReader.Default,
|
|
2682
3924
|
SchemaValidator.Default,
|
|
2683
3925
|
V4ConfigParser.Default
|
|
2684
3926
|
);
|
|
2685
|
-
var NetworkConfigLive = VercelBuildOutputParser.Default.pipe(
|
|
3927
|
+
var NetworkConfigLive = VercelBuildOutputParser.Default.pipe(import_effect25.Layer.provideMerge(BaseLayers));
|
|
2686
3928
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2687
3929
|
0 && (module.exports = {
|
|
2688
3930
|
ALLOWED_CONFIG_NAMES,
|
|
2689
3931
|
AVAILABLE_REGIONS,
|
|
2690
3932
|
AVAILABLE_RUNTIMES,
|
|
3933
|
+
COMPOSE_FILE_NAMES,
|
|
3934
|
+
CONTAINER_ENTRYPOINT_PREFIX,
|
|
3935
|
+
CONTAINER_RUNTIME,
|
|
2691
3936
|
ConfigFileEmptyError,
|
|
2692
3937
|
ConfigFileNotFoundError,
|
|
2693
3938
|
ConfigFileParseError,
|
|
@@ -2695,7 +3940,10 @@ var NetworkConfigLive = VercelBuildOutputParser.Default.pipe(import_effect23.Lay
|
|
|
2695
3940
|
ConfigModuleLoader,
|
|
2696
3941
|
ConfigSchemaValidationError,
|
|
2697
3942
|
ConfigVersionError,
|
|
3943
|
+
ContainerConfigError,
|
|
3944
|
+
DEFAULT_CONTAINER_MEMORY_MB,
|
|
2698
3945
|
DEFAULT_FUNCTION_DURATION_SECONDS,
|
|
3946
|
+
DEFAULT_SIDECAR_MEMORY_MB,
|
|
2699
3947
|
FRAMEWORK_DEFINITIONS,
|
|
2700
3948
|
FrameworkNotDetectedError,
|
|
2701
3949
|
FunctionConfigError,
|
|
@@ -2712,6 +3960,7 @@ var NetworkConfigLive = VercelBuildOutputParser.Default.pipe(import_effect23.Lay
|
|
|
2712
3960
|
GigadriveNextServerDescriptorSchema,
|
|
2713
3961
|
GigadriveNextStaticAssetPrefixSchema,
|
|
2714
3962
|
MAX_FUNCTION_DURATION_SECONDS,
|
|
3963
|
+
MAX_SIDECARS,
|
|
2715
3964
|
ManifestNotFoundError,
|
|
2716
3965
|
ManifestParseError,
|
|
2717
3966
|
ManifestReadError,
|
|
@@ -2724,19 +3973,26 @@ var NetworkConfigLive = VercelBuildOutputParser.Default.pipe(import_effect23.Lay
|
|
|
2724
3973
|
V4ConfigParser,
|
|
2725
3974
|
VercelBuildOutputParser,
|
|
2726
3975
|
collectAssetFiles,
|
|
3976
|
+
composeDeclaresApp,
|
|
3977
|
+
containerEntrypointPath,
|
|
2727
3978
|
defineConfig,
|
|
3979
|
+
detectContainerProject,
|
|
2728
3980
|
detectFramework,
|
|
2729
3981
|
detectPackageManager,
|
|
3982
|
+
dockerFunctionContainerName,
|
|
2730
3983
|
filterFunctionsFromAssets,
|
|
2731
3984
|
generateConfig,
|
|
2732
3985
|
getFunctionSettings,
|
|
2733
3986
|
mergeWithFrameworkDefaults,
|
|
3987
|
+
normalizeContainers,
|
|
2734
3988
|
parseConfig,
|
|
2735
3989
|
parseConfigRaw,
|
|
2736
3990
|
parseGigadriveNextBuildManifest,
|
|
2737
3991
|
parseGigadriveNextPrerenderManifest,
|
|
2738
3992
|
parseStaticAssetManifest,
|
|
2739
3993
|
postProcessConfig,
|
|
2740
|
-
|
|
3994
|
+
readComposeContainers,
|
|
3995
|
+
readDependencies,
|
|
3996
|
+
splitCommandWords
|
|
2741
3997
|
});
|
|
2742
3998
|
//# sourceMappingURL=index.js.map
|