@gigadrive/network-config 5.0.0 → 5.2.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 +492 -80
- package/dist/index.d.ts +492 -80
- package/dist/index.js +1863 -420
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1850 -421
- 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.mjs
CHANGED
|
@@ -93,16 +93,824 @@ var collectAssetFiles = Effect.fn("collectAssetFiles")(function* (projectFolder,
|
|
|
93
93
|
return files.map((file) => file.replaceAll("\\", "/")).filter((file) => !DISALLOWED_ASSET_EXTENSIONS.some((extension) => file.toLowerCase().endsWith(extension))).sort();
|
|
94
94
|
});
|
|
95
95
|
|
|
96
|
+
// src/containers.ts
|
|
97
|
+
import { FileSystem as FileSystem2, Path as Path2 } from "@effect/platform";
|
|
98
|
+
import { Effect as Effect2, Option as Option2 } from "effect";
|
|
99
|
+
import { posix } from "path";
|
|
100
|
+
import { parse as parseYaml, YAMLError } from "yaml";
|
|
101
|
+
|
|
102
|
+
// src/errors.ts
|
|
103
|
+
import { Schema as Schema3 } from "effect";
|
|
104
|
+
var ConfigFileNotFoundError = class extends Schema3.TaggedError()("ConfigFileNotFoundError", {
|
|
105
|
+
message: Schema3.String,
|
|
106
|
+
filePath: Schema3.String
|
|
107
|
+
}) {
|
|
108
|
+
};
|
|
109
|
+
var ConfigFileEmptyError = class extends Schema3.TaggedError()("ConfigFileEmptyError", {
|
|
110
|
+
message: Schema3.String,
|
|
111
|
+
filePath: Schema3.String
|
|
112
|
+
}) {
|
|
113
|
+
};
|
|
114
|
+
var ConfigFileParseError = class extends Schema3.TaggedError()("ConfigFileParseError", {
|
|
115
|
+
message: Schema3.String,
|
|
116
|
+
filePath: Schema3.String,
|
|
117
|
+
cause: Schema3.optional(Schema3.String)
|
|
118
|
+
}) {
|
|
119
|
+
};
|
|
120
|
+
var ConfigModuleLoadError = class extends Schema3.TaggedError()("ConfigModuleLoadError", {
|
|
121
|
+
message: Schema3.String,
|
|
122
|
+
filePath: Schema3.String,
|
|
123
|
+
cause: Schema3.optional(Schema3.String)
|
|
124
|
+
}) {
|
|
125
|
+
};
|
|
126
|
+
var ConfigVersionError = class extends Schema3.TaggedError()("ConfigVersionError", {
|
|
127
|
+
message: Schema3.String,
|
|
128
|
+
filePath: Schema3.String,
|
|
129
|
+
version: Schema3.optional(Schema3.Number)
|
|
130
|
+
}) {
|
|
131
|
+
};
|
|
132
|
+
var ConfigSchemaValidationError = class extends Schema3.TaggedError()(
|
|
133
|
+
"ConfigSchemaValidationError",
|
|
134
|
+
{
|
|
135
|
+
message: Schema3.String,
|
|
136
|
+
filePath: Schema3.String,
|
|
137
|
+
validationErrors: Schema3.Array(Schema3.String)
|
|
138
|
+
}
|
|
139
|
+
) {
|
|
140
|
+
};
|
|
141
|
+
var FunctionConfigError = class extends Schema3.TaggedError()("FunctionConfigError", {
|
|
142
|
+
message: Schema3.String,
|
|
143
|
+
functionPath: Schema3.String
|
|
144
|
+
}) {
|
|
145
|
+
};
|
|
146
|
+
var ContainerConfigError = class extends Schema3.TaggedError()("ContainerConfigError", {
|
|
147
|
+
message: Schema3.String,
|
|
148
|
+
containerName: Schema3.optional(Schema3.String),
|
|
149
|
+
filePath: Schema3.optional(Schema3.String)
|
|
150
|
+
}) {
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// src/normalized-config.ts
|
|
154
|
+
var DEFAULT_FUNCTION_DURATION_SECONDS = 30;
|
|
155
|
+
var MAX_FUNCTION_DURATION_SECONDS = 28800;
|
|
156
|
+
var CONTAINER_RUNTIME = "docker";
|
|
157
|
+
var CONTAINER_ENTRYPOINT_PREFIX = "container:";
|
|
158
|
+
var DEFAULT_CONTAINER_MEMORY_MB = 512;
|
|
159
|
+
var DEFAULT_SIDECAR_MEMORY_MB = 256;
|
|
160
|
+
var MAX_SIDECARS = 4;
|
|
161
|
+
|
|
162
|
+
// src/containers.ts
|
|
163
|
+
var COMPOSE_FILE_NAMES = ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"];
|
|
164
|
+
var CONTAINER_NAME_PATTERN = /^[a-z][a-z0-9_-]{0,62}$/;
|
|
165
|
+
var CONTAINER_NAME_RULES = "1 to 63 lowercase letters, digits, '-' or '_', starting with a letter, and not 'localhost'";
|
|
166
|
+
var MIN_CONTAINER_MEMORY_MB = 128;
|
|
167
|
+
var MAX_CONTAINER_MEMORY_MB = 3009;
|
|
168
|
+
var MAX_CONTAINER_ENV_VARS = 100;
|
|
169
|
+
var MAX_CONTAINER_ENV_VALUE_LENGTH = 65536;
|
|
170
|
+
var containerEntrypointPath = (name) => `${CONTAINER_ENTRYPOINT_PREFIX}${name}`;
|
|
171
|
+
var toContainerName = (raw) => {
|
|
172
|
+
const cleaned = raw.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^[^a-z0-9]+/, "");
|
|
173
|
+
const name = (cleaned === "" || /^[a-z]/.test(cleaned) ? cleaned : `app-${cleaned}`).slice(0, 63);
|
|
174
|
+
return name === "" || name === "localhost" ? "app" : name;
|
|
175
|
+
};
|
|
176
|
+
var dockerFunctionContainerName = (file) => {
|
|
177
|
+
const { dir, base } = posix.parse(file);
|
|
178
|
+
const variant = base.replace(/^Dockerfile[.-]?/i, "").replace(/[.-]?Dockerfile$/i, "");
|
|
179
|
+
const raw = [posix.basename(dir), variant === base ? posix.parse(base).name : variant].filter((part) => part !== "").join("-");
|
|
180
|
+
return toContainerName(raw);
|
|
181
|
+
};
|
|
182
|
+
var splitCommandWords = (input) => {
|
|
183
|
+
const words = [];
|
|
184
|
+
let current = "";
|
|
185
|
+
let inWord = false;
|
|
186
|
+
let quote;
|
|
187
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
188
|
+
const char = input[index];
|
|
189
|
+
if (quote === "'") {
|
|
190
|
+
if (char === "'") quote = void 0;
|
|
191
|
+
else current += char;
|
|
192
|
+
} else if (char === "\\" && index + 1 < input.length) {
|
|
193
|
+
index += 1;
|
|
194
|
+
current += input[index];
|
|
195
|
+
inWord = true;
|
|
196
|
+
} else if (quote === '"') {
|
|
197
|
+
if (char === '"') quote = void 0;
|
|
198
|
+
else current += char;
|
|
199
|
+
} else if (char === "'" || char === '"') {
|
|
200
|
+
quote = char;
|
|
201
|
+
inWord = true;
|
|
202
|
+
} else if (/\s/.test(char)) {
|
|
203
|
+
if (inWord) words.push(current);
|
|
204
|
+
current = "";
|
|
205
|
+
inWord = false;
|
|
206
|
+
} else {
|
|
207
|
+
current += char;
|
|
208
|
+
inWord = true;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (quote) throw new Error(`Unterminated ${quote} quote`);
|
|
212
|
+
if (inWord) words.push(current);
|
|
213
|
+
return words;
|
|
214
|
+
};
|
|
215
|
+
var normalizeProjectPath = (input) => {
|
|
216
|
+
if (posix.isAbsolute(input)) return void 0;
|
|
217
|
+
const normalized = posix.normalize(input.replace(/\\/g, "/")).replace(/\/+$/, "") || ".";
|
|
218
|
+
if (normalized === ".." || normalized.startsWith("../")) return void 0;
|
|
219
|
+
return normalized;
|
|
220
|
+
};
|
|
221
|
+
var resolveProjectRoot = (projectFolder) => Effect2.flatMap(
|
|
222
|
+
FileSystem2.FileSystem,
|
|
223
|
+
(fs) => fs.realPath(projectFolder).pipe(Effect2.orElseSucceed(() => projectFolder))
|
|
224
|
+
);
|
|
225
|
+
var resolveInsideProject = (projectRoot, projectRelative, subject, context) => Effect2.gen(function* () {
|
|
226
|
+
const fs = yield* FileSystem2.FileSystem;
|
|
227
|
+
const pathSvc = yield* Path2.Path;
|
|
228
|
+
const resolved = yield* fs.realPath(pathSvc.join(projectRoot, projectRelative)).pipe(Effect2.option);
|
|
229
|
+
if (Option2.isNone(resolved)) return resolved;
|
|
230
|
+
const relative = pathSvc.relative(projectRoot, resolved.value);
|
|
231
|
+
if (relative === ".." || relative.startsWith(`..${pathSvc.sep}`) || pathSvc.isAbsolute(relative)) {
|
|
232
|
+
return yield* new ContainerConfigError({
|
|
233
|
+
message: `${subject} leads through a symbolic link to a location outside the project. Only files inside the project can be deployed.`,
|
|
234
|
+
...context
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
return resolved;
|
|
238
|
+
});
|
|
239
|
+
var readInsideProject = (projectRoot, projectRelative, subject, context) => Effect2.gen(function* () {
|
|
240
|
+
const fs = yield* FileSystem2.FileSystem;
|
|
241
|
+
const resolved = yield* resolveInsideProject(projectRoot, projectRelative, subject, context);
|
|
242
|
+
if (Option2.isNone(resolved)) return Option2.none();
|
|
243
|
+
return yield* fs.readFileString(resolved.value).pipe(Effect2.option);
|
|
244
|
+
});
|
|
245
|
+
var toArgv = (name, key, value) => value === void 0 ? Effect2.succeed(void 0) : Array.isArray(value) ? Effect2.succeed(value) : Effect2.try({
|
|
246
|
+
try: () => splitCommandWords(value),
|
|
247
|
+
catch: (error) => new ContainerConfigError({
|
|
248
|
+
message: `Container '${name}' has an invalid ${key}: ${error instanceof Error ? error.message : String(error)}`,
|
|
249
|
+
containerName: name
|
|
250
|
+
})
|
|
251
|
+
});
|
|
252
|
+
var isIntegerBetween = (value, min, max) => Number.isInteger(value) && value >= min && value <= max;
|
|
253
|
+
var validateContainer = (name, container) => {
|
|
254
|
+
const build = typeof container.build === "object" ? container.build : void 0;
|
|
255
|
+
const buildArgs = Object.values(build?.args ?? {});
|
|
256
|
+
const env = Object.entries(container.env ?? {});
|
|
257
|
+
const user = container.user === void 0 ? void 0 : String(container.user);
|
|
258
|
+
const badEnvKey = env.find(([key]) => key === "" || key.includes("=") || key.includes("\0"))?.[0];
|
|
259
|
+
const longEnvKey = env.find(([, value]) => value.length > MAX_CONTAINER_ENV_VALUE_LENGTH)?.[0];
|
|
260
|
+
const problem = [
|
|
261
|
+
[
|
|
262
|
+
container.image !== void 0 && !/^\S{1,512}$/.test(container.image),
|
|
263
|
+
"has an invalid image reference. Use 1 to 512 characters without whitespace."
|
|
264
|
+
],
|
|
265
|
+
[
|
|
266
|
+
container.port !== void 0 && !isIntegerBetween(container.port, 1, 65535),
|
|
267
|
+
`listens on port ${container.port}. Use a whole number from 1 to 65535.`
|
|
268
|
+
],
|
|
269
|
+
[
|
|
270
|
+
container.memory !== void 0 && !isIntegerBetween(container.memory, MIN_CONTAINER_MEMORY_MB, MAX_CONTAINER_MEMORY_MB),
|
|
271
|
+
`asks for ${container.memory} MB of memory. Use a whole number from ${MIN_CONTAINER_MEMORY_MB} to ${MAX_CONTAINER_MEMORY_MB}.`
|
|
272
|
+
],
|
|
273
|
+
[
|
|
274
|
+
container.working_dir !== void 0 && !(container.working_dir.startsWith("/") && container.working_dir.length <= 1024),
|
|
275
|
+
`sets working_dir '${container.working_dir}', which must be an absolute path of at most 1024 characters.`
|
|
276
|
+
],
|
|
277
|
+
[
|
|
278
|
+
typeof container.user === "number" && !isIntegerBetween(container.user, 0, Number.MAX_SAFE_INTEGER),
|
|
279
|
+
`sets user ${container.user}. A numeric user must be a non-negative whole number.`
|
|
280
|
+
],
|
|
281
|
+
[
|
|
282
|
+
user !== void 0 && (user.length === 0 || user.length > 256),
|
|
283
|
+
"sets an empty or overlong user. Use 1 to 256 characters: a name, a uid, name:group or uid:gid."
|
|
284
|
+
],
|
|
285
|
+
[
|
|
286
|
+
build?.target !== void 0 && (build.target.length === 0 || build.target.length > 128),
|
|
287
|
+
"has an empty build target or one longer than 128 characters."
|
|
288
|
+
],
|
|
289
|
+
[
|
|
290
|
+
buildArgs.length > MAX_CONTAINER_ENV_VARS || buildArgs.some((value) => value.length > MAX_CONTAINER_ENV_VALUE_LENGTH),
|
|
291
|
+
`sets more than ${MAX_CONTAINER_ENV_VARS} build args, or one longer than ${MAX_CONTAINER_ENV_VALUE_LENGTH} characters.`
|
|
292
|
+
],
|
|
293
|
+
[
|
|
294
|
+
env.length > MAX_CONTAINER_ENV_VARS,
|
|
295
|
+
`sets ${env.length} environment variables. At most ${MAX_CONTAINER_ENV_VARS} are allowed.`
|
|
296
|
+
],
|
|
297
|
+
[
|
|
298
|
+
badEnvKey !== void 0,
|
|
299
|
+
`sets an environment variable named '${badEnvKey}'. Names must be non-empty and contain no '='.`
|
|
300
|
+
],
|
|
301
|
+
[
|
|
302
|
+
longEnvKey !== void 0,
|
|
303
|
+
`sets environment variable '${longEnvKey}' to a value longer than ${MAX_CONTAINER_ENV_VALUE_LENGTH} characters.`
|
|
304
|
+
]
|
|
305
|
+
].find(([failed]) => failed)?.[1];
|
|
306
|
+
return problem === void 0 ? Effect2.void : Effect2.fail(new ContainerConfigError({ message: `Container '${name}' ${problem}`, containerName: name }));
|
|
307
|
+
};
|
|
308
|
+
var toContainerSpec = Effect2.fn("toContainerSpec")(function* (name, container, projectFolder) {
|
|
309
|
+
yield* validateContainer(name, container);
|
|
310
|
+
let source;
|
|
311
|
+
if (container.image !== void 0 && container.build === void 0) {
|
|
312
|
+
source = { type: "registry", reference: container.image };
|
|
313
|
+
} else if (container.build !== void 0 && container.image === void 0) {
|
|
314
|
+
const build = typeof container.build === "string" ? { context: container.build } : container.build;
|
|
315
|
+
const dockerfile = build.dockerfile ?? "Dockerfile";
|
|
316
|
+
const context = normalizeProjectPath(build.context ?? ".");
|
|
317
|
+
const dockerfilePath = context === void 0 || posix.isAbsolute(dockerfile) ? void 0 : normalizeProjectPath(posix.join(context, dockerfile));
|
|
318
|
+
if (context === void 0 || dockerfilePath === void 0) {
|
|
319
|
+
return yield* new ContainerConfigError({
|
|
320
|
+
message: `Container '${name}' has a build context or Dockerfile outside the project.`,
|
|
321
|
+
containerName: name
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
const projectRoot = yield* resolveProjectRoot(projectFolder);
|
|
325
|
+
yield* resolveInsideProject(projectRoot, context, `The build context '${context}' of container '${name}'`, {
|
|
326
|
+
containerName: name
|
|
327
|
+
});
|
|
328
|
+
const dockerfileReal = yield* resolveInsideProject(
|
|
329
|
+
projectRoot,
|
|
330
|
+
dockerfilePath,
|
|
331
|
+
`The Dockerfile '${dockerfilePath}' of container '${name}'`,
|
|
332
|
+
{ containerName: name }
|
|
333
|
+
);
|
|
334
|
+
if (Option2.isNone(dockerfileReal)) {
|
|
335
|
+
return yield* new ContainerConfigError({
|
|
336
|
+
message: `Container '${name}' builds '${dockerfilePath}', which does not exist.`,
|
|
337
|
+
containerName: name
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
source = {
|
|
341
|
+
type: "dockerfile",
|
|
342
|
+
context,
|
|
343
|
+
dockerfile: posix.relative(context, dockerfilePath),
|
|
344
|
+
...build.target !== void 0 && { target: build.target },
|
|
345
|
+
...build.args !== void 0 && Object.keys(build.args).length > 0 && { buildArgs: { ...build.args } }
|
|
346
|
+
};
|
|
347
|
+
} else {
|
|
348
|
+
return yield* new ContainerConfigError({
|
|
349
|
+
message: `Container '${name}' must set exactly one of 'image' and 'build'.`,
|
|
350
|
+
containerName: name
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
const entrypoint = yield* toArgv(name, "entrypoint", container.entrypoint);
|
|
354
|
+
const command = yield* toArgv(name, "command", container.command);
|
|
355
|
+
const spec = {
|
|
356
|
+
name,
|
|
357
|
+
source,
|
|
358
|
+
...container.port !== void 0 && { port: container.port },
|
|
359
|
+
...entrypoint !== void 0 && { entrypoint },
|
|
360
|
+
...command !== void 0 && { command },
|
|
361
|
+
...container.working_dir !== void 0 && { workingDirectory: container.working_dir },
|
|
362
|
+
...container.user !== void 0 && { user: String(container.user) },
|
|
363
|
+
...container.env !== void 0 && Object.keys(container.env).length > 0 && { environmentVariables: { ...container.env } }
|
|
364
|
+
};
|
|
365
|
+
return spec;
|
|
366
|
+
});
|
|
367
|
+
var normalizeContainers = Effect2.fn("normalizeContainers")(function* (containers, projectFolder) {
|
|
368
|
+
const entrypoints = [];
|
|
369
|
+
const sidecars = [];
|
|
370
|
+
const warnings = [];
|
|
371
|
+
for (const [name, container] of Object.entries(containers)) {
|
|
372
|
+
if (!CONTAINER_NAME_PATTERN.test(name) || name === "localhost") {
|
|
373
|
+
return yield* new ContainerConfigError({
|
|
374
|
+
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)}'.`,
|
|
375
|
+
containerName: name
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
const spec = yield* toContainerSpec(name, container, projectFolder);
|
|
379
|
+
if (container.sidecar === true) {
|
|
380
|
+
const ignored = ["max_duration", "streaming", "schedule"].filter(
|
|
381
|
+
(key) => container[key] !== void 0
|
|
382
|
+
);
|
|
383
|
+
if (ignored.length > 0) {
|
|
384
|
+
warnings.push(
|
|
385
|
+
`Sidecar '${name}' ignores ${ignored.join(", ")}: those settings apply to container functions only.`
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
sidecars.push({ ...spec, memory: container.memory ?? DEFAULT_SIDECAR_MEMORY_MB });
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
entrypoints.push({
|
|
392
|
+
path: containerEntrypointPath(name),
|
|
393
|
+
displayName: name,
|
|
394
|
+
runtime: CONTAINER_RUNTIME,
|
|
395
|
+
memory: container.memory ?? DEFAULT_CONTAINER_MEMORY_MB,
|
|
396
|
+
maxDuration: container.max_duration ?? DEFAULT_FUNCTION_DURATION_SECONDS,
|
|
397
|
+
streaming: container.streaming ?? true,
|
|
398
|
+
...container.schedule !== void 0 && { schedule: container.schedule },
|
|
399
|
+
container: spec
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
if (sidecars.length > MAX_SIDECARS) {
|
|
403
|
+
return yield* new ContainerConfigError({
|
|
404
|
+
message: `A deployment may declare at most ${MAX_SIDECARS} sidecars; this one declares ${sidecars.length}.`
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
const sidecarPorts = /* @__PURE__ */ new Map();
|
|
408
|
+
for (const sidecar of sidecars) {
|
|
409
|
+
if (sidecar.port === void 0) continue;
|
|
410
|
+
const owner = sidecarPorts.get(sidecar.port);
|
|
411
|
+
if (owner !== void 0) {
|
|
412
|
+
return yield* new ContainerConfigError({
|
|
413
|
+
message: `Sidecars '${owner}' and '${sidecar.name}' both listen on port ${sidecar.port}. Sidecars share one network namespace, so their ports must differ.`,
|
|
414
|
+
containerName: sidecar.name
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
sidecarPorts.set(sidecar.port, sidecar.name);
|
|
418
|
+
}
|
|
419
|
+
for (const entrypoint of entrypoints) {
|
|
420
|
+
const port = entrypoint.container?.port;
|
|
421
|
+
const sidecar = port === void 0 ? void 0 : sidecarPorts.get(port);
|
|
422
|
+
if (sidecar !== void 0) {
|
|
423
|
+
return yield* new ContainerConfigError({
|
|
424
|
+
message: `Container '${entrypoint.displayName}' and sidecar '${sidecar}' both listen on port ${port}. Sidecars run inside the function's microVM, so their ports must differ.`,
|
|
425
|
+
containerName: sidecar
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
return { entrypoints, sidecars, warnings };
|
|
430
|
+
});
|
|
431
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
432
|
+
var isStringArray = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
433
|
+
var scalarToString = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : void 0;
|
|
434
|
+
var gigadriveExtension = (service) => isRecord(service["x-gigadrive"]) ? service["x-gigadrive"] : {};
|
|
435
|
+
var COMPOSE_OVERRIDE_FILE_NAMES = [
|
|
436
|
+
"compose.override.yaml",
|
|
437
|
+
"compose.override.yml",
|
|
438
|
+
"docker-compose.override.yaml",
|
|
439
|
+
"docker-compose.override.yml"
|
|
440
|
+
];
|
|
441
|
+
var findClosingQuote = (body, quote) => {
|
|
442
|
+
for (let index = 0; index < body.length; index += 1) {
|
|
443
|
+
if (quote === '"' && body[index] === "\\") index += 1;
|
|
444
|
+
else if (body[index] === quote) return index;
|
|
445
|
+
}
|
|
446
|
+
return -1;
|
|
447
|
+
};
|
|
448
|
+
var DOUBLE_QUOTE_ESCAPES = { n: "\n", r: "\r", t: " " };
|
|
449
|
+
var parseDotEnv = (content) => {
|
|
450
|
+
const values = {};
|
|
451
|
+
const lines = content.split(/\r?\n/);
|
|
452
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
453
|
+
const match = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_.-]*)\s*=(.*)$/.exec(lines[index]);
|
|
454
|
+
if (!match) continue;
|
|
455
|
+
const [, key, rest] = match;
|
|
456
|
+
const quote = rest.trimStart()[0];
|
|
457
|
+
if (quote === '"' || quote === "'") {
|
|
458
|
+
let body = rest.trimStart().slice(1);
|
|
459
|
+
let end = index;
|
|
460
|
+
let close = findClosingQuote(body, quote);
|
|
461
|
+
while (close === -1 && end + 1 < lines.length) {
|
|
462
|
+
end += 1;
|
|
463
|
+
body += `
|
|
464
|
+
${lines[end]}`;
|
|
465
|
+
close = findClosingQuote(body, quote);
|
|
466
|
+
}
|
|
467
|
+
if (close !== -1) {
|
|
468
|
+
const raw = body.slice(0, close);
|
|
469
|
+
values[key] = quote === '"' ? raw.replace(/\\([nrt"\\])/g, (_match, char) => DOUBLE_QUOTE_ESCAPES[char] ?? char) : raw;
|
|
470
|
+
index = end;
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
values[key] = rest.replace(/\s+#.*$/, "").trim();
|
|
475
|
+
}
|
|
476
|
+
return values;
|
|
477
|
+
};
|
|
478
|
+
var InterpolationError = class extends Error {
|
|
479
|
+
};
|
|
480
|
+
var findClosingBrace = (value, start) => {
|
|
481
|
+
let depth = 0;
|
|
482
|
+
for (let index = start; index < value.length; index += 1) {
|
|
483
|
+
if (value[index] === "$" && (value[index + 1] === "$" || value[index + 1] === "{")) {
|
|
484
|
+
if (value[index + 1] === "{") depth += 1;
|
|
485
|
+
index += 1;
|
|
486
|
+
} else if (value[index] === "}") {
|
|
487
|
+
if (depth === 0) return index;
|
|
488
|
+
depth -= 1;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return -1;
|
|
492
|
+
};
|
|
493
|
+
var interpolate = (value, variables, missing, where) => {
|
|
494
|
+
let result = "";
|
|
495
|
+
let index = 0;
|
|
496
|
+
while (index < value.length) {
|
|
497
|
+
const dollar = value.indexOf("$", index);
|
|
498
|
+
if (dollar === -1) {
|
|
499
|
+
result += value.slice(index);
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
result += value.slice(index, dollar);
|
|
503
|
+
const next = value[dollar + 1];
|
|
504
|
+
if (next === "$") {
|
|
505
|
+
result += "$";
|
|
506
|
+
index = dollar + 2;
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
if (next === "{") {
|
|
510
|
+
const close = findClosingBrace(value, dollar + 2);
|
|
511
|
+
const expression = close === -1 ? null : /^([A-Za-z_][A-Za-z0-9_]*)(?:(:?[-?+])([\s\S]*))?$/.exec(value.slice(dollar + 2, close));
|
|
512
|
+
if (expression === null) {
|
|
513
|
+
throw new InterpolationError(`has an invalid variable reference in ${where}. Write '$$' for a literal '$'.`);
|
|
514
|
+
}
|
|
515
|
+
const [, name, operator, operand = ""] = expression;
|
|
516
|
+
const current = variables[name];
|
|
517
|
+
const isSet = current !== void 0 && !(operator?.startsWith(":") === true && current === "");
|
|
518
|
+
if (operator === void 0) {
|
|
519
|
+
if (current === void 0) missing.add(name);
|
|
520
|
+
result += current ?? "";
|
|
521
|
+
} else if (operator.endsWith("-")) {
|
|
522
|
+
result += isSet ? current : interpolate(operand, variables, missing, where);
|
|
523
|
+
} else if (operator.endsWith("+")) {
|
|
524
|
+
result += isSet ? interpolate(operand, variables, missing, where) : "";
|
|
525
|
+
} else if (isSet) {
|
|
526
|
+
result += current;
|
|
527
|
+
} else {
|
|
528
|
+
const reason = interpolate(operand, variables, missing, where);
|
|
529
|
+
throw new InterpolationError(
|
|
530
|
+
`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.`
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
index = close + 1;
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
const bare = /^[A-Za-z_][A-Za-z0-9_]*/.exec(value.slice(dollar + 1))?.[0];
|
|
537
|
+
if (bare === void 0) {
|
|
538
|
+
result += "$";
|
|
539
|
+
index = dollar + 1;
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
if (variables[bare] === void 0) missing.add(bare);
|
|
543
|
+
result += variables[bare] ?? "";
|
|
544
|
+
index = dollar + 1 + bare.length;
|
|
545
|
+
}
|
|
546
|
+
return result;
|
|
547
|
+
};
|
|
548
|
+
var interpolateDeep = (value, variables, missing, where) => {
|
|
549
|
+
if (typeof value === "string") return interpolate(value, variables, missing, where);
|
|
550
|
+
if (Array.isArray(value)) {
|
|
551
|
+
return value.map((item, index) => interpolateDeep(item, variables, missing, `${where}[${index}]`));
|
|
552
|
+
}
|
|
553
|
+
if (isRecord(value)) {
|
|
554
|
+
return Object.fromEntries(
|
|
555
|
+
Object.entries(value).map(([key, item]) => [
|
|
556
|
+
key,
|
|
557
|
+
interpolateDeep(item, variables, missing, where === "" ? key : `${where}.${key}`)
|
|
558
|
+
])
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
return value;
|
|
562
|
+
};
|
|
563
|
+
var parseComposeMemory = (value) => {
|
|
564
|
+
if (typeof value === "number") {
|
|
565
|
+
return Number.isFinite(value) && value >= 0 ? Math.ceil(value / 1024 ** 2) : void 0;
|
|
566
|
+
}
|
|
567
|
+
if (typeof value !== "string") return void 0;
|
|
568
|
+
const match = /^(\d+(?:\.\d+)?) ?([kmgtp])?i?b?$/i.exec(value.trim());
|
|
569
|
+
if (!match) return void 0;
|
|
570
|
+
const exponent = " kmgtp".indexOf((match[2] ?? " ").toLowerCase());
|
|
571
|
+
return Math.ceil(Number(match[1]) * 1024 ** exponent / 1024 ** 2);
|
|
572
|
+
};
|
|
573
|
+
var parseComposePort = (entry) => {
|
|
574
|
+
let port = entry;
|
|
575
|
+
if (isRecord(entry)) {
|
|
576
|
+
if (typeof entry.protocol === "string" && entry.protocol.toLowerCase() !== "tcp") return void 0;
|
|
577
|
+
port = entry.target;
|
|
578
|
+
} else if (typeof entry === "string") {
|
|
579
|
+
const [withoutProtocol, protocol] = entry.split("/");
|
|
580
|
+
if (protocol !== void 0 && protocol.toLowerCase() !== "tcp") return void 0;
|
|
581
|
+
port = (withoutProtocol.split(":").at(-1) ?? "").split("-")[0];
|
|
582
|
+
}
|
|
583
|
+
const number = typeof port === "number" ? port : typeof port === "string" && /^\d+$/.test(port) ? Number(port) : NaN;
|
|
584
|
+
return isIntegerBetween(number, 1, 65535) ? number : void 0;
|
|
585
|
+
};
|
|
586
|
+
var parseComposeEnvironment = (serviceName, value, warnings) => {
|
|
587
|
+
if (value === void 0 || value === null) return void 0;
|
|
588
|
+
const environment = {};
|
|
589
|
+
if (Array.isArray(value)) {
|
|
590
|
+
for (const item of value) {
|
|
591
|
+
if (typeof item !== "string") continue;
|
|
592
|
+
const separator = item.indexOf("=");
|
|
593
|
+
if (separator === -1) {
|
|
594
|
+
warnings.push(
|
|
595
|
+
`Compose service '${serviceName}' takes '${item}' from the host environment, which deployments do not have. Set it in the console instead.`
|
|
596
|
+
);
|
|
597
|
+
continue;
|
|
598
|
+
}
|
|
599
|
+
environment[item.slice(0, separator)] = item.slice(separator + 1);
|
|
600
|
+
}
|
|
601
|
+
} else if (isRecord(value)) {
|
|
602
|
+
for (const [key, item] of Object.entries(value)) {
|
|
603
|
+
const scalar = scalarToString(item);
|
|
604
|
+
if (scalar === void 0) {
|
|
605
|
+
warnings.push(
|
|
606
|
+
`Compose service '${serviceName}' takes '${key}' from the host environment, which deployments do not have. Set it in the console instead.`
|
|
607
|
+
);
|
|
608
|
+
continue;
|
|
609
|
+
}
|
|
610
|
+
environment[key] = scalar;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return environment;
|
|
614
|
+
};
|
|
615
|
+
var isPublicMarked = (service) => gigadriveExtension(service).public === true;
|
|
616
|
+
var buildsFromSource = (service) => service.build !== void 0 && gigadriveExtension(service).sidecar !== true;
|
|
617
|
+
var loadComposeServices = Effect2.fn("loadComposeServices")(function* (composePath, projectFolder) {
|
|
618
|
+
const relativePath = normalizeProjectPath(composePath);
|
|
619
|
+
if (relativePath === void 0) {
|
|
620
|
+
return yield* new ContainerConfigError({
|
|
621
|
+
message: `Compose file '${composePath}' is outside the project.`,
|
|
622
|
+
filePath: composePath
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
const projectRoot = yield* resolveProjectRoot(projectFolder);
|
|
626
|
+
const content = yield* readInsideProject(projectRoot, relativePath, `Compose file '${relativePath}'`, {
|
|
627
|
+
filePath: relativePath
|
|
628
|
+
});
|
|
629
|
+
if (Option2.isNone(content)) {
|
|
630
|
+
return yield* new ContainerConfigError({
|
|
631
|
+
message: `Compose file '${relativePath}' could not be read.`,
|
|
632
|
+
filePath: relativePath
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
const document = yield* Effect2.try({
|
|
636
|
+
try: () => parseYaml(content.value),
|
|
637
|
+
catch: (error) => {
|
|
638
|
+
const position = error instanceof YAMLError ? error.linePos?.[0] : void 0;
|
|
639
|
+
return new ContainerConfigError({
|
|
640
|
+
message: `Compose file '${relativePath}' is not valid YAML${position ? ` (line ${position.line}, column ${position.col})` : ""}.`,
|
|
641
|
+
filePath: relativePath
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
if (!isRecord(document) || !isRecord(document.services) || Object.keys(document.services).length === 0) {
|
|
646
|
+
return yield* new ContainerConfigError({
|
|
647
|
+
message: `Compose file '${relativePath}' declares no services.`,
|
|
648
|
+
filePath: relativePath
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
const services = Object.entries(document.services).filter(
|
|
652
|
+
(entry) => isRecord(entry[1]) && !(isStringArray(entry[1].profiles) && entry[1].profiles.length > 0) && gigadriveExtension(entry[1]).skip !== true
|
|
653
|
+
);
|
|
654
|
+
return { relativePath, projectRoot, services };
|
|
655
|
+
});
|
|
656
|
+
var composeDeclaresApp = Effect2.fn("composeDeclaresApp")(function* (composePath, projectFolder) {
|
|
657
|
+
const { services } = yield* loadComposeServices(composePath, projectFolder);
|
|
658
|
+
return services.some(([, service]) => isPublicMarked(service) || buildsFromSource(service));
|
|
659
|
+
});
|
|
660
|
+
var readComposeContainers = Effect2.fn("readComposeContainers")(function* (composePath, projectFolder) {
|
|
661
|
+
const fs = yield* FileSystem2.FileSystem;
|
|
662
|
+
const pathSvc = yield* Path2.Path;
|
|
663
|
+
const { relativePath, projectRoot, services } = yield* loadComposeServices(composePath, projectFolder);
|
|
664
|
+
const composeDirectory = posix.dirname(relativePath);
|
|
665
|
+
const warnings = [];
|
|
666
|
+
for (const [name] of services) {
|
|
667
|
+
if (!CONTAINER_NAME_PATTERN.test(name) || name === "localhost") {
|
|
668
|
+
return yield* new ContainerConfigError({
|
|
669
|
+
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}'.`,
|
|
670
|
+
containerName: name,
|
|
671
|
+
filePath: relativePath
|
|
672
|
+
});
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
const marked = services.filter(([, service]) => isPublicMarked(service)).map(([name]) => name);
|
|
676
|
+
const built = services.filter(([, service]) => buildsFromSource(service)).map(([name]) => name);
|
|
677
|
+
if (marked.length > 1) {
|
|
678
|
+
return yield* new ContainerConfigError({
|
|
679
|
+
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.`,
|
|
680
|
+
filePath: relativePath
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
const publicService = marked[0] ?? (built.length === 1 ? built[0] : void 0);
|
|
684
|
+
if (publicService === void 0) {
|
|
685
|
+
return yield* new ContainerConfigError({
|
|
686
|
+
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 }'.`,
|
|
687
|
+
filePath: relativePath
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
if (COMPOSE_FILE_NAMES.includes(posix.basename(relativePath))) {
|
|
691
|
+
for (const overrideName of COMPOSE_OVERRIDE_FILE_NAMES) {
|
|
692
|
+
const overridePath = posix.join(composeDirectory, overrideName);
|
|
693
|
+
const overrideExists = yield* fs.exists(pathSvc.join(projectRoot, overridePath)).pipe(Effect2.orElseSucceed(() => false));
|
|
694
|
+
if (overrideExists) {
|
|
695
|
+
warnings.push(
|
|
696
|
+
`Compose file '${relativePath}' has the override file '${overridePath}' next to it, which is not merged. Move its settings into '${relativePath}' or gigadrive.yaml.`
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
const dotEnv = yield* readInsideProject(
|
|
702
|
+
projectRoot,
|
|
703
|
+
posix.join(composeDirectory, ".env"),
|
|
704
|
+
`The .env file next to '${relativePath}'`,
|
|
705
|
+
{ filePath: relativePath }
|
|
706
|
+
);
|
|
707
|
+
const variables = Option2.isSome(dotEnv) ? parseDotEnv(dotEnv.value) : {};
|
|
708
|
+
const missing = /* @__PURE__ */ new Set();
|
|
709
|
+
const containers = {};
|
|
710
|
+
for (const [name, rawService] of services) {
|
|
711
|
+
const isPublic = name === publicService;
|
|
712
|
+
const service = yield* Effect2.try({
|
|
713
|
+
try: () => interpolateDeep(rawService, variables, missing, ""),
|
|
714
|
+
catch: (error) => new ContainerConfigError({
|
|
715
|
+
message: `Compose service '${name}' ${error instanceof InterpolationError ? error.message : "could not be interpolated."}`,
|
|
716
|
+
containerName: name,
|
|
717
|
+
filePath: relativePath
|
|
718
|
+
})
|
|
719
|
+
});
|
|
720
|
+
const container = {};
|
|
721
|
+
if (service.extends !== void 0) {
|
|
722
|
+
warnings.push(
|
|
723
|
+
`Compose service '${name}' uses 'extends', which is not supported. The service is deployed as written, without the settings it would inherit.`
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
if (typeof service.image === "string" && service.build === void 0) {
|
|
727
|
+
container.image = service.image;
|
|
728
|
+
} else if (typeof service.build === "string" || isRecord(service.build)) {
|
|
729
|
+
const build = typeof service.build === "string" ? { context: service.build } : service.build;
|
|
730
|
+
if (build.dockerfile_inline !== void 0) {
|
|
731
|
+
return yield* new ContainerConfigError({
|
|
732
|
+
message: `Compose service '${name}' uses build.dockerfile_inline, which is not supported. Commit the Dockerfile and point build.dockerfile at it.`,
|
|
733
|
+
containerName: name,
|
|
734
|
+
filePath: relativePath
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
const rawContext = typeof build.context === "string" ? build.context : ".";
|
|
738
|
+
const context = posix.isAbsolute(rawContext) ? rawContext : posix.join(composeDirectory, rawContext);
|
|
739
|
+
const args = Array.isArray(build.args) ? Object.fromEntries(
|
|
740
|
+
build.args.filter((item) => typeof item === "string" && item.includes("=")).map((item) => [item.slice(0, item.indexOf("=")), item.slice(item.indexOf("=") + 1)])
|
|
741
|
+
) : isRecord(build.args) ? Object.fromEntries(Object.entries(build.args).map(([key, item]) => [key, scalarToString(item) ?? ""])) : void 0;
|
|
742
|
+
container.build = {
|
|
743
|
+
context,
|
|
744
|
+
...typeof build.dockerfile === "string" && { dockerfile: build.dockerfile },
|
|
745
|
+
...typeof build.target === "string" && { target: build.target },
|
|
746
|
+
...args !== void 0 && Object.keys(args).length > 0 && { args }
|
|
747
|
+
};
|
|
748
|
+
} else {
|
|
749
|
+
return yield* new ContainerConfigError({
|
|
750
|
+
message: `Compose service '${name}' has neither an image nor a build.`,
|
|
751
|
+
containerName: name,
|
|
752
|
+
filePath: relativePath
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
if (!isPublic) container.sidecar = true;
|
|
756
|
+
const ports = [
|
|
757
|
+
...isPublic && Array.isArray(service.ports) ? service.ports : [],
|
|
758
|
+
...Array.isArray(service.expose) ? service.expose : [],
|
|
759
|
+
...!isPublic && Array.isArray(service.ports) ? service.ports : []
|
|
760
|
+
];
|
|
761
|
+
const port = ports.map(parseComposePort).find((value) => value !== void 0);
|
|
762
|
+
if (port !== void 0) container.port = port;
|
|
763
|
+
for (const key of ["entrypoint", "command"]) {
|
|
764
|
+
const value = service[key];
|
|
765
|
+
if (typeof value === "string" || isStringArray(value)) container[key] = value;
|
|
766
|
+
}
|
|
767
|
+
const environment = {};
|
|
768
|
+
const envFiles = (typeof service.env_file === "string" ? [service.env_file] : Array.isArray(service.env_file) ? service.env_file : []).flatMap(
|
|
769
|
+
(entry) => typeof entry === "string" ? [{ path: entry }] : isRecord(entry) && typeof entry.path === "string" ? [{ path: entry.path, ...typeof entry.required === "boolean" && { required: entry.required } }] : []
|
|
770
|
+
);
|
|
771
|
+
for (const envFile of envFiles) {
|
|
772
|
+
const envFilePath = posix.isAbsolute(envFile.path) ? void 0 : normalizeProjectPath(posix.join(composeDirectory, envFile.path));
|
|
773
|
+
const envContent = envFilePath === void 0 ? Option2.none() : yield* readInsideProject(
|
|
774
|
+
projectRoot,
|
|
775
|
+
envFilePath,
|
|
776
|
+
`The env_file '${envFile.path}' of Compose service '${name}'`,
|
|
777
|
+
{ containerName: name, filePath: relativePath }
|
|
778
|
+
);
|
|
779
|
+
if (Option2.isSome(envContent)) {
|
|
780
|
+
Object.assign(environment, parseDotEnv(envContent.value));
|
|
781
|
+
} else if (envFile.required === true) {
|
|
782
|
+
return yield* new ContainerConfigError({
|
|
783
|
+
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.`,
|
|
784
|
+
containerName: name,
|
|
785
|
+
filePath: relativePath
|
|
786
|
+
});
|
|
787
|
+
} else if (envFile.required === void 0) {
|
|
788
|
+
warnings.push(
|
|
789
|
+
`Compose service '${name}' reads env_file '${envFile.path}', which is not in the deployed source. Set those variables in the console instead.`
|
|
790
|
+
);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
Object.assign(environment, parseComposeEnvironment(name, service.environment, warnings));
|
|
794
|
+
if (Object.keys(environment).length > 0) container.env = environment;
|
|
795
|
+
if (typeof service.working_dir === "string") container.working_dir = service.working_dir;
|
|
796
|
+
if (typeof service.user === "string" || typeof service.user === "number") container.user = String(service.user);
|
|
797
|
+
const deploy = isRecord(service.deploy) ? service.deploy : {};
|
|
798
|
+
const resources = isRecord(deploy.resources) ? deploy.resources : {};
|
|
799
|
+
const limits = isRecord(resources.limits) ? resources.limits : {};
|
|
800
|
+
const memoryLimit = limits.memory ?? service.mem_limit;
|
|
801
|
+
if (memoryLimit !== void 0 && memoryLimit !== null) {
|
|
802
|
+
const memory = parseComposeMemory(memoryLimit);
|
|
803
|
+
if (memory === void 0) {
|
|
804
|
+
warnings.push(
|
|
805
|
+
`Compose service '${name}' sets the memory limit ${JSON.stringify(memoryLimit)}, which is not a size Docker accepts. The default is used instead.`
|
|
806
|
+
);
|
|
807
|
+
} else if (memory >= MIN_CONTAINER_MEMORY_MB && memory <= MAX_CONTAINER_MEMORY_MB) {
|
|
808
|
+
container.memory = memory;
|
|
809
|
+
} else if (memory > 0) {
|
|
810
|
+
warnings.push(
|
|
811
|
+
`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.`
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
if (service.volumes !== void 0) {
|
|
816
|
+
warnings.push(
|
|
817
|
+
`Compose service '${name}' declares volumes. Containers on Gigadrive Network have no persistent volumes, so anything written there is lost when the instance stops.`
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
containers[name] = container;
|
|
821
|
+
}
|
|
822
|
+
if (missing.size > 0) {
|
|
823
|
+
warnings.push(
|
|
824
|
+
`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.`
|
|
825
|
+
);
|
|
826
|
+
}
|
|
827
|
+
return { containers, publicService, warnings };
|
|
828
|
+
});
|
|
829
|
+
|
|
96
830
|
// src/define-config.ts
|
|
97
831
|
var defineConfig = (config) => config;
|
|
98
832
|
|
|
833
|
+
// src/detection/detect-container-project.ts
|
|
834
|
+
import { FileSystem as FileSystem3, Path as Path3 } from "@effect/platform";
|
|
835
|
+
import { Effect as Effect3 } from "effect";
|
|
836
|
+
|
|
837
|
+
// src/regions.ts
|
|
838
|
+
var REGION_DEFINITIONS = [
|
|
839
|
+
"us-east-1",
|
|
840
|
+
"us-east-2",
|
|
841
|
+
"us-west-1",
|
|
842
|
+
"us-west-2",
|
|
843
|
+
"ap-south-1",
|
|
844
|
+
"ap-northeast-3",
|
|
845
|
+
"ap-northeast-2",
|
|
846
|
+
"ap-southeast-1",
|
|
847
|
+
"ap-southeast-2",
|
|
848
|
+
"ap-northeast-1",
|
|
849
|
+
"ca-central-1",
|
|
850
|
+
"eu-central-1",
|
|
851
|
+
"eu-west-1",
|
|
852
|
+
"eu-west-2",
|
|
853
|
+
"eu-west-3",
|
|
854
|
+
"eu-north-1",
|
|
855
|
+
"sa-east-1"
|
|
856
|
+
];
|
|
857
|
+
var AVAILABLE_REGIONS = [...REGION_DEFINITIONS];
|
|
858
|
+
|
|
859
|
+
// src/detection/detect-container-project.ts
|
|
860
|
+
var detectContainerProject = Effect3.fn("detectContainerProject")(function* (projectFolder) {
|
|
861
|
+
const fs = yield* FileSystem3.FileSystem;
|
|
862
|
+
const pathSvc = yield* Path3.Path;
|
|
863
|
+
const exists = (file) => fs.exists(pathSvc.join(projectFolder, file)).pipe(Effect3.catchAll(() => Effect3.succeed(false)));
|
|
864
|
+
let detection;
|
|
865
|
+
const warnings = [];
|
|
866
|
+
const composeFile = yield* Effect3.findFirst(COMPOSE_FILE_NAMES, exists);
|
|
867
|
+
if (composeFile._tag === "Some" && (yield* composeDeclaresApp(composeFile.value, projectFolder))) {
|
|
868
|
+
const imported = yield* readComposeContainers(composeFile.value, projectFolder);
|
|
869
|
+
warnings.push(...imported.warnings);
|
|
870
|
+
detection = { kind: "compose", file: composeFile.value, containers: imported.containers };
|
|
871
|
+
} else if (yield* exists("Dockerfile")) {
|
|
872
|
+
detection = { kind: "dockerfile", file: "Dockerfile", containers: { app: { build: "." } } };
|
|
873
|
+
} else {
|
|
874
|
+
return void 0;
|
|
875
|
+
}
|
|
876
|
+
const {
|
|
877
|
+
entrypoints,
|
|
878
|
+
sidecars,
|
|
879
|
+
warnings: containerWarnings
|
|
880
|
+
} = yield* normalizeContainers(detection.containers, projectFolder);
|
|
881
|
+
const [publicContainer] = entrypoints;
|
|
882
|
+
const config = {
|
|
883
|
+
regions: [...AVAILABLE_REGIONS],
|
|
884
|
+
environmentVariables: {},
|
|
885
|
+
commands: [],
|
|
886
|
+
entrypoints,
|
|
887
|
+
...sidecars.length > 0 && { sidecars },
|
|
888
|
+
routes: publicContainer ? [
|
|
889
|
+
{
|
|
890
|
+
path: "/*",
|
|
891
|
+
destination: publicContainer.path,
|
|
892
|
+
handler: "SERVERLESS_FUNCTION_STREAMING",
|
|
893
|
+
methods: ["ANY"],
|
|
894
|
+
headers: {}
|
|
895
|
+
}
|
|
896
|
+
] : [],
|
|
897
|
+
warnings: [
|
|
898
|
+
`Auto-detected ${detection.kind === "compose" ? "Docker Compose" : "Dockerfile"} project (${detection.file}). Create a gigadrive.yaml to customize.`,
|
|
899
|
+
...warnings,
|
|
900
|
+
...containerWarnings
|
|
901
|
+
],
|
|
902
|
+
errors: []
|
|
903
|
+
};
|
|
904
|
+
return { kind: detection.kind, file: detection.file, config };
|
|
905
|
+
});
|
|
906
|
+
|
|
99
907
|
// src/detection/detect-framework.ts
|
|
100
|
-
import { FileSystem as
|
|
101
|
-
import { Effect as
|
|
908
|
+
import { FileSystem as FileSystem12, Path as Path10 } from "@effect/platform";
|
|
909
|
+
import { Effect as Effect14 } from "effect";
|
|
102
910
|
|
|
103
911
|
// src/detection/detect-package-manager.ts
|
|
104
|
-
import { FileSystem as
|
|
105
|
-
import { Effect as
|
|
912
|
+
import { FileSystem as FileSystem4, Path as Path4 } from "@effect/platform";
|
|
913
|
+
import { Effect as Effect4 } from "effect";
|
|
106
914
|
var LOCKFILE_MAP = [
|
|
107
915
|
{ files: ["bun.lockb", "bun.lock"], pm: "bun" },
|
|
108
916
|
{ files: ["pnpm-lock.yaml"], pm: "pnpm" },
|
|
@@ -110,19 +918,19 @@ var LOCKFILE_MAP = [
|
|
|
110
918
|
{ files: ["package-lock.json"], pm: "npm" },
|
|
111
919
|
{ files: ["composer.lock"], pm: "composer" }
|
|
112
920
|
];
|
|
113
|
-
var detectPackageManager =
|
|
114
|
-
const fs = yield*
|
|
115
|
-
const pathService = yield*
|
|
921
|
+
var detectPackageManager = Effect4.fn("detectPackageManager")(function* (projectFolder) {
|
|
922
|
+
const fs = yield* FileSystem4.FileSystem;
|
|
923
|
+
const pathService = yield* Path4.Path;
|
|
116
924
|
for (const { files, pm } of LOCKFILE_MAP) {
|
|
117
925
|
for (const file of files) {
|
|
118
|
-
const exists = yield* fs.exists(pathService.join(projectFolder, file)).pipe(
|
|
926
|
+
const exists = yield* fs.exists(pathService.join(projectFolder, file)).pipe(Effect4.catchAll(() => Effect4.succeed(false)));
|
|
119
927
|
if (exists) {
|
|
120
|
-
yield*
|
|
928
|
+
yield* Effect4.logDebug(`Detected package manager: ${pm} (via ${file})`);
|
|
121
929
|
return pm;
|
|
122
930
|
}
|
|
123
931
|
}
|
|
124
932
|
}
|
|
125
|
-
yield*
|
|
933
|
+
yield* Effect4.logDebug("No lockfile found, defaulting to npm");
|
|
126
934
|
return "npm";
|
|
127
935
|
});
|
|
128
936
|
|
|
@@ -147,9 +955,71 @@ var astro = {
|
|
|
147
955
|
})
|
|
148
956
|
};
|
|
149
957
|
|
|
958
|
+
// src/detection/frameworks/php-front-controller.ts
|
|
959
|
+
var phpFrontControllerDefaults = ({
|
|
960
|
+
documentRoot,
|
|
961
|
+
writablePaths = [],
|
|
962
|
+
excludeFiles = [],
|
|
963
|
+
memory = 256,
|
|
964
|
+
environmentVariables = {}
|
|
965
|
+
}) => {
|
|
966
|
+
const entrypoint = documentRoot === "." ? "index.php" : `${documentRoot}/index.php`;
|
|
967
|
+
return {
|
|
968
|
+
runtime: "php-84",
|
|
969
|
+
memory,
|
|
970
|
+
maxDuration: 30,
|
|
971
|
+
streaming: false,
|
|
972
|
+
commands: [],
|
|
973
|
+
entrypoint,
|
|
974
|
+
assetsDir: documentRoot,
|
|
975
|
+
excludeFiles: [".ddev", "node_modules/", ...excludeFiles],
|
|
976
|
+
routes: [{ source: "/*", destination: entrypoint }],
|
|
977
|
+
environmentVariables,
|
|
978
|
+
...writablePaths.length > 0 ? { package: { writablePaths } } : {}
|
|
979
|
+
};
|
|
980
|
+
};
|
|
981
|
+
|
|
982
|
+
// src/detection/frameworks/cakephp.ts
|
|
983
|
+
var cakephp = {
|
|
984
|
+
slug: "cakephp",
|
|
985
|
+
name: "CakePHP",
|
|
986
|
+
language: "php",
|
|
987
|
+
detectors: [{ matchPackage: "cakephp/cakephp" }, { path: "webroot/index.php" }],
|
|
988
|
+
priority: 80,
|
|
989
|
+
getDefaultConfig: () => phpFrontControllerDefaults({
|
|
990
|
+
documentRoot: "webroot",
|
|
991
|
+
// config/paths.php puts TMP and LOGS inside the project.
|
|
992
|
+
writablePaths: [
|
|
993
|
+
"tmp/cache/models",
|
|
994
|
+
"tmp/cache/persistent",
|
|
995
|
+
"tmp/cache/views",
|
|
996
|
+
"tmp/sessions",
|
|
997
|
+
"tmp/tests",
|
|
998
|
+
"logs"
|
|
999
|
+
],
|
|
1000
|
+
excludeFiles: ["tests/", "tmp/", "logs/"]
|
|
1001
|
+
})
|
|
1002
|
+
};
|
|
1003
|
+
|
|
1004
|
+
// src/detection/frameworks/codeigniter.ts
|
|
1005
|
+
var codeigniter = {
|
|
1006
|
+
slug: "codeigniter",
|
|
1007
|
+
name: "CodeIgniter",
|
|
1008
|
+
language: "php",
|
|
1009
|
+
detectors: [{ matchPackage: "codeigniter4/framework" }, { path: "spark" }],
|
|
1010
|
+
priority: 80,
|
|
1011
|
+
getDefaultConfig: () => phpFrontControllerDefaults({
|
|
1012
|
+
documentRoot: "public",
|
|
1013
|
+
// WRITEPATH: the cache, file session and log handlers write below it.
|
|
1014
|
+
writablePaths: ["writable/cache", "writable/debugbar", "writable/logs", "writable/session", "writable/uploads"],
|
|
1015
|
+
excludeFiles: ["tests/", "writable/"],
|
|
1016
|
+
environmentVariables: { CI_ENVIRONMENT: "production" }
|
|
1017
|
+
})
|
|
1018
|
+
};
|
|
1019
|
+
|
|
150
1020
|
// src/detection/frameworks/resolve-node-entrypoint.ts
|
|
151
|
-
import { FileSystem as
|
|
152
|
-
import { Effect as
|
|
1021
|
+
import { FileSystem as FileSystem5, Path as Path5 } from "@effect/platform";
|
|
1022
|
+
import { Effect as Effect5 } from "effect";
|
|
153
1023
|
var SCRIPT_RUNNERS = /* @__PURE__ */ new Set(["node", "bun", "tsx", "ts-node"]);
|
|
154
1024
|
var COMMON_ENTRYPOINT_CANDIDATES = [
|
|
155
1025
|
"index.js",
|
|
@@ -165,11 +1035,11 @@ var COMMON_ENTRYPOINT_CANDIDATES = [
|
|
|
165
1035
|
"server.ts",
|
|
166
1036
|
"src/server.ts"
|
|
167
1037
|
];
|
|
168
|
-
var
|
|
1038
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null;
|
|
169
1039
|
var parsePackageJson = (content) => {
|
|
170
1040
|
try {
|
|
171
1041
|
const parsed = JSON.parse(content);
|
|
172
|
-
if (!
|
|
1042
|
+
if (!isRecord2(parsed)) return void 0;
|
|
173
1043
|
return parsed;
|
|
174
1044
|
} catch {
|
|
175
1045
|
return void 0;
|
|
@@ -197,14 +1067,14 @@ var applyEntrypoint = (defaults, entrypoint) => ({
|
|
|
197
1067
|
(route) => route.destination === defaults.entrypoint ? { ...route, destination: entrypoint } : route
|
|
198
1068
|
)
|
|
199
1069
|
});
|
|
200
|
-
var resolveNodeServerEntrypoint = (defaults, projectFolder) =>
|
|
201
|
-
const fs = yield*
|
|
202
|
-
const pathService = yield*
|
|
1070
|
+
var resolveNodeServerEntrypoint = (defaults, projectFolder) => Effect5.gen(function* () {
|
|
1071
|
+
const fs = yield* FileSystem5.FileSystem;
|
|
1072
|
+
const pathService = yield* Path5.Path;
|
|
203
1073
|
const isFile = (relativePath) => fs.stat(pathService.join(projectFolder, relativePath)).pipe(
|
|
204
|
-
|
|
205
|
-
|
|
1074
|
+
Effect5.map((info) => info.type === "File"),
|
|
1075
|
+
Effect5.catchAll(() => Effect5.succeed(false))
|
|
206
1076
|
);
|
|
207
|
-
const content = yield* fs.readFileString(pathService.join(projectFolder, "package.json")).pipe(
|
|
1077
|
+
const content = yield* fs.readFileString(pathService.join(projectFolder, "package.json")).pipe(Effect5.catchAll(() => Effect5.succeed(void 0)));
|
|
208
1078
|
const manifest = content ? parsePackageJson(content) : void 0;
|
|
209
1079
|
const startScript = typeof manifest?.scripts?.start === "string" ? manifest.scripts.start : void 0;
|
|
210
1080
|
const candidates = [
|
|
@@ -304,6 +1174,21 @@ var hono = {
|
|
|
304
1174
|
refineDefaultConfig: resolveNodeServerEntrypoint
|
|
305
1175
|
};
|
|
306
1176
|
|
|
1177
|
+
// src/detection/frameworks/laminas.ts
|
|
1178
|
+
var laminas = {
|
|
1179
|
+
slug: "laminas",
|
|
1180
|
+
name: "Laminas MVC",
|
|
1181
|
+
language: "php",
|
|
1182
|
+
detectors: [{ matchPackage: "laminas/laminas-mvc" }, { path: "public/index.php" }],
|
|
1183
|
+
priority: 80,
|
|
1184
|
+
getDefaultConfig: () => phpFrontControllerDefaults({
|
|
1185
|
+
documentRoot: "public",
|
|
1186
|
+
// The merged-config and module-map caches of the skeleton.
|
|
1187
|
+
writablePaths: ["data/cache"],
|
|
1188
|
+
excludeFiles: ["test/", "data/cache/"]
|
|
1189
|
+
})
|
|
1190
|
+
};
|
|
1191
|
+
|
|
307
1192
|
// src/detection/frameworks/laravel.ts
|
|
308
1193
|
var laravel = {
|
|
309
1194
|
slug: "laravel",
|
|
@@ -322,6 +1207,18 @@ var laravel = {
|
|
|
322
1207
|
populateAssetCache: true,
|
|
323
1208
|
excludeFiles: ["tests/", "storage/", ".ddev", "node_modules/"],
|
|
324
1209
|
routes: [{ source: "/*", destination: "public/index.php" }],
|
|
1210
|
+
package: {
|
|
1211
|
+
// storage/ is excluded, so the directories Laravel writes compiled
|
|
1212
|
+
// views, file caches, sessions and logs to are created empty.
|
|
1213
|
+
writablePaths: [
|
|
1214
|
+
"bootstrap/cache",
|
|
1215
|
+
"storage/app/public",
|
|
1216
|
+
"storage/framework/cache/data",
|
|
1217
|
+
"storage/framework/sessions",
|
|
1218
|
+
"storage/framework/views",
|
|
1219
|
+
"storage/logs"
|
|
1220
|
+
]
|
|
1221
|
+
},
|
|
325
1222
|
environmentVariables: {
|
|
326
1223
|
APP_NAME: "Laravel",
|
|
327
1224
|
APP_ENV: "production",
|
|
@@ -335,14 +1232,29 @@ var laravel = {
|
|
|
335
1232
|
})
|
|
336
1233
|
};
|
|
337
1234
|
|
|
1235
|
+
// src/detection/frameworks/mezzio.ts
|
|
1236
|
+
var mezzio = {
|
|
1237
|
+
slug: "mezzio",
|
|
1238
|
+
name: "Mezzio",
|
|
1239
|
+
language: "php",
|
|
1240
|
+
detectors: [{ matchPackage: "mezzio/mezzio" }, { path: "public/index.php" }],
|
|
1241
|
+
priority: 80,
|
|
1242
|
+
getDefaultConfig: () => phpFrontControllerDefaults({
|
|
1243
|
+
documentRoot: "public",
|
|
1244
|
+
// config/config.php writes the merged config cache here.
|
|
1245
|
+
writablePaths: ["data/cache"],
|
|
1246
|
+
excludeFiles: ["test/", "data/cache/"]
|
|
1247
|
+
})
|
|
1248
|
+
};
|
|
1249
|
+
|
|
338
1250
|
// src/detection/frameworks/nestjs.ts
|
|
339
|
-
import { FileSystem as
|
|
340
|
-
import { Effect as
|
|
341
|
-
var
|
|
1251
|
+
import { FileSystem as FileSystem6 } from "@effect/platform";
|
|
1252
|
+
import { Effect as Effect6 } from "effect";
|
|
1253
|
+
var isRecord3 = (value) => typeof value === "object" && value !== null;
|
|
342
1254
|
var parseNestCliJson = (content) => {
|
|
343
1255
|
try {
|
|
344
1256
|
const parsed = JSON.parse(content);
|
|
345
|
-
if (!
|
|
1257
|
+
if (!isRecord3(parsed)) return void 0;
|
|
346
1258
|
return parsed;
|
|
347
1259
|
} catch {
|
|
348
1260
|
return void 0;
|
|
@@ -388,9 +1300,9 @@ var nestjs = {
|
|
|
388
1300
|
detectors: [{ matchPackage: "@nestjs/core" }],
|
|
389
1301
|
priority: 90,
|
|
390
1302
|
getDefaultConfig: () => createNestConfig("dist"),
|
|
391
|
-
refineDefaultConfig: (defaults, projectFolder) =>
|
|
392
|
-
const fs = yield*
|
|
393
|
-
const content = yield* fs.readFileString(`${projectFolder}/nest-cli.json`).pipe(
|
|
1303
|
+
refineDefaultConfig: (defaults, projectFolder) => Effect6.gen(function* () {
|
|
1304
|
+
const fs = yield* FileSystem6.FileSystem;
|
|
1305
|
+
const content = yield* fs.readFileString(`${projectFolder}/nest-cli.json`).pipe(Effect6.catchAll(() => Effect6.succeed(void 0)));
|
|
394
1306
|
if (!content) return defaults;
|
|
395
1307
|
const nestConfig = parseNestCliJson(content);
|
|
396
1308
|
const outputPath = nestConfig ? getProjectOutputPath(nestConfig) : void 0;
|
|
@@ -399,28 +1311,28 @@ var nestjs = {
|
|
|
399
1311
|
};
|
|
400
1312
|
|
|
401
1313
|
// src/detection/frameworks/nextjs.ts
|
|
402
|
-
import { FileSystem as
|
|
403
|
-
import { Effect as
|
|
1314
|
+
import { FileSystem as FileSystem8, Path as Path7 } from "@effect/platform";
|
|
1315
|
+
import { Effect as Effect8 } from "effect";
|
|
404
1316
|
|
|
405
1317
|
// src/build-output-v3/get-default-path-map.ts
|
|
406
|
-
import { FileSystem as
|
|
407
|
-
import { Effect as
|
|
408
|
-
var getDefaultPathMap =
|
|
409
|
-
const fs = yield*
|
|
410
|
-
const pathService = yield*
|
|
1318
|
+
import { FileSystem as FileSystem7, Path as Path6 } from "@effect/platform";
|
|
1319
|
+
import { Effect as Effect7 } from "effect";
|
|
1320
|
+
var getDefaultPathMap = Effect7.fn("getDefaultPathMap")(function* (directory) {
|
|
1321
|
+
const fs = yield* FileSystem7.FileSystem;
|
|
1322
|
+
const pathService = yield* Path6.Path;
|
|
411
1323
|
const result = {};
|
|
412
|
-
const exists = yield* fs.exists(directory).pipe(
|
|
1324
|
+
const exists = yield* fs.exists(directory).pipe(Effect7.catchAll(() => Effect7.succeed(false)));
|
|
413
1325
|
if (!exists) {
|
|
414
1326
|
return result;
|
|
415
1327
|
}
|
|
416
1328
|
const MAX_DEPTH = 100;
|
|
417
|
-
const processDirectory = (currentPath, basePath = "", depth = 0) =>
|
|
1329
|
+
const processDirectory = (currentPath, basePath = "", depth = 0) => Effect7.gen(function* () {
|
|
418
1330
|
if (depth > MAX_DEPTH) return;
|
|
419
|
-
const entries = yield* fs.readDirectory(currentPath).pipe(
|
|
1331
|
+
const entries = yield* fs.readDirectory(currentPath).pipe(Effect7.catchAll(() => Effect7.succeed([])));
|
|
420
1332
|
for (const name of entries) {
|
|
421
1333
|
const fullPath = pathService.join(currentPath, name);
|
|
422
1334
|
const relativePath = basePath ? pathService.join(basePath, name) : name;
|
|
423
|
-
const stat = yield* fs.stat(fullPath).pipe(
|
|
1335
|
+
const stat = yield* fs.stat(fullPath).pipe(Effect7.catchAll(() => Effect7.succeed(null)));
|
|
424
1336
|
if (!stat) continue;
|
|
425
1337
|
if (stat.type === "Directory") {
|
|
426
1338
|
yield* processDirectory(fullPath, relativePath, depth + 1);
|
|
@@ -437,291 +1349,269 @@ var getDefaultPathMap = Effect5.fn("getDefaultPathMap")(function* (directory) {
|
|
|
437
1349
|
var MAXIMUM_ENTRY_PAGE_PATHS = 50;
|
|
438
1350
|
|
|
439
1351
|
// src/nextjs-manifest.ts
|
|
440
|
-
import { Schema as
|
|
441
|
-
var StringArraySchema =
|
|
442
|
-
var StringRecordSchema =
|
|
443
|
-
var JsonValueSchema =
|
|
444
|
-
() =>
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
1352
|
+
import { Schema as Schema4 } from "effect";
|
|
1353
|
+
var StringArraySchema = Schema4.mutable(Schema4.Array(Schema4.String));
|
|
1354
|
+
var StringRecordSchema = Schema4.mutable(Schema4.Record({ key: Schema4.String, value: Schema4.String }));
|
|
1355
|
+
var JsonValueSchema = Schema4.suspend(
|
|
1356
|
+
() => Schema4.Union(
|
|
1357
|
+
Schema4.Null,
|
|
1358
|
+
Schema4.Boolean,
|
|
1359
|
+
Schema4.Number,
|
|
1360
|
+
Schema4.String,
|
|
1361
|
+
Schema4.mutable(Schema4.Array(JsonValueSchema)),
|
|
1362
|
+
Schema4.mutable(Schema4.Record({ key: Schema4.String, value: JsonValueSchema }))
|
|
451
1363
|
)
|
|
452
1364
|
);
|
|
453
|
-
var ImageLocalPatternSchema =
|
|
454
|
-
|
|
455
|
-
pathname:
|
|
456
|
-
search:
|
|
1365
|
+
var ImageLocalPatternSchema = Schema4.mutable(
|
|
1366
|
+
Schema4.Struct({
|
|
1367
|
+
pathname: Schema4.optional(Schema4.String),
|
|
1368
|
+
search: Schema4.optional(Schema4.String)
|
|
457
1369
|
})
|
|
458
1370
|
);
|
|
459
|
-
var ImageRemotePatternSchema =
|
|
460
|
-
|
|
461
|
-
protocol:
|
|
462
|
-
hostname:
|
|
463
|
-
port:
|
|
464
|
-
pathname:
|
|
465
|
-
search:
|
|
1371
|
+
var ImageRemotePatternSchema = Schema4.mutable(
|
|
1372
|
+
Schema4.Struct({
|
|
1373
|
+
protocol: Schema4.optional(Schema4.Literal("http", "https")),
|
|
1374
|
+
hostname: Schema4.String,
|
|
1375
|
+
port: Schema4.optional(Schema4.String),
|
|
1376
|
+
pathname: Schema4.optional(Schema4.String),
|
|
1377
|
+
search: Schema4.optional(Schema4.String)
|
|
466
1378
|
})
|
|
467
1379
|
);
|
|
468
|
-
var ImageVariantSchema =
|
|
469
|
-
|
|
470
|
-
width:
|
|
471
|
-
height:
|
|
472
|
-
quality:
|
|
473
|
-
format:
|
|
474
|
-
fit:
|
|
1380
|
+
var ImageVariantSchema = Schema4.mutable(
|
|
1381
|
+
Schema4.Struct({
|
|
1382
|
+
width: Schema4.optional(Schema4.Number),
|
|
1383
|
+
height: Schema4.optional(Schema4.Number),
|
|
1384
|
+
quality: Schema4.optional(Schema4.Number),
|
|
1385
|
+
format: Schema4.optional(Schema4.Literal("image/avif", "image/webp", "image/jpeg", "image/png")),
|
|
1386
|
+
fit: Schema4.optional(Schema4.Literal("contain", "cover", "fill", "inside", "outside"))
|
|
475
1387
|
})
|
|
476
1388
|
);
|
|
477
|
-
var PositiveIntSchema =
|
|
478
|
-
var ImagePolicySchema =
|
|
479
|
-
|
|
480
|
-
localPatterns:
|
|
481
|
-
remotePatterns:
|
|
482
|
-
widths:
|
|
483
|
-
heights:
|
|
484
|
-
qualities:
|
|
485
|
-
formats:
|
|
486
|
-
minimumCacheTTL:
|
|
487
|
-
dangerouslyAllowSVG:
|
|
488
|
-
contentSecurityPolicy:
|
|
489
|
-
contentDispositionType:
|
|
490
|
-
maximumRedirects:
|
|
491
|
-
maximumResponseBody:
|
|
492
|
-
variants:
|
|
1389
|
+
var PositiveIntSchema = Schema4.Int.pipe(Schema4.greaterThan(0));
|
|
1390
|
+
var ImagePolicySchema = Schema4.mutable(
|
|
1391
|
+
Schema4.Struct({
|
|
1392
|
+
localPatterns: Schema4.mutable(Schema4.Array(ImageLocalPatternSchema)),
|
|
1393
|
+
remotePatterns: Schema4.mutable(Schema4.Array(ImageRemotePatternSchema)),
|
|
1394
|
+
widths: Schema4.mutable(Schema4.Array(PositiveIntSchema)),
|
|
1395
|
+
heights: Schema4.mutable(Schema4.Array(PositiveIntSchema)),
|
|
1396
|
+
qualities: Schema4.mutable(Schema4.Array(Schema4.Number.pipe(Schema4.between(1, 100)))),
|
|
1397
|
+
formats: Schema4.mutable(Schema4.Array(Schema4.Literal("image/avif", "image/webp", "image/jpeg", "image/png"))),
|
|
1398
|
+
minimumCacheTTL: Schema4.Number,
|
|
1399
|
+
dangerouslyAllowSVG: Schema4.Boolean,
|
|
1400
|
+
contentSecurityPolicy: Schema4.String,
|
|
1401
|
+
contentDispositionType: Schema4.Literal("inline", "attachment"),
|
|
1402
|
+
maximumRedirects: Schema4.Number,
|
|
1403
|
+
maximumResponseBody: Schema4.Number,
|
|
1404
|
+
variants: Schema4.mutable(Schema4.Record({ key: Schema4.String, value: ImageVariantSchema }))
|
|
493
1405
|
})
|
|
494
1406
|
);
|
|
495
1407
|
var GigadriveNextPrerenderOutputFields = {
|
|
496
|
-
id:
|
|
497
|
-
type:
|
|
1408
|
+
id: Schema4.String,
|
|
1409
|
+
type: Schema4.Literal("PRERENDER"),
|
|
498
1410
|
pathname: UrlPathnameSchema,
|
|
499
|
-
route:
|
|
500
|
-
parentOutputId:
|
|
501
|
-
groupId:
|
|
502
|
-
pprChain:
|
|
503
|
-
parentFallbackMode:
|
|
504
|
-
fallback:
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
filePath:
|
|
508
|
-
initialStatus:
|
|
509
|
-
initialHeaders:
|
|
510
|
-
initialExpiration:
|
|
511
|
-
initialRevalidate:
|
|
512
|
-
postponedState:
|
|
1411
|
+
route: Schema4.optional(UrlPathnameSchema),
|
|
1412
|
+
parentOutputId: Schema4.String,
|
|
1413
|
+
groupId: Schema4.Number,
|
|
1414
|
+
pprChain: Schema4.optional(Schema4.mutable(Schema4.Struct({ headers: HttpSingleValueHeadersSchema }))),
|
|
1415
|
+
parentFallbackMode: Schema4.optional(JsonValueSchema),
|
|
1416
|
+
fallback: Schema4.optional(
|
|
1417
|
+
Schema4.mutable(
|
|
1418
|
+
Schema4.Struct({
|
|
1419
|
+
filePath: Schema4.optional(PortableRelativePathSchema),
|
|
1420
|
+
initialStatus: Schema4.optional(Schema4.Int.pipe(Schema4.between(100, 599))),
|
|
1421
|
+
initialHeaders: Schema4.optional(HttpHeadersSchema),
|
|
1422
|
+
initialExpiration: Schema4.optional(Schema4.Number),
|
|
1423
|
+
initialRevalidate: Schema4.optional(Schema4.Union(Schema4.Number, Schema4.Literal(false))),
|
|
1424
|
+
postponedState: Schema4.optional(Schema4.String)
|
|
513
1425
|
})
|
|
514
1426
|
)
|
|
515
1427
|
),
|
|
516
|
-
config:
|
|
517
|
-
|
|
518
|
-
allowQuery:
|
|
519
|
-
allowHeader:
|
|
520
|
-
bypassFor:
|
|
521
|
-
renderingMode:
|
|
522
|
-
partialFallback:
|
|
523
|
-
bypassToken:
|
|
1428
|
+
config: Schema4.mutable(
|
|
1429
|
+
Schema4.Struct({
|
|
1430
|
+
allowQuery: Schema4.optional(StringArraySchema),
|
|
1431
|
+
allowHeader: Schema4.optional(StringArraySchema),
|
|
1432
|
+
bypassFor: Schema4.optional(Schema4.mutable(Schema4.Array(JsonValueSchema))),
|
|
1433
|
+
renderingMode: Schema4.optional(Schema4.String),
|
|
1434
|
+
partialFallback: Schema4.optional(Schema4.Boolean),
|
|
1435
|
+
bypassToken: Schema4.optional(Schema4.String)
|
|
524
1436
|
})
|
|
525
1437
|
)
|
|
526
1438
|
};
|
|
527
|
-
var GigadriveNextPrerenderClassificationSchema =
|
|
528
|
-
routeType:
|
|
529
|
-
response:
|
|
530
|
-
compute:
|
|
531
|
-
htmlSize:
|
|
1439
|
+
var GigadriveNextPrerenderClassificationSchema = Schema4.Struct({
|
|
1440
|
+
routeType: Schema4.Literal("route", "fallback", "shell", "page"),
|
|
1441
|
+
response: Schema4.Literal("empty", "initial", "complete"),
|
|
1442
|
+
compute: Schema4.Literal("blocking", "resuming", "static"),
|
|
1443
|
+
htmlSize: Schema4.optional(Schema4.Number)
|
|
532
1444
|
});
|
|
533
|
-
var GigadriveNextPrerenderWithoutClassificationSchema =
|
|
534
|
-
routeType:
|
|
535
|
-
response:
|
|
536
|
-
compute:
|
|
537
|
-
htmlSize:
|
|
1445
|
+
var GigadriveNextPrerenderWithoutClassificationSchema = Schema4.Struct({
|
|
1446
|
+
routeType: Schema4.optional(Schema4.Never),
|
|
1447
|
+
response: Schema4.optional(Schema4.Never),
|
|
1448
|
+
compute: Schema4.optional(Schema4.Never),
|
|
1449
|
+
htmlSize: Schema4.optional(Schema4.Never)
|
|
538
1450
|
});
|
|
539
|
-
var GigadriveNextPrerenderOutputSchema =
|
|
540
|
-
|
|
541
|
-
|
|
1451
|
+
var GigadriveNextPrerenderOutputSchema = Schema4.Union(
|
|
1452
|
+
Schema4.mutable(
|
|
1453
|
+
Schema4.Struct({ ...GigadriveNextPrerenderOutputFields, ...GigadriveNextPrerenderClassificationSchema.fields })
|
|
542
1454
|
),
|
|
543
|
-
|
|
544
|
-
|
|
1455
|
+
Schema4.mutable(
|
|
1456
|
+
Schema4.Struct({
|
|
545
1457
|
...GigadriveNextPrerenderOutputFields,
|
|
546
1458
|
...GigadriveNextPrerenderWithoutClassificationSchema.fields
|
|
547
1459
|
})
|
|
548
1460
|
)
|
|
549
1461
|
);
|
|
550
|
-
var GigadriveNextStaticAssetPrefixSchema =
|
|
551
|
-
|
|
1462
|
+
var GigadriveNextStaticAssetPrefixSchema = Schema4.mutable(
|
|
1463
|
+
Schema4.Struct({
|
|
552
1464
|
sourceDir: PortableRelativePathSchema,
|
|
553
1465
|
urlPrefix: PortableRelativePathSchema,
|
|
554
|
-
immutable:
|
|
1466
|
+
immutable: Schema4.Boolean
|
|
555
1467
|
})
|
|
556
1468
|
);
|
|
557
|
-
var GigadriveNextRouteConditionSchema =
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
type:
|
|
561
|
-
key:
|
|
562
|
-
value:
|
|
1469
|
+
var GigadriveNextRouteConditionSchema = Schema4.Union(
|
|
1470
|
+
Schema4.mutable(
|
|
1471
|
+
Schema4.Struct({
|
|
1472
|
+
type: Schema4.Literal("header", "cookie", "query"),
|
|
1473
|
+
key: Schema4.String,
|
|
1474
|
+
value: Schema4.optional(Schema4.String)
|
|
563
1475
|
})
|
|
564
1476
|
),
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
type:
|
|
568
|
-
value:
|
|
1477
|
+
Schema4.mutable(
|
|
1478
|
+
Schema4.Struct({
|
|
1479
|
+
type: Schema4.Literal("host"),
|
|
1480
|
+
value: Schema4.String
|
|
569
1481
|
})
|
|
570
1482
|
)
|
|
571
1483
|
);
|
|
572
|
-
var GigadriveNextMiddlewareMatcherSchema =
|
|
573
|
-
|
|
574
|
-
source:
|
|
575
|
-
sourceRegex:
|
|
576
|
-
has:
|
|
577
|
-
missing:
|
|
1484
|
+
var GigadriveNextMiddlewareMatcherSchema = Schema4.mutable(
|
|
1485
|
+
Schema4.Struct({
|
|
1486
|
+
source: Schema4.String,
|
|
1487
|
+
sourceRegex: Schema4.String,
|
|
1488
|
+
has: Schema4.optional(Schema4.mutable(Schema4.Array(GigadriveNextRouteConditionSchema))),
|
|
1489
|
+
missing: Schema4.optional(Schema4.mutable(Schema4.Array(GigadriveNextRouteConditionSchema)))
|
|
578
1490
|
})
|
|
579
1491
|
);
|
|
580
|
-
var GigadriveNextMiddlewareDescriptorSchema =
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
present:
|
|
584
|
-
matchers:
|
|
1492
|
+
var GigadriveNextMiddlewareDescriptorSchema = Schema4.Union(
|
|
1493
|
+
Schema4.mutable(
|
|
1494
|
+
Schema4.Struct({
|
|
1495
|
+
present: Schema4.Literal(true),
|
|
1496
|
+
matchers: Schema4.mutable(Schema4.Array(GigadriveNextMiddlewareMatcherSchema))
|
|
585
1497
|
})
|
|
586
1498
|
),
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
present:
|
|
590
|
-
matchers:
|
|
1499
|
+
Schema4.mutable(
|
|
1500
|
+
Schema4.Struct({
|
|
1501
|
+
present: Schema4.Literal(false),
|
|
1502
|
+
matchers: Schema4.mutable(Schema4.Tuple())
|
|
591
1503
|
})
|
|
592
1504
|
)
|
|
593
1505
|
);
|
|
594
|
-
var GigadriveNextServerDescriptorSchema =
|
|
595
|
-
|
|
596
|
-
maxDuration:
|
|
597
|
-
preferredRegion:
|
|
598
|
-
env:
|
|
1506
|
+
var GigadriveNextServerDescriptorSchema = Schema4.mutable(
|
|
1507
|
+
Schema4.Struct({
|
|
1508
|
+
maxDuration: Schema4.optional(Schema4.Number),
|
|
1509
|
+
preferredRegion: Schema4.optional(Schema4.Union(Schema4.String, StringArraySchema)),
|
|
1510
|
+
env: Schema4.optional(StringRecordSchema)
|
|
599
1511
|
})
|
|
600
1512
|
);
|
|
601
|
-
var PrerenderArraySchema =
|
|
602
|
-
var StaticAssetArraySchema =
|
|
603
|
-
var JsonValueArraySchema =
|
|
604
|
-
var GigadriveNextPrerenderSeedMethodsSchema =
|
|
605
|
-
|
|
1513
|
+
var PrerenderArraySchema = Schema4.mutable(Schema4.Array(GigadriveNextPrerenderOutputSchema));
|
|
1514
|
+
var StaticAssetArraySchema = Schema4.mutable(Schema4.Array(GigadriveNextStaticAssetPrefixSchema));
|
|
1515
|
+
var JsonValueArraySchema = Schema4.mutable(Schema4.Array(JsonValueSchema));
|
|
1516
|
+
var GigadriveNextPrerenderSeedMethodsSchema = Schema4.mutable(
|
|
1517
|
+
Schema4.Tuple(Schema4.Literal("GET"), Schema4.Literal("HEAD"))
|
|
606
1518
|
);
|
|
607
|
-
var GigadriveNextBuildManifestV1Schema =
|
|
608
|
-
|
|
609
|
-
version:
|
|
610
|
-
output:
|
|
1519
|
+
var GigadriveNextBuildManifestV1Schema = Schema4.mutable(
|
|
1520
|
+
Schema4.Struct({
|
|
1521
|
+
version: Schema4.Literal(1),
|
|
1522
|
+
output: Schema4.Literal("standalone", "export"),
|
|
611
1523
|
distDir: PortableRelativePathSchema,
|
|
612
1524
|
repoRootToProject: RepositoryRelativePathSchema,
|
|
613
|
-
nextVersion:
|
|
614
|
-
buildId:
|
|
1525
|
+
nextVersion: Schema4.String,
|
|
1526
|
+
buildId: Schema4.String
|
|
615
1527
|
})
|
|
616
1528
|
);
|
|
617
|
-
var GigadriveNextBuildManifestV2ExportSchema =
|
|
618
|
-
|
|
619
|
-
version:
|
|
620
|
-
mode:
|
|
1529
|
+
var GigadriveNextBuildManifestV2ExportSchema = Schema4.mutable(
|
|
1530
|
+
Schema4.Struct({
|
|
1531
|
+
version: Schema4.Literal(2),
|
|
1532
|
+
mode: Schema4.Literal("export"),
|
|
621
1533
|
distDir: PortableRelativePathSchema,
|
|
622
1534
|
repoRootToProject: RepositoryRelativePathSchema,
|
|
623
|
-
nextVersion:
|
|
624
|
-
buildId:
|
|
1535
|
+
nextVersion: Schema4.String,
|
|
1536
|
+
buildId: Schema4.String
|
|
625
1537
|
})
|
|
626
1538
|
);
|
|
627
|
-
var GigadriveNextBuildManifestV2StandaloneSchema =
|
|
628
|
-
|
|
629
|
-
version:
|
|
630
|
-
mode:
|
|
1539
|
+
var GigadriveNextBuildManifestV2StandaloneSchema = Schema4.mutable(
|
|
1540
|
+
Schema4.Struct({
|
|
1541
|
+
version: Schema4.Literal(2),
|
|
1542
|
+
mode: Schema4.Literal("standalone-v2"),
|
|
631
1543
|
distDir: PortableRelativePathSchema,
|
|
632
1544
|
repoRootToProject: RepositoryRelativePathSchema,
|
|
633
|
-
nextVersion:
|
|
634
|
-
buildId:
|
|
1545
|
+
nextVersion: Schema4.String,
|
|
1546
|
+
buildId: Schema4.String,
|
|
635
1547
|
server: GigadriveNextServerDescriptorSchema,
|
|
636
|
-
config:
|
|
637
|
-
|
|
638
|
-
basePath:
|
|
639
|
-
trailingSlash:
|
|
640
|
-
cacheComponents:
|
|
641
|
-
i18n:
|
|
642
|
-
images:
|
|
1548
|
+
config: Schema4.mutable(
|
|
1549
|
+
Schema4.Struct({
|
|
1550
|
+
basePath: Schema4.String,
|
|
1551
|
+
trailingSlash: Schema4.Boolean,
|
|
1552
|
+
cacheComponents: Schema4.Boolean,
|
|
1553
|
+
i18n: Schema4.optional(JsonValueSchema),
|
|
1554
|
+
images: Schema4.optional(ImagePolicySchema)
|
|
643
1555
|
})
|
|
644
1556
|
),
|
|
645
|
-
routing:
|
|
646
|
-
|
|
1557
|
+
routing: Schema4.mutable(
|
|
1558
|
+
Schema4.Struct({
|
|
647
1559
|
beforeMiddleware: JsonValueArraySchema,
|
|
648
1560
|
beforeFiles: JsonValueArraySchema,
|
|
649
1561
|
afterFiles: JsonValueArraySchema,
|
|
650
1562
|
dynamicRoutes: JsonValueArraySchema,
|
|
651
1563
|
onMatch: JsonValueArraySchema,
|
|
652
|
-
fallback: JsonValueArraySchema,
|
|
653
|
-
shouldNormalizeNextData:
|
|
654
|
-
rsc: JsonValueSchema
|
|
655
|
-
})
|
|
656
|
-
),
|
|
657
|
-
outputs:
|
|
658
|
-
|
|
659
|
-
prerenders: PrerenderArraySchema,
|
|
660
|
-
prerenderManifest:
|
|
661
|
-
assetManifest:
|
|
662
|
-
entryPagePaths:
|
|
663
|
-
staticAssets: StaticAssetArraySchema,
|
|
664
|
-
middleware:
|
|
665
|
-
})
|
|
666
|
-
)
|
|
667
|
-
})
|
|
668
|
-
);
|
|
669
|
-
var GigadriveNextBuildManifestSchema =
|
|
670
|
-
GigadriveNextBuildManifestV1Schema,
|
|
671
|
-
GigadriveNextBuildManifestV2ExportSchema,
|
|
672
|
-
GigadriveNextBuildManifestV2StandaloneSchema
|
|
673
|
-
);
|
|
674
|
-
var GigadriveNextPrerenderManifestV1Schema =
|
|
675
|
-
|
|
676
|
-
version:
|
|
677
|
-
seedMethods:
|
|
678
|
-
prerenders: PrerenderArraySchema
|
|
679
|
-
})
|
|
680
|
-
);
|
|
681
|
-
var parseGigadriveNextBuildManifest = (content) => decodeJson(GigadriveNextBuildManifestSchema, content);
|
|
682
|
-
var parseGigadriveNextPrerenderManifest = (content) => decodeJson(GigadriveNextPrerenderManifestV1Schema, content);
|
|
683
|
-
|
|
684
|
-
// src/regions.ts
|
|
685
|
-
var REGION_DEFINITIONS = [
|
|
686
|
-
"us-east-1",
|
|
687
|
-
"us-east-2",
|
|
688
|
-
"us-west-1",
|
|
689
|
-
"us-west-2",
|
|
690
|
-
"ap-south-1",
|
|
691
|
-
"ap-northeast-3",
|
|
692
|
-
"ap-northeast-2",
|
|
693
|
-
"ap-southeast-1",
|
|
694
|
-
"ap-southeast-2",
|
|
695
|
-
"ap-northeast-1",
|
|
696
|
-
"ca-central-1",
|
|
697
|
-
"eu-central-1",
|
|
698
|
-
"eu-west-1",
|
|
699
|
-
"eu-west-2",
|
|
700
|
-
"eu-west-3",
|
|
701
|
-
"eu-north-1",
|
|
702
|
-
"sa-east-1"
|
|
703
|
-
];
|
|
704
|
-
var AVAILABLE_REGIONS = [...REGION_DEFINITIONS];
|
|
1564
|
+
fallback: JsonValueArraySchema,
|
|
1565
|
+
shouldNormalizeNextData: Schema4.Boolean,
|
|
1566
|
+
rsc: JsonValueSchema
|
|
1567
|
+
})
|
|
1568
|
+
),
|
|
1569
|
+
outputs: Schema4.mutable(
|
|
1570
|
+
Schema4.Struct({
|
|
1571
|
+
prerenders: PrerenderArraySchema,
|
|
1572
|
+
prerenderManifest: Schema4.optional(PortableRelativePathSchema),
|
|
1573
|
+
assetManifest: Schema4.optional(PortableRelativePathSchema),
|
|
1574
|
+
entryPagePaths: Schema4.optional(Schema4.mutable(Schema4.Array(UrlPathnameSchema))),
|
|
1575
|
+
staticAssets: StaticAssetArraySchema,
|
|
1576
|
+
middleware: Schema4.optional(GigadriveNextMiddlewareDescriptorSchema)
|
|
1577
|
+
})
|
|
1578
|
+
)
|
|
1579
|
+
})
|
|
1580
|
+
);
|
|
1581
|
+
var GigadriveNextBuildManifestSchema = Schema4.Union(
|
|
1582
|
+
GigadriveNextBuildManifestV1Schema,
|
|
1583
|
+
GigadriveNextBuildManifestV2ExportSchema,
|
|
1584
|
+
GigadriveNextBuildManifestV2StandaloneSchema
|
|
1585
|
+
);
|
|
1586
|
+
var GigadriveNextPrerenderManifestV1Schema = Schema4.mutable(
|
|
1587
|
+
Schema4.Struct({
|
|
1588
|
+
version: Schema4.Literal(1),
|
|
1589
|
+
seedMethods: Schema4.optional(GigadriveNextPrerenderSeedMethodsSchema),
|
|
1590
|
+
prerenders: PrerenderArraySchema
|
|
1591
|
+
})
|
|
1592
|
+
);
|
|
1593
|
+
var parseGigadriveNextBuildManifest = (content) => decodeJson(GigadriveNextBuildManifestSchema, content);
|
|
1594
|
+
var parseGigadriveNextPrerenderManifest = (content) => decodeJson(GigadriveNextPrerenderManifestV1Schema, content);
|
|
705
1595
|
|
|
706
1596
|
// src/detection/frameworks/nextjs.ts
|
|
707
1597
|
var toPortablePath = (value) => value.replaceAll("\\", "/");
|
|
708
1598
|
var STANDALONE_SERVER_MEMORY_MB = 1024;
|
|
709
|
-
var resolveStandaloneServer =
|
|
710
|
-
const fs = yield*
|
|
711
|
-
const pathService = yield*
|
|
1599
|
+
var resolveStandaloneServer = Effect8.fn("nextjs.resolveStandaloneServer")(function* (projectFolder, distDir, repoRootToProject) {
|
|
1600
|
+
const fs = yield* FileSystem8.FileSystem;
|
|
1601
|
+
const pathService = yield* Path7.Path;
|
|
712
1602
|
const standaloneRoot = pathService.join(projectFolder, distDir, "standalone");
|
|
713
1603
|
const monorepoServer = pathService.join(standaloneRoot, repoRootToProject, "server.js");
|
|
714
1604
|
const rootServer = pathService.join(standaloneRoot, "server.js");
|
|
715
|
-
const monorepoServerExists = yield* fs.exists(monorepoServer).pipe(
|
|
1605
|
+
const monorepoServerExists = yield* fs.exists(monorepoServer).pipe(Effect8.catchAll(() => Effect8.succeed(false)));
|
|
716
1606
|
const serverPath = monorepoServerExists ? monorepoServer : rootServer;
|
|
717
|
-
const serverExists = yield* fs.exists(serverPath).pipe(
|
|
1607
|
+
const serverExists = yield* fs.exists(serverPath).pipe(Effect8.catchAll(() => Effect8.succeed(false)));
|
|
718
1608
|
if (!serverExists) return void 0;
|
|
719
1609
|
const serverDirectory = pathService.dirname(serverPath);
|
|
720
1610
|
const entrypoint = toPortablePath(pathService.relative(standaloneRoot, serverPath));
|
|
721
1611
|
return { standaloneRoot, serverDirectory, entrypoint };
|
|
722
1612
|
});
|
|
723
|
-
var buildStandalonePublicAssets =
|
|
724
|
-
const pathService = yield*
|
|
1613
|
+
var buildStandalonePublicAssets = Effect8.fn("nextjs.buildStandalonePublicAssets")(function* (projectFolder, standaloneRoot, serverDirectory) {
|
|
1614
|
+
const pathService = yield* Path7.Path;
|
|
725
1615
|
const publicFiles = yield* getDefaultPathMap(pathService.join(projectFolder, "public"));
|
|
726
1616
|
const assetPaths = [];
|
|
727
1617
|
const assetOverrides = {};
|
|
@@ -737,8 +1627,8 @@ var buildStandalonePublicAssets = Effect6.fn("nextjs.buildStandalonePublicAssets
|
|
|
737
1627
|
}
|
|
738
1628
|
return { assetPaths, assetOverrides, filePathMap };
|
|
739
1629
|
});
|
|
740
|
-
var createStaticExportConfig =
|
|
741
|
-
const pathService = yield*
|
|
1630
|
+
var createStaticExportConfig = Effect8.fn("nextjs.createStaticExportConfig")(function* (defaults, projectFolder) {
|
|
1631
|
+
const pathService = yield* Path7.Path;
|
|
742
1632
|
const outputDirectory = pathService.join(projectFolder, "out");
|
|
743
1633
|
const files = yield* getDefaultPathMap(outputDirectory);
|
|
744
1634
|
const assetPaths = [];
|
|
@@ -761,8 +1651,8 @@ var createStaticExportConfig = Effect6.fn("nextjs.createStaticExportConfig")(fun
|
|
|
761
1651
|
package: void 0
|
|
762
1652
|
};
|
|
763
1653
|
});
|
|
764
|
-
var createStandaloneConfig =
|
|
765
|
-
const pathService = yield*
|
|
1654
|
+
var createStandaloneConfig = Effect8.fn("nextjs.createStandaloneConfig")(function* (defaults, projectFolder, manifest) {
|
|
1655
|
+
const pathService = yield* Path7.Path;
|
|
766
1656
|
const resolved = yield* resolveStandaloneServer(projectFolder, manifest.distDir, manifest.repoRootToProject);
|
|
767
1657
|
if (!resolved) return defaults;
|
|
768
1658
|
const { standaloneRoot, serverDirectory, entrypoint } = resolved;
|
|
@@ -795,7 +1685,7 @@ var createStandaloneConfig = Effect6.fn("nextjs.createStandaloneConfig")(functio
|
|
|
795
1685
|
}
|
|
796
1686
|
};
|
|
797
1687
|
});
|
|
798
|
-
var createStandaloneV2Config =
|
|
1688
|
+
var createStandaloneV2Config = Effect8.fn("nextjs.createStandaloneV2Config")(function* (defaults, projectFolder, manifest) {
|
|
799
1689
|
const resolved = yield* resolveStandaloneServer(projectFolder, manifest.distDir, manifest.repoRootToProject);
|
|
800
1690
|
if (!resolved) return defaults;
|
|
801
1691
|
const { standaloneRoot, serverDirectory, entrypoint } = resolved;
|
|
@@ -903,9 +1793,9 @@ var nextjs = {
|
|
|
903
1793
|
routes: [{ source: "/*", destination: ".next/standalone/server.js" }],
|
|
904
1794
|
environmentVariables: { NODE_ENV: "production" }
|
|
905
1795
|
}),
|
|
906
|
-
refineDefaultConfig: (defaults, projectFolder) =>
|
|
907
|
-
const fs = yield*
|
|
908
|
-
const manifestContent = yield* fs.readFileString(`${projectFolder}/.gigadrive/nextjs.json`).pipe(
|
|
1796
|
+
refineDefaultConfig: (defaults, projectFolder) => Effect8.gen(function* () {
|
|
1797
|
+
const fs = yield* FileSystem8.FileSystem;
|
|
1798
|
+
const manifestContent = yield* fs.readFileString(`${projectFolder}/.gigadrive/nextjs.json`).pipe(Effect8.catchAll(() => Effect8.succeed(void 0)));
|
|
909
1799
|
const manifest = manifestContent ? parseGigadriveNextBuildManifest(manifestContent) : void 0;
|
|
910
1800
|
if (!manifest) return defaults;
|
|
911
1801
|
if (manifest.version === 2) {
|
|
@@ -916,8 +1806,8 @@ var nextjs = {
|
|
|
916
1806
|
};
|
|
917
1807
|
|
|
918
1808
|
// src/detection/frameworks/nuxt.ts
|
|
919
|
-
import { FileSystem as
|
|
920
|
-
import { Effect as
|
|
1809
|
+
import { FileSystem as FileSystem9 } from "@effect/platform";
|
|
1810
|
+
import { Effect as Effect9 } from "effect";
|
|
921
1811
|
var isVercelBuildOutputV3 = (content) => {
|
|
922
1812
|
try {
|
|
923
1813
|
const config = JSON.parse(content);
|
|
@@ -944,9 +1834,9 @@ var nuxt = {
|
|
|
944
1834
|
routes: [{ source: "/*", destination: ".output/server/index.mjs" }],
|
|
945
1835
|
environmentVariables: { NODE_ENV: "production", NITRO_PRESET: "node-server" }
|
|
946
1836
|
}),
|
|
947
|
-
refineDefaultConfig: (defaults, projectFolder) =>
|
|
948
|
-
const fs = yield*
|
|
949
|
-
const buildOutputConfig = yield* fs.readFileString(`${projectFolder}/.vercel/output/config.json`).pipe(
|
|
1837
|
+
refineDefaultConfig: (defaults, projectFolder) => Effect9.gen(function* () {
|
|
1838
|
+
const fs = yield* FileSystem9.FileSystem;
|
|
1839
|
+
const buildOutputConfig = yield* fs.readFileString(`${projectFolder}/.vercel/output/config.json`).pipe(Effect9.catchAll(() => Effect9.succeed(void 0)));
|
|
950
1840
|
if (!buildOutputConfig || !isVercelBuildOutputV3(buildOutputConfig)) {
|
|
951
1841
|
return defaults;
|
|
952
1842
|
}
|
|
@@ -960,6 +1850,43 @@ var nuxt = {
|
|
|
960
1850
|
})
|
|
961
1851
|
};
|
|
962
1852
|
|
|
1853
|
+
// src/detection/frameworks/php.ts
|
|
1854
|
+
import { FileSystem as FileSystem10, Path as Path8 } from "@effect/platform";
|
|
1855
|
+
import { Effect as Effect10 } from "effect";
|
|
1856
|
+
var COMPOSER_FILES = ["composer.json", "composer.lock"];
|
|
1857
|
+
var DOCUMENT_ROOTS = ["public", "web", "webroot", "public_html", "htdocs", "."];
|
|
1858
|
+
var refinePhpDocumentRoot = (defaults, projectFolder) => Effect10.gen(function* () {
|
|
1859
|
+
const fs = yield* FileSystem10.FileSystem;
|
|
1860
|
+
const pathService = yield* Path8.Path;
|
|
1861
|
+
for (const documentRoot of DOCUMENT_ROOTS) {
|
|
1862
|
+
const frontController = pathService.join(projectFolder, documentRoot, "index.php");
|
|
1863
|
+
if (yield* fs.exists(frontController).pipe(Effect10.catchAll(() => Effect10.succeed(false)))) {
|
|
1864
|
+
return phpFrontControllerDefaults({ documentRoot, excludeFiles: COMPOSER_FILES });
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
return defaults;
|
|
1868
|
+
});
|
|
1869
|
+
var getDefaultConfig = () => phpFrontControllerDefaults({ documentRoot: ".", excludeFiles: COMPOSER_FILES });
|
|
1870
|
+
var frontControllerPath = (documentRoot) => documentRoot === "." ? "index.php" : `${documentRoot}/index.php`;
|
|
1871
|
+
var phpComposerProjects = DOCUMENT_ROOTS.map((documentRoot) => ({
|
|
1872
|
+
slug: "php",
|
|
1873
|
+
name: "PHP",
|
|
1874
|
+
language: "php",
|
|
1875
|
+
detectors: [{ path: "composer.json" }, { path: frontControllerPath(documentRoot) }],
|
|
1876
|
+
priority: 7,
|
|
1877
|
+
getDefaultConfig,
|
|
1878
|
+
refineDefaultConfig: refinePhpDocumentRoot
|
|
1879
|
+
}));
|
|
1880
|
+
var phpSites = DOCUMENT_ROOTS.map((documentRoot) => ({
|
|
1881
|
+
slug: "php-site",
|
|
1882
|
+
name: "PHP",
|
|
1883
|
+
language: "php",
|
|
1884
|
+
detectors: [{ path: frontControllerPath(documentRoot) }],
|
|
1885
|
+
priority: 6,
|
|
1886
|
+
getDefaultConfig: () => ({ ...getDefaultConfig(), installCommand: "" }),
|
|
1887
|
+
refineDefaultConfig: (defaults, projectFolder) => refinePhpDocumentRoot(defaults, projectFolder).pipe(Effect10.map((refined) => ({ ...refined, installCommand: "" })))
|
|
1888
|
+
}));
|
|
1889
|
+
|
|
963
1890
|
// src/detection/frameworks/remix.ts
|
|
964
1891
|
var remix = {
|
|
965
1892
|
slug: "remix",
|
|
@@ -981,6 +1908,21 @@ var remix = {
|
|
|
981
1908
|
})
|
|
982
1909
|
};
|
|
983
1910
|
|
|
1911
|
+
// src/detection/frameworks/slim.ts
|
|
1912
|
+
var slim = {
|
|
1913
|
+
slug: "slim",
|
|
1914
|
+
name: "Slim",
|
|
1915
|
+
language: "php",
|
|
1916
|
+
detectors: [{ matchPackage: "slim/slim" }, { path: "public/index.php" }],
|
|
1917
|
+
priority: 75,
|
|
1918
|
+
getDefaultConfig: () => phpFrontControllerDefaults({
|
|
1919
|
+
documentRoot: "public",
|
|
1920
|
+
// slim/slim-skeleton logs to logs/ and caches the container and routes in var/cache.
|
|
1921
|
+
writablePaths: ["logs", "var/cache"],
|
|
1922
|
+
excludeFiles: ["tests/", "logs/", "var/"]
|
|
1923
|
+
})
|
|
1924
|
+
};
|
|
1925
|
+
|
|
984
1926
|
// src/detection/frameworks/sveltekit.ts
|
|
985
1927
|
var sveltekit = {
|
|
986
1928
|
slug: "sveltekit",
|
|
@@ -1020,12 +1962,13 @@ var symfony = {
|
|
|
1020
1962
|
assetsDir: "public",
|
|
1021
1963
|
populateAssetCache: true,
|
|
1022
1964
|
excludeFiles: ["tests/*", ".ddev", "var"],
|
|
1023
|
-
symlinks: { var: "/tmp" },
|
|
1024
1965
|
routes: [{ source: "/*", destination: "public/index.php" }],
|
|
1966
|
+
// The kernel's cache and log directories. A symlink to /tmp used to stand
|
|
1967
|
+
// in for them, which the build rejected as pointing outside the project.
|
|
1968
|
+
package: { writablePaths: ["var/cache", "var/log"] },
|
|
1025
1969
|
environmentVariables: {
|
|
1026
1970
|
APP_ENV: "prod",
|
|
1027
1971
|
APP_DEBUG: "false",
|
|
1028
|
-
APP_SECRET: "please_change_this_value_in_your_settings",
|
|
1029
1972
|
MESSENGER_TRANSPORT_DSN: "doctrine://default?auto_setup=0"
|
|
1030
1973
|
}
|
|
1031
1974
|
})
|
|
@@ -1051,6 +1994,22 @@ var vite = {
|
|
|
1051
1994
|
})
|
|
1052
1995
|
};
|
|
1053
1996
|
|
|
1997
|
+
// src/detection/frameworks/yii.ts
|
|
1998
|
+
var yii = {
|
|
1999
|
+
slug: "yii",
|
|
2000
|
+
name: "Yii 2",
|
|
2001
|
+
language: "php",
|
|
2002
|
+
detectors: [{ matchPackage: "yiisoft/yii2" }, { path: "web/index.php" }],
|
|
2003
|
+
priority: 80,
|
|
2004
|
+
getDefaultConfig: () => phpFrontControllerDefaults({
|
|
2005
|
+
documentRoot: "web",
|
|
2006
|
+
// @runtime holds cache, logs and sessions; the asset manager publishes
|
|
2007
|
+
// bundles from vendor/ into web/assets when a page first uses them.
|
|
2008
|
+
writablePaths: ["runtime", "web/assets"],
|
|
2009
|
+
excludeFiles: ["tests/", "runtime/", "web/assets/"]
|
|
2010
|
+
})
|
|
2011
|
+
};
|
|
2012
|
+
|
|
1054
2013
|
// src/detection/frameworks/index.ts
|
|
1055
2014
|
var FRAMEWORK_DEFINITIONS = [
|
|
1056
2015
|
nextjs,
|
|
@@ -1061,15 +2020,23 @@ var FRAMEWORK_DEFINITIONS = [
|
|
|
1061
2020
|
astro,
|
|
1062
2021
|
laravel,
|
|
1063
2022
|
symfony,
|
|
2023
|
+
cakephp,
|
|
2024
|
+
codeigniter,
|
|
2025
|
+
laminas,
|
|
2026
|
+
mezzio,
|
|
2027
|
+
yii,
|
|
2028
|
+
slim,
|
|
1064
2029
|
hono,
|
|
1065
2030
|
elysia,
|
|
1066
2031
|
fastify,
|
|
1067
2032
|
express,
|
|
2033
|
+
...phpComposerProjects,
|
|
2034
|
+
...phpSites,
|
|
1068
2035
|
vite
|
|
1069
2036
|
].sort((a, b) => b.priority - a.priority);
|
|
1070
2037
|
|
|
1071
2038
|
// src/detection/generate-config.ts
|
|
1072
|
-
import { Effect as
|
|
2039
|
+
import { Effect as Effect11 } from "effect";
|
|
1073
2040
|
var getInstallCommand = (pm) => {
|
|
1074
2041
|
switch (pm) {
|
|
1075
2042
|
case "bun":
|
|
@@ -1085,11 +2052,16 @@ var getInstallCommand = (pm) => {
|
|
|
1085
2052
|
return "npm install";
|
|
1086
2053
|
}
|
|
1087
2054
|
};
|
|
1088
|
-
var
|
|
2055
|
+
var COMPOSER_ROOT_FILES = /* @__PURE__ */ new Set(["composer.json", "composer.lock", "auth.json"]);
|
|
2056
|
+
var isPrivatePhpProjectFile = (projectPath) => {
|
|
2057
|
+
const segments = projectPath.split("/").filter((segment) => segment !== "" && segment !== ".");
|
|
2058
|
+
return segments.some((segment) => segment.startsWith(".")) || segments[0] === "vendor" || segments[0] === "node_modules" || segments.length === 1 && COMPOSER_ROOT_FILES.has(segments[0] ?? "");
|
|
2059
|
+
};
|
|
2060
|
+
var generateConfig = Effect11.fn("generateConfig")(function* (framework, packageManager, projectFolder, refinedDefaults) {
|
|
1089
2061
|
const defaults = refinedDefaults ?? framework.getDefaultConfig(packageManager);
|
|
1090
2062
|
const installCmd = defaults.installCommand ?? getInstallCommand(packageManager);
|
|
1091
|
-
const commands = [installCmd, ...defaults.commands];
|
|
1092
|
-
yield*
|
|
2063
|
+
const commands = installCmd ? [installCmd, ...defaults.commands] : [...defaults.commands];
|
|
2064
|
+
yield* Effect11.logDebug(`Generating config for ${framework.name}`, {
|
|
1093
2065
|
runtime: defaults.runtime,
|
|
1094
2066
|
entrypoint: defaults.entrypoint,
|
|
1095
2067
|
commands
|
|
@@ -1131,6 +2103,7 @@ var generateConfig = Effect8.fn("generateConfig")(function* (framework, packageM
|
|
|
1131
2103
|
if (assetsDir && !defaults.assetPaths && !defaults.assetPrefixes && !defaults.assetManifests) {
|
|
1132
2104
|
for (const file of yield* collectAssetFiles(projectFolder, assetsDir)) {
|
|
1133
2105
|
if (framework.language === "php" && /\.(php|phtml|phar)$/i.test(file)) continue;
|
|
2106
|
+
if (framework.language === "php" && isPrivatePhpProjectFile(`${assetsDir}/${file}`)) continue;
|
|
1134
2107
|
paths.push(`${assetsDir}/${file}`);
|
|
1135
2108
|
if (!servesDirectoryIndexes || file in overrides) continue;
|
|
1136
2109
|
if (file === "index.html") {
|
|
@@ -1154,31 +2127,31 @@ var generateConfig = Effect8.fn("generateConfig")(function* (framework, packageM
|
|
|
1154
2127
|
});
|
|
1155
2128
|
|
|
1156
2129
|
// src/detection/read-dependencies.ts
|
|
1157
|
-
import { FileSystem as
|
|
1158
|
-
import { Effect as
|
|
2130
|
+
import { FileSystem as FileSystem11, Path as Path9 } from "@effect/platform";
|
|
2131
|
+
import { Effect as Effect13 } from "effect";
|
|
1159
2132
|
|
|
1160
2133
|
// src/detection/types.ts
|
|
1161
|
-
import { Schema as
|
|
1162
|
-
var ManifestNotFoundError = class extends
|
|
1163
|
-
message:
|
|
1164
|
-
filePath:
|
|
2134
|
+
import { Schema as Schema5 } from "effect";
|
|
2135
|
+
var ManifestNotFoundError = class extends Schema5.TaggedError()("ManifestNotFoundError", {
|
|
2136
|
+
message: Schema5.String,
|
|
2137
|
+
filePath: Schema5.String
|
|
1165
2138
|
}) {
|
|
1166
2139
|
};
|
|
1167
|
-
var ManifestReadError = class extends
|
|
1168
|
-
message:
|
|
1169
|
-
filePath:
|
|
2140
|
+
var ManifestReadError = class extends Schema5.TaggedError()("ManifestReadError", {
|
|
2141
|
+
message: Schema5.String,
|
|
2142
|
+
filePath: Schema5.String
|
|
1170
2143
|
}) {
|
|
1171
2144
|
};
|
|
1172
|
-
var ManifestParseError = class extends
|
|
1173
|
-
message:
|
|
1174
|
-
filePath:
|
|
2145
|
+
var ManifestParseError = class extends Schema5.TaggedError()("ManifestParseError", {
|
|
2146
|
+
message: Schema5.String,
|
|
2147
|
+
filePath: Schema5.String
|
|
1175
2148
|
}) {
|
|
1176
2149
|
};
|
|
1177
|
-
var FrameworkNotDetectedError = class extends
|
|
2150
|
+
var FrameworkNotDetectedError = class extends Schema5.TaggedError()(
|
|
1178
2151
|
"FrameworkNotDetectedError",
|
|
1179
2152
|
{
|
|
1180
|
-
message:
|
|
1181
|
-
directory:
|
|
2153
|
+
message: Schema5.String,
|
|
2154
|
+
directory: Schema5.String
|
|
1182
2155
|
}
|
|
1183
2156
|
) {
|
|
1184
2157
|
};
|
|
@@ -1188,25 +2161,25 @@ var MANIFEST_CONFIG = {
|
|
|
1188
2161
|
node: { file: "package.json", depKeys: ["dependencies", "devDependencies"] },
|
|
1189
2162
|
php: { file: "composer.json", depKeys: ["require", "require-dev"] }
|
|
1190
2163
|
};
|
|
1191
|
-
var readManifest =
|
|
1192
|
-
const fs = yield*
|
|
1193
|
-
const exists = yield* fs.exists(filePath).pipe(
|
|
2164
|
+
var readManifest = Effect13.fn("readManifest")(function* (filePath) {
|
|
2165
|
+
const fs = yield* FileSystem11.FileSystem;
|
|
2166
|
+
const exists = yield* fs.exists(filePath).pipe(Effect13.catchAll(() => Effect13.succeed(false)));
|
|
1194
2167
|
if (!exists) {
|
|
1195
|
-
return yield*
|
|
2168
|
+
return yield* Effect13.fail(new ManifestNotFoundError({ message: "Manifest not found", filePath }));
|
|
1196
2169
|
}
|
|
1197
|
-
const content = yield* fs.readFileString(filePath).pipe(
|
|
1198
|
-
const parsed = yield*
|
|
2170
|
+
const content = yield* fs.readFileString(filePath).pipe(Effect13.mapError(() => new ManifestReadError({ message: "Failed to read manifest", filePath })));
|
|
2171
|
+
const parsed = yield* Effect13.try({
|
|
1199
2172
|
try: () => JSON.parse(content),
|
|
1200
2173
|
catch: () => new ManifestParseError({ message: "Failed to parse manifest JSON", filePath })
|
|
1201
2174
|
});
|
|
1202
2175
|
return parsed;
|
|
1203
2176
|
});
|
|
1204
|
-
var readDependencies =
|
|
1205
|
-
const pathService = yield*
|
|
2177
|
+
var readDependencies = Effect13.fn("readDependencies")(function* (projectFolder, language) {
|
|
2178
|
+
const pathService = yield* Path9.Path;
|
|
1206
2179
|
const config = MANIFEST_CONFIG[language];
|
|
1207
2180
|
const filePath = pathService.join(projectFolder, config.file);
|
|
1208
2181
|
const manifest = yield* readManifest(filePath).pipe(
|
|
1209
|
-
|
|
2182
|
+
Effect13.catchTag("ManifestNotFoundError", () => Effect13.succeed(null))
|
|
1210
2183
|
);
|
|
1211
2184
|
if (!manifest) {
|
|
1212
2185
|
return /* @__PURE__ */ new Set();
|
|
@@ -1224,9 +2197,9 @@ var readDependencies = Effect10.fn("readDependencies")(function* (projectFolder,
|
|
|
1224
2197
|
});
|
|
1225
2198
|
|
|
1226
2199
|
// src/detection/detect-framework.ts
|
|
1227
|
-
var matchesDetectionItem =
|
|
1228
|
-
const fs = yield*
|
|
1229
|
-
const pathService = yield*
|
|
2200
|
+
var matchesDetectionItem = Effect14.fn("matchesDetectionItem")(function* (item, projectFolder, framework, cachedReadDeps) {
|
|
2201
|
+
const fs = yield* FileSystem12.FileSystem;
|
|
2202
|
+
const pathService = yield* Path10.Path;
|
|
1230
2203
|
if (item.matchPackage != null) {
|
|
1231
2204
|
const deps = yield* cachedReadDeps(`${projectFolder}\0${framework.language}`);
|
|
1232
2205
|
if (!deps.has(item.matchPackage)) {
|
|
@@ -1235,12 +2208,12 @@ var matchesDetectionItem = Effect11.fn("matchesDetectionItem")(function* (item,
|
|
|
1235
2208
|
}
|
|
1236
2209
|
if (item.path != null) {
|
|
1237
2210
|
const filePath = pathService.join(projectFolder, item.path);
|
|
1238
|
-
const exists = yield* fs.exists(filePath).pipe(
|
|
2211
|
+
const exists = yield* fs.exists(filePath).pipe(Effect14.catchAll(() => Effect14.succeed(false)));
|
|
1239
2212
|
if (!exists) {
|
|
1240
2213
|
return false;
|
|
1241
2214
|
}
|
|
1242
2215
|
if (item.matchContent != null) {
|
|
1243
|
-
const content = yield* fs.readFileString(filePath).pipe(
|
|
2216
|
+
const content = yield* fs.readFileString(filePath).pipe(Effect14.catchAll(() => Effect14.succeed("")));
|
|
1244
2217
|
let regexMatch = false;
|
|
1245
2218
|
try {
|
|
1246
2219
|
regexMatch = new RegExp(item.matchContent).test(content);
|
|
@@ -1253,7 +2226,7 @@ var matchesDetectionItem = Effect11.fn("matchesDetectionItem")(function* (item,
|
|
|
1253
2226
|
}
|
|
1254
2227
|
return true;
|
|
1255
2228
|
});
|
|
1256
|
-
var matchesFramework =
|
|
2229
|
+
var matchesFramework = Effect14.fn("matchesFramework")(function* (framework, projectFolder, cachedReadDeps) {
|
|
1257
2230
|
for (const detector of framework.detectors) {
|
|
1258
2231
|
const matches = yield* matchesDetectionItem(detector, projectFolder, framework, cachedReadDeps);
|
|
1259
2232
|
if (!matches) {
|
|
@@ -1262,9 +2235,9 @@ var matchesFramework = Effect11.fn("matchesFramework")(function* (framework, pro
|
|
|
1262
2235
|
}
|
|
1263
2236
|
return true;
|
|
1264
2237
|
});
|
|
1265
|
-
var detectFramework =
|
|
1266
|
-
yield*
|
|
1267
|
-
const cachedReadDeps = yield*
|
|
2238
|
+
var detectFramework = Effect14.fn("detectFramework")(function* (projectFolder) {
|
|
2239
|
+
yield* Effect14.logDebug(`Detecting framework in ${projectFolder}`);
|
|
2240
|
+
const cachedReadDeps = yield* Effect14.cachedFunction((key) => {
|
|
1268
2241
|
const sepIndex = key.lastIndexOf("\0");
|
|
1269
2242
|
const folder = key.slice(0, sepIndex);
|
|
1270
2243
|
const language = key.slice(sepIndex + 1);
|
|
@@ -1273,7 +2246,7 @@ var detectFramework = Effect11.fn("detectFramework")(function* (projectFolder) {
|
|
|
1273
2246
|
for (const framework of FRAMEWORK_DEFINITIONS) {
|
|
1274
2247
|
const matches = yield* matchesFramework(framework, projectFolder, cachedReadDeps);
|
|
1275
2248
|
if (matches) {
|
|
1276
|
-
yield*
|
|
2249
|
+
yield* Effect14.log(`Detected framework: ${framework.name}`, { slug: framework.slug });
|
|
1277
2250
|
const detectedPackageManager = yield* detectPackageManager(projectFolder);
|
|
1278
2251
|
const packageManager = framework.language === "php" ? "composer" : detectedPackageManager;
|
|
1279
2252
|
const defaults = framework.getDefaultConfig(packageManager);
|
|
@@ -1282,7 +2255,7 @@ var detectFramework = Effect11.fn("detectFramework")(function* (projectFolder) {
|
|
|
1282
2255
|
return { framework, packageManager, config };
|
|
1283
2256
|
}
|
|
1284
2257
|
}
|
|
1285
|
-
return yield*
|
|
2258
|
+
return yield* Effect14.fail(
|
|
1286
2259
|
new FrameworkNotDetectedError({
|
|
1287
2260
|
message: `No framework detected in project directory`,
|
|
1288
2261
|
directory: projectFolder
|
|
@@ -1291,15 +2264,22 @@ var detectFramework = Effect11.fn("detectFramework")(function* (projectFolder) {
|
|
|
1291
2264
|
});
|
|
1292
2265
|
|
|
1293
2266
|
// src/detection/merge-config.ts
|
|
1294
|
-
import { Effect as
|
|
1295
|
-
var mergeWithFrameworkDefaults =
|
|
1296
|
-
yield*
|
|
2267
|
+
import { Effect as Effect15 } from "effect";
|
|
2268
|
+
var mergeWithFrameworkDefaults = Effect15.fn("mergeWithFrameworkDefaults")(function* (userConfig, frameworkConfig) {
|
|
2269
|
+
yield* Effect15.logDebug("Merging user config with framework defaults");
|
|
1297
2270
|
const userHasAssets = (userConfig.assets?.paths?.length ?? 0) > 0 || (userConfig.assets?.prefixes?.length ?? 0) > 0 || (userConfig.assets?.manifests?.length ?? 0) > 0;
|
|
2271
|
+
const isContainer = (entrypoint) => entrypoint.runtime === CONTAINER_RUNTIME;
|
|
2272
|
+
const userFileFunctions = userConfig.entrypoints.filter((entrypoint) => !isContainer(entrypoint));
|
|
2273
|
+
const containerPaths = new Set(userConfig.entrypoints.filter(isContainer).map((entrypoint) => entrypoint.path));
|
|
2274
|
+
const targetsContainer = (route) => containerPaths.has(route.destination.replace(/^\/+/, ""));
|
|
1298
2275
|
const merged = {
|
|
1299
2276
|
regions: userConfig.regions,
|
|
1300
2277
|
commands: userConfig.commands.length > 0 ? userConfig.commands : frameworkConfig.commands,
|
|
1301
|
-
entrypoints:
|
|
1302
|
-
|
|
2278
|
+
entrypoints: [
|
|
2279
|
+
...userFileFunctions.length > 0 ? userFileFunctions : frameworkConfig.entrypoints,
|
|
2280
|
+
...userConfig.entrypoints.filter(isContainer)
|
|
2281
|
+
],
|
|
2282
|
+
routes: containerPaths.size > 0 && userConfig.routes.every(targetsContainer) ? [...userConfig.routes, ...frameworkConfig.routes] : userConfig.routes.length > 0 ? userConfig.routes : frameworkConfig.routes,
|
|
1303
2283
|
assets: userHasAssets ? userConfig.assets : frameworkConfig.assets,
|
|
1304
2284
|
environmentVariables: {
|
|
1305
2285
|
...frameworkConfig.environmentVariables,
|
|
@@ -1307,6 +2287,7 @@ var mergeWithFrameworkDefaults = Effect12.fn("mergeWithFrameworkDefaults")(funct
|
|
|
1307
2287
|
},
|
|
1308
2288
|
excludeFiles: userConfig.excludeFiles && userConfig.excludeFiles.length > 0 ? userConfig.excludeFiles : frameworkConfig.excludeFiles,
|
|
1309
2289
|
services: userConfig.services,
|
|
2290
|
+
...userConfig.sidecars !== void 0 && { sidecars: userConfig.sidecars },
|
|
1310
2291
|
userArchive: userConfig.userArchive,
|
|
1311
2292
|
warnings: [...frameworkConfig.warnings, ...userConfig.warnings],
|
|
1312
2293
|
errors: [...frameworkConfig.errors, ...userConfig.errors]
|
|
@@ -1314,51 +2295,6 @@ var mergeWithFrameworkDefaults = Effect12.fn("mergeWithFrameworkDefaults")(funct
|
|
|
1314
2295
|
return merged;
|
|
1315
2296
|
});
|
|
1316
2297
|
|
|
1317
|
-
// src/errors.ts
|
|
1318
|
-
import { Schema as Schema5 } from "effect";
|
|
1319
|
-
var ConfigFileNotFoundError = class extends Schema5.TaggedError()("ConfigFileNotFoundError", {
|
|
1320
|
-
message: Schema5.String,
|
|
1321
|
-
filePath: Schema5.String
|
|
1322
|
-
}) {
|
|
1323
|
-
};
|
|
1324
|
-
var ConfigFileEmptyError = class extends Schema5.TaggedError()("ConfigFileEmptyError", {
|
|
1325
|
-
message: Schema5.String,
|
|
1326
|
-
filePath: Schema5.String
|
|
1327
|
-
}) {
|
|
1328
|
-
};
|
|
1329
|
-
var ConfigFileParseError = class extends Schema5.TaggedError()("ConfigFileParseError", {
|
|
1330
|
-
message: Schema5.String,
|
|
1331
|
-
filePath: Schema5.String,
|
|
1332
|
-
cause: Schema5.optional(Schema5.String)
|
|
1333
|
-
}) {
|
|
1334
|
-
};
|
|
1335
|
-
var ConfigModuleLoadError = class extends Schema5.TaggedError()("ConfigModuleLoadError", {
|
|
1336
|
-
message: Schema5.String,
|
|
1337
|
-
filePath: Schema5.String,
|
|
1338
|
-
cause: Schema5.optional(Schema5.String)
|
|
1339
|
-
}) {
|
|
1340
|
-
};
|
|
1341
|
-
var ConfigVersionError = class extends Schema5.TaggedError()("ConfigVersionError", {
|
|
1342
|
-
message: Schema5.String,
|
|
1343
|
-
filePath: Schema5.String,
|
|
1344
|
-
version: Schema5.optional(Schema5.Number)
|
|
1345
|
-
}) {
|
|
1346
|
-
};
|
|
1347
|
-
var ConfigSchemaValidationError = class extends Schema5.TaggedError()(
|
|
1348
|
-
"ConfigSchemaValidationError",
|
|
1349
|
-
{
|
|
1350
|
-
message: Schema5.String,
|
|
1351
|
-
filePath: Schema5.String,
|
|
1352
|
-
validationErrors: Schema5.Array(Schema5.String)
|
|
1353
|
-
}
|
|
1354
|
-
) {
|
|
1355
|
-
};
|
|
1356
|
-
var FunctionConfigError = class extends Schema5.TaggedError()("FunctionConfigError", {
|
|
1357
|
-
message: Schema5.String,
|
|
1358
|
-
functionPath: Schema5.String
|
|
1359
|
-
}) {
|
|
1360
|
-
};
|
|
1361
|
-
|
|
1362
2298
|
// src/filter-functions-from-assets.ts
|
|
1363
2299
|
var filterFunctionsFromAssets = (config) => {
|
|
1364
2300
|
return {
|
|
@@ -1370,28 +2306,24 @@ var filterFunctionsFromAssets = (config) => {
|
|
|
1370
2306
|
};
|
|
1371
2307
|
};
|
|
1372
2308
|
|
|
1373
|
-
// src/normalized-config.ts
|
|
1374
|
-
var DEFAULT_FUNCTION_DURATION_SECONDS = 30;
|
|
1375
|
-
var MAX_FUNCTION_DURATION_SECONDS = 28800;
|
|
1376
|
-
|
|
1377
2309
|
// src/parse-config.ts
|
|
1378
|
-
import { Effect as
|
|
2310
|
+
import { Effect as Effect21 } from "effect";
|
|
1379
2311
|
|
|
1380
2312
|
// src/services/raw-config-reader.ts
|
|
1381
|
-
import { FileSystem as
|
|
1382
|
-
import { Effect as
|
|
1383
|
-
import { parse as
|
|
2313
|
+
import { FileSystem as FileSystem13, Path as Path11 } from "@effect/platform";
|
|
2314
|
+
import { Effect as Effect17 } from "effect";
|
|
2315
|
+
import { parse as parseYaml2 } from "yaml";
|
|
1384
2316
|
|
|
1385
2317
|
// src/services/config-module-loader.ts
|
|
1386
|
-
import { Effect as
|
|
2318
|
+
import { Effect as Effect16 } from "effect";
|
|
1387
2319
|
import { createJiti } from "jiti";
|
|
1388
2320
|
var MISSING_DEFAULT_EXPORT = /* @__PURE__ */ Symbol("MissingDefaultExport");
|
|
1389
2321
|
var STRICT_DEFAULT_EXPORT_EXTENSIONS = [".ts", ".mts", ".mjs"];
|
|
1390
|
-
var ConfigModuleLoader = class extends
|
|
1391
|
-
effect:
|
|
1392
|
-
const loadConfigModule =
|
|
2322
|
+
var ConfigModuleLoader = class extends Effect16.Service()("ConfigModuleLoader", {
|
|
2323
|
+
effect: Effect16.gen(function* () {
|
|
2324
|
+
const loadConfigModule = Effect16.fn("ConfigModuleLoader.loadConfigModule")(function* (filePath) {
|
|
1393
2325
|
const extension = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
|
|
1394
|
-
const mod = yield*
|
|
2326
|
+
const mod = yield* Effect16.tryPromise({
|
|
1395
2327
|
try: async () => {
|
|
1396
2328
|
const jiti = createJiti(filePath, { fsCache: false, interopDefault: true, moduleCache: false });
|
|
1397
2329
|
const namespace = await jiti.import(filePath);
|
|
@@ -1410,7 +2342,7 @@ var ConfigModuleLoader = class extends Effect13.Service()("ConfigModuleLoader",
|
|
|
1410
2342
|
})
|
|
1411
2343
|
});
|
|
1412
2344
|
if (mod === MISSING_DEFAULT_EXPORT) {
|
|
1413
|
-
return yield*
|
|
2345
|
+
return yield* Effect16.fail(
|
|
1414
2346
|
new ConfigModuleLoadError({
|
|
1415
2347
|
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.`,
|
|
1416
2348
|
filePath
|
|
@@ -1418,7 +2350,7 @@ var ConfigModuleLoader = class extends Effect13.Service()("ConfigModuleLoader",
|
|
|
1418
2350
|
);
|
|
1419
2351
|
}
|
|
1420
2352
|
if (typeof mod === "function") {
|
|
1421
|
-
return yield*
|
|
2353
|
+
return yield* Effect16.fail(
|
|
1422
2354
|
new ConfigModuleLoadError({
|
|
1423
2355
|
message: `Config module at ${filePath} default-exports a function; config factories are not supported. Export a config object instead (optionally wrapped in defineConfig).`,
|
|
1424
2356
|
filePath
|
|
@@ -1426,7 +2358,7 @@ var ConfigModuleLoader = class extends Effect13.Service()("ConfigModuleLoader",
|
|
|
1426
2358
|
);
|
|
1427
2359
|
}
|
|
1428
2360
|
if (typeof mod !== "object" || mod === null || Array.isArray(mod)) {
|
|
1429
|
-
return yield*
|
|
2361
|
+
return yield* Effect16.fail(
|
|
1430
2362
|
new ConfigModuleLoadError({
|
|
1431
2363
|
message: `Config module at ${filePath} must default-export a config object.`,
|
|
1432
2364
|
filePath
|
|
@@ -1456,36 +2388,36 @@ var ALLOWED_CONFIG_NAMES = [
|
|
|
1456
2388
|
"nebula.json"
|
|
1457
2389
|
];
|
|
1458
2390
|
var MODULE_EXTENSIONS = [".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"];
|
|
1459
|
-
var RawConfigReader = class extends
|
|
2391
|
+
var RawConfigReader = class extends Effect17.Service()("RawConfigReader", {
|
|
1460
2392
|
dependencies: [ConfigModuleLoader.Default],
|
|
1461
|
-
effect:
|
|
1462
|
-
const fs = yield*
|
|
1463
|
-
const pathService = yield*
|
|
2393
|
+
effect: Effect17.gen(function* () {
|
|
2394
|
+
const fs = yield* FileSystem13.FileSystem;
|
|
2395
|
+
const pathService = yield* Path11.Path;
|
|
1464
2396
|
const moduleLoader = yield* ConfigModuleLoader;
|
|
1465
|
-
const findConfig =
|
|
2397
|
+
const findConfig = Effect17.fn("RawConfigReader.findConfig")(function* (projectFolder) {
|
|
1466
2398
|
for (const name of ALLOWED_CONFIG_NAMES) {
|
|
1467
2399
|
const filePath = pathService.join(projectFolder, name);
|
|
1468
|
-
const exists = yield* fs.exists(filePath).pipe(
|
|
2400
|
+
const exists = yield* fs.exists(filePath).pipe(Effect17.catchAll(() => Effect17.succeed(false)));
|
|
1469
2401
|
if (exists) {
|
|
1470
2402
|
return filePath;
|
|
1471
2403
|
}
|
|
1472
2404
|
}
|
|
1473
2405
|
return null;
|
|
1474
2406
|
});
|
|
1475
|
-
const readRawConfig =
|
|
1476
|
-
const exists = yield* fs.exists(filePath).pipe(
|
|
2407
|
+
const readRawConfig = Effect17.fn("RawConfigReader.readRawConfig")(function* (filePath, options) {
|
|
2408
|
+
const exists = yield* fs.exists(filePath).pipe(Effect17.catchAll(() => Effect17.succeed(false)));
|
|
1477
2409
|
if (!exists) {
|
|
1478
|
-
return yield*
|
|
2410
|
+
return yield* Effect17.fail(
|
|
1479
2411
|
new ConfigFileNotFoundError({ message: `Config file not found at ${filePath}`, filePath })
|
|
1480
2412
|
);
|
|
1481
2413
|
}
|
|
1482
2414
|
const fileContents = yield* fs.readFileString(filePath).pipe(
|
|
1483
|
-
|
|
2415
|
+
Effect17.mapError(
|
|
1484
2416
|
() => new ConfigFileParseError({ message: `Failed to read config file at ${filePath}`, filePath })
|
|
1485
2417
|
)
|
|
1486
2418
|
);
|
|
1487
2419
|
if (fileContents.length === 0) {
|
|
1488
|
-
return yield*
|
|
2420
|
+
return yield* Effect17.fail(
|
|
1489
2421
|
new ConfigFileEmptyError({ message: `Config file is empty at ${filePath}`, filePath })
|
|
1490
2422
|
);
|
|
1491
2423
|
}
|
|
@@ -1498,10 +2430,10 @@ var RawConfigReader = class extends Effect14.Service()("RawConfigReader", {
|
|
|
1498
2430
|
if (fileExtension === ".json") {
|
|
1499
2431
|
parsed = JSON.parse(fileContents);
|
|
1500
2432
|
} else {
|
|
1501
|
-
parsed =
|
|
2433
|
+
parsed = parseYaml2(fileContents);
|
|
1502
2434
|
}
|
|
1503
2435
|
} catch (error) {
|
|
1504
|
-
return yield*
|
|
2436
|
+
return yield* Effect17.fail(
|
|
1505
2437
|
new ConfigFileParseError({
|
|
1506
2438
|
message: `Failed to parse config file at ${filePath}: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1507
2439
|
filePath,
|
|
@@ -1511,21 +2443,21 @@ var RawConfigReader = class extends Effect14.Service()("RawConfigReader", {
|
|
|
1511
2443
|
}
|
|
1512
2444
|
}
|
|
1513
2445
|
if (parsed == null) {
|
|
1514
|
-
return yield*
|
|
2446
|
+
return yield* Effect17.fail(
|
|
1515
2447
|
new ConfigFileParseError({ message: `Config file could not be parsed at ${filePath}`, filePath })
|
|
1516
2448
|
);
|
|
1517
2449
|
}
|
|
1518
2450
|
if (!options?.disableVersionCheck && typeof parsed.version !== "number") {
|
|
1519
|
-
return yield*
|
|
2451
|
+
return yield* Effect17.fail(
|
|
1520
2452
|
new ConfigVersionError({ message: `Config file is missing version at ${filePath}`, filePath })
|
|
1521
2453
|
);
|
|
1522
2454
|
}
|
|
1523
2455
|
return parsed;
|
|
1524
2456
|
});
|
|
1525
2457
|
const readConfigFile = (configFilePath) => readRawConfig(configFilePath, { disableVersionCheck: true }).pipe(
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
2458
|
+
Effect17.map((parsed) => parsed),
|
|
2459
|
+
Effect17.catchTag("ConfigFileNotFoundError", () => Effect17.succeed(null)),
|
|
2460
|
+
Effect17.withSpan("RawConfigReader.readConfigFile")
|
|
1529
2461
|
);
|
|
1530
2462
|
return { findConfig, readRawConfig, readConfigFile };
|
|
1531
2463
|
})
|
|
@@ -1535,17 +2467,17 @@ var RawConfigReader = class extends Effect14.Service()("RawConfigReader", {
|
|
|
1535
2467
|
// src/services/schema-validator.ts
|
|
1536
2468
|
import Ajv from "ajv";
|
|
1537
2469
|
import addFormats from "ajv-formats";
|
|
1538
|
-
import { Effect as
|
|
1539
|
-
var SchemaValidator = class extends
|
|
1540
|
-
effect:
|
|
2470
|
+
import { Effect as Effect18 } from "effect";
|
|
2471
|
+
var SchemaValidator = class extends Effect18.Service()("SchemaValidator", {
|
|
2472
|
+
effect: Effect18.gen(function* () {
|
|
1541
2473
|
const ajv = new Ajv();
|
|
1542
2474
|
addFormats(ajv);
|
|
1543
|
-
const validate =
|
|
2475
|
+
const validate = Effect18.fn("SchemaValidator.validate")(function* (config, schema, filePath) {
|
|
1544
2476
|
const compiledValidate = ajv.compile(schema);
|
|
1545
2477
|
const valid = compiledValidate(config);
|
|
1546
2478
|
if (!valid) {
|
|
1547
2479
|
const errors = compiledValidate.errors?.map((e) => `${e.instancePath || "/"} ${e.message ?? ""}`.trim()) ?? [];
|
|
1548
|
-
return yield*
|
|
2480
|
+
return yield* Effect18.fail(
|
|
1549
2481
|
new ConfigSchemaValidationError({
|
|
1550
2482
|
message: `Config file at ${filePath} is invalid: ${ajv.errorsText(compiledValidate.errors)}`,
|
|
1551
2483
|
filePath,
|
|
@@ -1601,8 +2533,9 @@ var getFilesForPattern = async (pattern, projectFolder, excludeFiles = []) => {
|
|
|
1601
2533
|
};
|
|
1602
2534
|
|
|
1603
2535
|
// src/services/v4-config-parser.ts
|
|
1604
|
-
import { Effect as
|
|
2536
|
+
import { Effect as Effect19 } from "effect";
|
|
1605
2537
|
import { minimatch as minimatch2 } from "minimatch";
|
|
2538
|
+
import { posix as posix2 } from "path";
|
|
1606
2539
|
import safeRegex from "safe-regex2";
|
|
1607
2540
|
var DEFAULT_FUNCTION_SETTINGS = {
|
|
1608
2541
|
memory: 128,
|
|
@@ -1635,6 +2568,46 @@ var normalizeImagePolicy = (images) => {
|
|
|
1635
2568
|
variants: images.variants ?? {}
|
|
1636
2569
|
};
|
|
1637
2570
|
};
|
|
2571
|
+
var DURATION_UNIT_SECONDS = { s: 1, m: 60, h: 3600, d: 86400 };
|
|
2572
|
+
var queueDurationSeconds = (value) => {
|
|
2573
|
+
if (value === void 0) return void 0;
|
|
2574
|
+
if (typeof value === "number") return value;
|
|
2575
|
+
const match = /^(\d+(?:\.\d+)?)(s|m|h|d)$/.exec(value);
|
|
2576
|
+
if (!match)
|
|
2577
|
+
throw new Error(`Invalid queue duration "${value}". Use seconds or a string such as 30s, 10m, 1.5h or 4d.`);
|
|
2578
|
+
return Math.ceil(Number(match[1]) * DURATION_UNIT_SECONDS[match[2]]);
|
|
2579
|
+
};
|
|
2580
|
+
var byName = (left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0;
|
|
2581
|
+
var definedOnly = (value) => Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
|
|
2582
|
+
var normalizeQueue = (name, queue) => {
|
|
2583
|
+
if (queue === null) return { name };
|
|
2584
|
+
const schedules = queue.schedules ? Object.entries(queue.schedules).map(
|
|
2585
|
+
([scheduleName, schedule]) => definedOnly({
|
|
2586
|
+
name: scheduleName,
|
|
2587
|
+
cron: schedule.cron,
|
|
2588
|
+
timezone: schedule.timezone,
|
|
2589
|
+
body: schedule.body === void 0 || typeof schedule.body === "string" ? schedule.body : JSON.stringify(schedule.body),
|
|
2590
|
+
// A plain-text body labelled JSON would fail to decode on every fire.
|
|
2591
|
+
contentType: schedule.contentType ?? (typeof schedule.body === "string" ? "text/plain; charset=utf-8" : void 0),
|
|
2592
|
+
headers: schedule.headers,
|
|
2593
|
+
enabled: schedule.enabled
|
|
2594
|
+
})
|
|
2595
|
+
).sort(byName) : void 0;
|
|
2596
|
+
return definedOnly({
|
|
2597
|
+
name,
|
|
2598
|
+
consumer: queue.consumer,
|
|
2599
|
+
visibilityTimeoutSeconds: queueDurationSeconds(queue.visibilityTimeout),
|
|
2600
|
+
retentionSeconds: queueDurationSeconds(queue.retention),
|
|
2601
|
+
maxAttempts: queue.maxAttempts,
|
|
2602
|
+
retryBackoffMinSeconds: queueDurationSeconds(queue.retryBackoff?.min),
|
|
2603
|
+
retryBackoffMaxSeconds: queueDurationSeconds(queue.retryBackoff?.max),
|
|
2604
|
+
deduplicationWindowSeconds: queueDurationSeconds(queue.deduplicationWindow),
|
|
2605
|
+
concurrency: queue.concurrency,
|
|
2606
|
+
rateLimit: queue.rateLimit == null ? queue.rateLimit : { count: queue.rateLimit.count, periodSeconds: queueDurationSeconds(queue.rateLimit.period) ?? 1 },
|
|
2607
|
+
deadLetter: queue.deadLetter,
|
|
2608
|
+
schedules
|
|
2609
|
+
});
|
|
2610
|
+
};
|
|
1638
2611
|
var normalizeServices = (services) => {
|
|
1639
2612
|
if (services == null) return void 0;
|
|
1640
2613
|
const normalized = [];
|
|
@@ -1647,7 +2620,13 @@ var normalizeServices = (services) => {
|
|
|
1647
2620
|
if (services.storage !== void 0) {
|
|
1648
2621
|
normalized.push({
|
|
1649
2622
|
type: "storage",
|
|
1650
|
-
buckets: Object.entries(services.storage.buckets).map(([name, bucket]) => ({ name, visibility: bucket?.visibility ?? "private" })).sort(
|
|
2623
|
+
buckets: Object.entries(services.storage.buckets).map(([name, bucket]) => ({ name, visibility: bucket?.visibility ?? "private" })).sort(byName)
|
|
2624
|
+
});
|
|
2625
|
+
}
|
|
2626
|
+
if (services.queues !== void 0) {
|
|
2627
|
+
normalized.push({
|
|
2628
|
+
type: "queues",
|
|
2629
|
+
queues: Object.entries(services.queues).map(([name, queue]) => normalizeQueue(name, queue)).sort(byName)
|
|
1651
2630
|
});
|
|
1652
2631
|
}
|
|
1653
2632
|
return normalized.length > 0 ? normalized : void 0;
|
|
@@ -1705,9 +2684,10 @@ var mapRoute = (route, entrypoints) => ({
|
|
|
1705
2684
|
negativeRequirements: route.missing,
|
|
1706
2685
|
status: route.statusCode
|
|
1707
2686
|
});
|
|
1708
|
-
var parseEntrypoints =
|
|
2687
|
+
var parseEntrypoints = Effect19.fn("parseEntrypoints")(function* (config, projectFolder) {
|
|
1709
2688
|
const entrypoints = [];
|
|
1710
|
-
|
|
2689
|
+
const dockerFunctions = [];
|
|
2690
|
+
if (config.functions == null) return { entrypoints, dockerFunctions };
|
|
1711
2691
|
for (const [fnPath, func] of Object.entries(config.functions)) {
|
|
1712
2692
|
if (getFunctionSettings(fnPath, config) == null) {
|
|
1713
2693
|
return yield* new FunctionConfigError({
|
|
@@ -1715,7 +2695,7 @@ var parseEntrypoints = Effect16.fn("parseEntrypoints")(function* (config, projec
|
|
|
1715
2695
|
functionPath: fnPath
|
|
1716
2696
|
});
|
|
1717
2697
|
}
|
|
1718
|
-
const matchedFiles = yield*
|
|
2698
|
+
const matchedFiles = yield* Effect19.tryPromise({
|
|
1719
2699
|
try: () => getFilesForPattern(fnPath, projectFolder, func.excludeFiles),
|
|
1720
2700
|
catch: (error) => new FunctionConfigError({
|
|
1721
2701
|
message: `Failed to resolve files for function pattern '${fnPath}': ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -1732,6 +2712,35 @@ var parseEntrypoints = Effect16.fn("parseEntrypoints")(function* (config, projec
|
|
|
1732
2712
|
functionPath: file
|
|
1733
2713
|
});
|
|
1734
2714
|
}
|
|
2715
|
+
if (settings.runtime === CONTAINER_RUNTIME) {
|
|
2716
|
+
const unsupported = ["symlinks", "includeFiles"].filter((key) => settings[key] !== void 0);
|
|
2717
|
+
if (unsupported.length > 0) {
|
|
2718
|
+
return yield* new FunctionConfigError({
|
|
2719
|
+
message: `Function '${file}' runs a Dockerfile, so ${unsupported.join(" and ")} do not apply. Copy files in the Dockerfile instead.`,
|
|
2720
|
+
functionPath: file
|
|
2721
|
+
});
|
|
2722
|
+
}
|
|
2723
|
+
const declared = Object.entries(config.functions).filter(([pattern]) => matchesPattern(file, pattern)).reduce((merged, [, value]) => ({ ...merged, ...value }), {});
|
|
2724
|
+
dockerFunctions.push({
|
|
2725
|
+
file,
|
|
2726
|
+
name: dockerFunctionContainerName(file),
|
|
2727
|
+
container: {
|
|
2728
|
+
build: { context: posix2.dirname(file), dockerfile: posix2.basename(file) },
|
|
2729
|
+
...declared.port !== void 0 && { port: declared.port },
|
|
2730
|
+
...declared.memory !== void 0 && { memory: declared.memory },
|
|
2731
|
+
...declared.max_duration !== void 0 && { max_duration: declared.max_duration },
|
|
2732
|
+
...declared.streaming !== void 0 && { streaming: declared.streaming },
|
|
2733
|
+
...func.schedule !== void 0 && { schedule: func.schedule }
|
|
2734
|
+
}
|
|
2735
|
+
});
|
|
2736
|
+
continue;
|
|
2737
|
+
}
|
|
2738
|
+
if (settings.port !== void 0) {
|
|
2739
|
+
return yield* new FunctionConfigError({
|
|
2740
|
+
message: `Function '${file}' sets port, which only applies to 'runtime: docker'.`,
|
|
2741
|
+
functionPath: file
|
|
2742
|
+
});
|
|
2743
|
+
}
|
|
1735
2744
|
const runtime = settings.runtime ?? "node-20";
|
|
1736
2745
|
const streaming = settings.streaming ?? runtimeStreamsByDefault(runtime);
|
|
1737
2746
|
entrypoints.push({
|
|
@@ -1749,25 +2758,84 @@ var parseEntrypoints = Effect16.fn("parseEntrypoints")(function* (config, projec
|
|
|
1749
2758
|
});
|
|
1750
2759
|
}
|
|
1751
2760
|
}
|
|
1752
|
-
|
|
2761
|
+
dockerFunctions.sort((left, right) => left.file < right.file ? -1 : left.file > right.file ? 1 : 0);
|
|
2762
|
+
for (const [index, { file, name }] of dockerFunctions.entries()) {
|
|
2763
|
+
const clash = dockerFunctions.slice(0, index).find((candidate) => candidate.name === name);
|
|
2764
|
+
if (clash !== void 0) {
|
|
2765
|
+
return yield* new FunctionConfigError({
|
|
2766
|
+
message: `Functions '${clash.file}' and '${file}' would both be named '${name}'. Declare one of them under 'containers' with an explicit name.`,
|
|
2767
|
+
functionPath: file
|
|
2768
|
+
});
|
|
2769
|
+
}
|
|
2770
|
+
}
|
|
2771
|
+
return { entrypoints, dockerFunctions };
|
|
1753
2772
|
});
|
|
1754
|
-
var collectAssets =
|
|
2773
|
+
var collectAssets = Effect19.fn("collectAssets")(function* (config, projectFolder) {
|
|
1755
2774
|
if (config.assets == null) return [];
|
|
1756
2775
|
const assetNames = yield* collectAssetFiles(projectFolder, config.assets);
|
|
1757
2776
|
return assetNames.filter((assetName) => getFunctionSettings(`${config.assets}/${assetName}`, config) == null).map((assetName) => `${config.assets}/${assetName}`);
|
|
1758
2777
|
});
|
|
1759
|
-
var
|
|
2778
|
+
var reservedRuntimePorts = (entrypoint) => entrypoint.runtime === CONTAINER_RUNTIME ? [] : entrypoint.runtime.startsWith("php-") ? [8080, 9e3] : [8080];
|
|
2779
|
+
var parseContainers = Effect19.fn("parseContainers")(function* (config, projectFolder, fileEntrypoints, dockerFunctions) {
|
|
2780
|
+
const warnings = [];
|
|
2781
|
+
let containers = {};
|
|
2782
|
+
if (config.compose != null) {
|
|
2783
|
+
const imported = yield* readComposeContainers(config.compose, projectFolder);
|
|
2784
|
+
containers = imported.containers;
|
|
2785
|
+
warnings.push(...imported.warnings);
|
|
2786
|
+
}
|
|
2787
|
+
containers = { ...containers, ...config.containers ?? {} };
|
|
2788
|
+
for (const { file, name, container } of dockerFunctions) {
|
|
2789
|
+
if (containers[name] !== void 0) {
|
|
2790
|
+
return yield* new ContainerConfigError({
|
|
2791
|
+
message: `Function '${file}' runs as container '${name}', which 'containers' or the Compose file already declares. Rename one of them.`,
|
|
2792
|
+
containerName: name
|
|
2793
|
+
});
|
|
2794
|
+
}
|
|
2795
|
+
containers[name] = container;
|
|
2796
|
+
}
|
|
2797
|
+
const result = yield* normalizeContainers(containers, projectFolder);
|
|
2798
|
+
warnings.push(...result.warnings);
|
|
2799
|
+
for (const entrypoint of fileEntrypoints) {
|
|
2800
|
+
for (const port of reservedRuntimePorts(entrypoint)) {
|
|
2801
|
+
const sidecar = result.sidecars.find((candidate) => candidate.port === port);
|
|
2802
|
+
if (sidecar !== void 0) {
|
|
2803
|
+
return yield* new ContainerConfigError({
|
|
2804
|
+
message: `Sidecar '${sidecar.name}' listens on port ${port}, which the ${entrypoint.runtime} runtime of '${entrypoint.path}' uses inside the same microVM. Choose another port.`,
|
|
2805
|
+
containerName: sidecar.name
|
|
2806
|
+
});
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
}
|
|
2810
|
+
return { ...result, warnings };
|
|
2811
|
+
});
|
|
2812
|
+
var V4ConfigParser = class extends Effect19.Service()("V4ConfigParser", {
|
|
1760
2813
|
accessors: true,
|
|
1761
|
-
effect:
|
|
2814
|
+
effect: Effect19.succeed({
|
|
1762
2815
|
/**
|
|
1763
2816
|
* Parses a ConfigV4 into a NormalizedConfig.
|
|
1764
2817
|
*
|
|
1765
2818
|
* @param config - The raw V4 config object
|
|
1766
2819
|
* @param projectFolder - Absolute path to the project root
|
|
1767
2820
|
*/
|
|
1768
|
-
parse:
|
|
1769
|
-
const entrypoints = yield* parseEntrypoints(config, projectFolder);
|
|
2821
|
+
parse: Effect19.fn("V4ConfigParser.parse")(function* (config, projectFolder) {
|
|
2822
|
+
const { entrypoints: fileEntrypoints, dockerFunctions } = yield* parseEntrypoints(config, projectFolder);
|
|
2823
|
+
const containers = yield* parseContainers(config, projectFolder, fileEntrypoints, dockerFunctions);
|
|
2824
|
+
const entrypoints = [...fileEntrypoints, ...containers.entrypoints];
|
|
1770
2825
|
const assets = yield* collectAssets(config, projectFolder);
|
|
2826
|
+
const dockerFunctionPaths = new Map(
|
|
2827
|
+
dockerFunctions.map(({ file, name }) => [file, containerEntrypointPath(name)])
|
|
2828
|
+
);
|
|
2829
|
+
const routes = (config.routes ?? []).map(
|
|
2830
|
+
(route) => mapRoute(
|
|
2831
|
+
{
|
|
2832
|
+
...route,
|
|
2833
|
+
destination: dockerFunctionPaths.get(normalizeRouteDestination(route.destination)) ?? route.destination
|
|
2834
|
+
},
|
|
2835
|
+
entrypoints
|
|
2836
|
+
)
|
|
2837
|
+
);
|
|
2838
|
+
const warnings = [...containers.warnings];
|
|
1771
2839
|
return {
|
|
1772
2840
|
regions: resolveRegions(config.regions),
|
|
1773
2841
|
assets: {
|
|
@@ -1780,10 +2848,11 @@ var V4ConfigParser = class extends Effect16.Service()("V4ConfigParser", {
|
|
|
1780
2848
|
commands: config.build_commands ?? [],
|
|
1781
2849
|
images: normalizeImagePolicy(config.images),
|
|
1782
2850
|
services: normalizeServices(config.services),
|
|
2851
|
+
...containers.sidecars.length > 0 && { sidecars: containers.sidecars },
|
|
1783
2852
|
entrypoints,
|
|
1784
2853
|
errors: [],
|
|
1785
|
-
warnings
|
|
1786
|
-
routes
|
|
2854
|
+
warnings,
|
|
2855
|
+
routes
|
|
1787
2856
|
};
|
|
1788
2857
|
})
|
|
1789
2858
|
})
|
|
@@ -1791,7 +2860,7 @@ var V4ConfigParser = class extends Effect16.Service()("V4ConfigParser", {
|
|
|
1791
2860
|
};
|
|
1792
2861
|
|
|
1793
2862
|
// src/services/vercel-build-output-parser.ts
|
|
1794
|
-
import { Path as
|
|
2863
|
+
import { Path as Path12 } from "@effect/platform";
|
|
1795
2864
|
|
|
1796
2865
|
// ../commons/src/deep-merge.ts
|
|
1797
2866
|
var deepMerge = (target, ...partials) => {
|
|
@@ -1820,7 +2889,7 @@ var deepMerge = (target, ...partials) => {
|
|
|
1820
2889
|
};
|
|
1821
2890
|
|
|
1822
2891
|
// src/services/vercel-build-output-parser.ts
|
|
1823
|
-
import { Effect as
|
|
2892
|
+
import { Effect as Effect20 } from "effect";
|
|
1824
2893
|
|
|
1825
2894
|
// src/build-output-v3/determine-repo-root.ts
|
|
1826
2895
|
import path from "path";
|
|
@@ -1916,11 +2985,11 @@ var translateVercelRuntime = (runtime) => {
|
|
|
1916
2985
|
var CONFIG_PATH = ".vercel/output/config.json";
|
|
1917
2986
|
var FUNCTIONS_FOLDER = ".vercel/output/functions";
|
|
1918
2987
|
var FUNCTION_CONFIGS_PATTERN = `${FUNCTIONS_FOLDER}/**/*.func/.vc-config.json`;
|
|
1919
|
-
var VercelBuildOutputParser = class extends
|
|
1920
|
-
effect:
|
|
2988
|
+
var VercelBuildOutputParser = class extends Effect20.Service()("VercelBuildOutputParser", {
|
|
2989
|
+
effect: Effect20.gen(function* () {
|
|
1921
2990
|
const rawConfigReader = yield* RawConfigReader;
|
|
1922
|
-
const pathService = yield*
|
|
1923
|
-
const parse =
|
|
2991
|
+
const pathService = yield* Path12.Path;
|
|
2992
|
+
const parse = Effect20.fn("VercelBuildOutputParser.parse")(function* (parseResult, projectFolder) {
|
|
1924
2993
|
const config = yield* rawConfigReader.readConfigFile(pathService.join(projectFolder, CONFIG_PATH));
|
|
1925
2994
|
if (!config || typeof config.version !== "number" || config.version < 3) {
|
|
1926
2995
|
return parseResult;
|
|
@@ -1932,8 +3001,8 @@ var VercelBuildOutputParser = class extends Effect17.Service()("VercelBuildOutpu
|
|
|
1932
3001
|
merged.regions = [...new Set(merged.regions)];
|
|
1933
3002
|
return merged;
|
|
1934
3003
|
});
|
|
1935
|
-
const loadFunctions =
|
|
1936
|
-
const functionConfigs = yield*
|
|
3004
|
+
const loadFunctions = Effect20.fn("VercelBuildOutputParser.loadFunctions")(function* (config, parseResult, projectFolder) {
|
|
3005
|
+
const functionConfigs = yield* Effect20.tryPromise({
|
|
1937
3006
|
try: () => getFilesForPattern(FUNCTION_CONFIGS_PATTERN, projectFolder),
|
|
1938
3007
|
catch: (error) => new ConfigFileParseError({
|
|
1939
3008
|
message: `Failed to scan for function configs: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -2219,17 +3288,22 @@ var schema_default = {
|
|
|
2219
3288
|
minimum: 1
|
|
2220
3289
|
},
|
|
2221
3290
|
runtime: {
|
|
2222
|
-
$ref: "#/$defs/runtimes",
|
|
2223
|
-
description: "The runtime to use for the function."
|
|
3291
|
+
anyOf: [{ $ref: "#/$defs/runtimes" }, { const: "docker" }],
|
|
3292
|
+
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."
|
|
3293
|
+
},
|
|
3294
|
+
port: {
|
|
3295
|
+
type: "integer",
|
|
3296
|
+
minimum: 1,
|
|
3297
|
+
maximum: 65535,
|
|
3298
|
+
description: "TCP port the image listens on. Only for `runtime: docker`. Defaults to the first exposed port of the image, then 8080."
|
|
2224
3299
|
},
|
|
2225
3300
|
streaming: {
|
|
2226
3301
|
type: "boolean",
|
|
2227
3302
|
description: "Enable function response streaming. When omitted, Node and Bun runtimes stream by default."
|
|
2228
3303
|
},
|
|
2229
3304
|
schedule: {
|
|
2230
|
-
|
|
2231
|
-
description: "An expression to schedule the function to run at specific times."
|
|
2232
|
-
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]+))?)*)[)])$"
|
|
3305
|
+
$ref: "#/$defs/schedule",
|
|
3306
|
+
description: "An expression to schedule the function to run at specific times."
|
|
2233
3307
|
},
|
|
2234
3308
|
symlinks: {
|
|
2235
3309
|
type: "object",
|
|
@@ -2321,6 +3395,151 @@ var schema_default = {
|
|
|
2321
3395
|
}
|
|
2322
3396
|
}
|
|
2323
3397
|
},
|
|
3398
|
+
compose: {
|
|
3399
|
+
type: ["string", "null"],
|
|
3400
|
+
minLength: 1,
|
|
3401
|
+
maxLength: 1024,
|
|
3402
|
+
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."
|
|
3403
|
+
},
|
|
3404
|
+
containers: {
|
|
3405
|
+
type: ["object", "null"],
|
|
3406
|
+
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>`.",
|
|
3407
|
+
maxProperties: 16,
|
|
3408
|
+
propertyNames: {
|
|
3409
|
+
pattern: "^[a-z][a-z0-9_-]{0,62}$",
|
|
3410
|
+
not: {
|
|
3411
|
+
enum: ["localhost"]
|
|
3412
|
+
}
|
|
3413
|
+
},
|
|
3414
|
+
additionalProperties: {
|
|
3415
|
+
type: "object",
|
|
3416
|
+
additionalProperties: false,
|
|
3417
|
+
oneOf: [
|
|
3418
|
+
{
|
|
3419
|
+
required: ["image"]
|
|
3420
|
+
},
|
|
3421
|
+
{
|
|
3422
|
+
required: ["build"]
|
|
3423
|
+
}
|
|
3424
|
+
],
|
|
3425
|
+
properties: {
|
|
3426
|
+
image: {
|
|
3427
|
+
type: "string",
|
|
3428
|
+
minLength: 1,
|
|
3429
|
+
maxLength: 512,
|
|
3430
|
+
pattern: "^[^\\s]+$",
|
|
3431
|
+
description: "Registry image reference, e.g. `redis:7-alpine` or `ghcr.io/acme/api:1.4`."
|
|
3432
|
+
},
|
|
3433
|
+
build: {
|
|
3434
|
+
description: "Build context directory, or the full build settings, for a Dockerfile in the repository.",
|
|
3435
|
+
oneOf: [
|
|
3436
|
+
{
|
|
3437
|
+
type: "string",
|
|
3438
|
+
minLength: 1,
|
|
3439
|
+
maxLength: 1024
|
|
3440
|
+
},
|
|
3441
|
+
{
|
|
3442
|
+
type: "object",
|
|
3443
|
+
additionalProperties: false,
|
|
3444
|
+
properties: {
|
|
3445
|
+
context: {
|
|
3446
|
+
type: "string",
|
|
3447
|
+
minLength: 1,
|
|
3448
|
+
maxLength: 1024
|
|
3449
|
+
},
|
|
3450
|
+
dockerfile: {
|
|
3451
|
+
type: "string",
|
|
3452
|
+
minLength: 1,
|
|
3453
|
+
maxLength: 1024
|
|
3454
|
+
},
|
|
3455
|
+
target: {
|
|
3456
|
+
type: "string",
|
|
3457
|
+
minLength: 1,
|
|
3458
|
+
maxLength: 128
|
|
3459
|
+
},
|
|
3460
|
+
args: {
|
|
3461
|
+
type: "object",
|
|
3462
|
+
maxProperties: 100,
|
|
3463
|
+
additionalProperties: {
|
|
3464
|
+
type: "string",
|
|
3465
|
+
maxLength: 65536
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
3470
|
+
]
|
|
3471
|
+
},
|
|
3472
|
+
sidecar: {
|
|
3473
|
+
type: "boolean",
|
|
3474
|
+
description: "Run next to every function instance instead of serving routes. Defaults to false."
|
|
3475
|
+
},
|
|
3476
|
+
port: {
|
|
3477
|
+
type: "integer",
|
|
3478
|
+
minimum: 1,
|
|
3479
|
+
maximum: 65535,
|
|
3480
|
+
description: "TCP port the container listens on. Defaults to the first exposed port of the image, then 8080."
|
|
3481
|
+
},
|
|
3482
|
+
entrypoint: {
|
|
3483
|
+
$ref: "#/$defs/stringOrStringArray",
|
|
3484
|
+
description: "Replaces the image ENTRYPOINT. A string is split into words the way Compose splits it."
|
|
3485
|
+
},
|
|
3486
|
+
command: {
|
|
3487
|
+
$ref: "#/$defs/stringOrStringArray",
|
|
3488
|
+
description: "Replaces the image CMD. A string is split into words the way Compose splits it."
|
|
3489
|
+
},
|
|
3490
|
+
env: {
|
|
3491
|
+
type: "object",
|
|
3492
|
+
maxProperties: 100,
|
|
3493
|
+
additionalProperties: {
|
|
3494
|
+
type: "string",
|
|
3495
|
+
maxLength: 65536
|
|
3496
|
+
},
|
|
3497
|
+
description: "Environment variables baked into the container, merged over the image ENV."
|
|
3498
|
+
},
|
|
3499
|
+
working_dir: {
|
|
3500
|
+
type: "string",
|
|
3501
|
+
minLength: 1,
|
|
3502
|
+
maxLength: 1024,
|
|
3503
|
+
pattern: "^/",
|
|
3504
|
+
description: "Replaces the image WORKDIR. Must be absolute."
|
|
3505
|
+
},
|
|
3506
|
+
user: {
|
|
3507
|
+
oneOf: [
|
|
3508
|
+
{
|
|
3509
|
+
type: "string",
|
|
3510
|
+
minLength: 1,
|
|
3511
|
+
maxLength: 256
|
|
3512
|
+
},
|
|
3513
|
+
{
|
|
3514
|
+
type: "integer",
|
|
3515
|
+
minimum: 0
|
|
3516
|
+
}
|
|
3517
|
+
],
|
|
3518
|
+
description: "Replaces the image USER: a name, a uid, `name:group` or `uid:gid`. A bare uid may be a number."
|
|
3519
|
+
},
|
|
3520
|
+
memory: {
|
|
3521
|
+
type: "integer",
|
|
3522
|
+
minimum: 128,
|
|
3523
|
+
maximum: 3009,
|
|
3524
|
+
description: "Memory in MB. Defaults to 512 for a container function and 256 for a sidecar."
|
|
3525
|
+
},
|
|
3526
|
+
max_duration: {
|
|
3527
|
+
type: "number",
|
|
3528
|
+
minimum: 1,
|
|
3529
|
+
maximum: 28800,
|
|
3530
|
+
description: "Maximum lifetime in seconds of one request. Container functions only."
|
|
3531
|
+
},
|
|
3532
|
+
streaming: {
|
|
3533
|
+
type: "boolean",
|
|
3534
|
+
description: "Stream responses. Defaults to true. Container functions only."
|
|
3535
|
+
},
|
|
3536
|
+
schedule: {
|
|
3537
|
+
$ref: "#/$defs/schedule",
|
|
3538
|
+
description: "An expression to run the container function at specific times. Container functions only."
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
}
|
|
3542
|
+
},
|
|
2324
3543
|
services: {
|
|
2325
3544
|
type: "object",
|
|
2326
3545
|
description: "Managed services to provision for the deployment environment.",
|
|
@@ -2471,11 +3690,179 @@ var schema_default = {
|
|
|
2471
3690
|
}
|
|
2472
3691
|
}
|
|
2473
3692
|
}
|
|
3693
|
+
},
|
|
3694
|
+
queues: {
|
|
3695
|
+
type: "object",
|
|
3696
|
+
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.",
|
|
3697
|
+
propertyNames: {
|
|
3698
|
+
maxLength: 255,
|
|
3699
|
+
pattern: "^[A-Za-z0-9_][A-Za-z0-9_.~:@+=-]*$"
|
|
3700
|
+
},
|
|
3701
|
+
additionalProperties: {
|
|
3702
|
+
oneOf: [
|
|
3703
|
+
{
|
|
3704
|
+
type: "null"
|
|
3705
|
+
},
|
|
3706
|
+
{
|
|
3707
|
+
type: "object",
|
|
3708
|
+
additionalProperties: false,
|
|
3709
|
+
properties: {
|
|
3710
|
+
consumer: {
|
|
3711
|
+
type: ["string", "null"],
|
|
3712
|
+
pattern: "^/(?!/)\\S*$",
|
|
3713
|
+
maxLength: 2048,
|
|
3714
|
+
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."
|
|
3715
|
+
},
|
|
3716
|
+
visibilityTimeout: {
|
|
3717
|
+
$ref: "#/$defs/queueDuration",
|
|
3718
|
+
description: "How long a push delivery may run, or how long a received message stays leased. Defaults to 60 seconds, at most 12 hours."
|
|
3719
|
+
},
|
|
3720
|
+
retention: {
|
|
3721
|
+
$ref: "#/$defs/queueDuration",
|
|
3722
|
+
description: "How long an undelivered message is kept. Defaults to 4 days, at most 14 days."
|
|
3723
|
+
},
|
|
3724
|
+
maxAttempts: {
|
|
3725
|
+
type: "integer",
|
|
3726
|
+
minimum: 1,
|
|
3727
|
+
maximum: 100,
|
|
3728
|
+
description: "Deliveries per message before it moves to the dead-letter list. Defaults to 10."
|
|
3729
|
+
},
|
|
3730
|
+
retryBackoff: {
|
|
3731
|
+
type: "object",
|
|
3732
|
+
additionalProperties: false,
|
|
3733
|
+
description: "Exponential backoff between failed deliveries. Defaults to 5 seconds, doubling up to 15 minutes.",
|
|
3734
|
+
properties: {
|
|
3735
|
+
min: {
|
|
3736
|
+
$ref: "#/$defs/queueDuration"
|
|
3737
|
+
},
|
|
3738
|
+
max: {
|
|
3739
|
+
$ref: "#/$defs/queueDuration"
|
|
3740
|
+
}
|
|
3741
|
+
}
|
|
3742
|
+
},
|
|
3743
|
+
deduplicationWindow: {
|
|
3744
|
+
$ref: "#/$defs/queueDuration",
|
|
3745
|
+
description: "How long a deduplication key is remembered. Defaults to 24 hours, at most 7 days."
|
|
3746
|
+
},
|
|
3747
|
+
concurrency: {
|
|
3748
|
+
type: ["integer", "null"],
|
|
3749
|
+
minimum: 1,
|
|
3750
|
+
maximum: 1e3,
|
|
3751
|
+
description: "Most push deliveries in flight at once. Defaults to 100."
|
|
3752
|
+
},
|
|
3753
|
+
rateLimit: {
|
|
3754
|
+
oneOf: [
|
|
3755
|
+
{
|
|
3756
|
+
type: "null"
|
|
3757
|
+
},
|
|
3758
|
+
{
|
|
3759
|
+
type: "object",
|
|
3760
|
+
required: ["count"],
|
|
3761
|
+
additionalProperties: false,
|
|
3762
|
+
properties: {
|
|
3763
|
+
count: {
|
|
3764
|
+
type: "integer",
|
|
3765
|
+
minimum: 1,
|
|
3766
|
+
maximum: 1e6
|
|
3767
|
+
},
|
|
3768
|
+
period: {
|
|
3769
|
+
$ref: "#/$defs/queueDuration"
|
|
3770
|
+
}
|
|
3771
|
+
}
|
|
3772
|
+
}
|
|
3773
|
+
],
|
|
3774
|
+
description: "Most deliveries started per period. The period defaults to one second."
|
|
3775
|
+
},
|
|
3776
|
+
deadLetter: {
|
|
3777
|
+
type: "boolean",
|
|
3778
|
+
description: "Keep messages that run out of attempts so you can inspect and redrive them. Defaults to true."
|
|
3779
|
+
},
|
|
3780
|
+
schedules: {
|
|
3781
|
+
type: "object",
|
|
3782
|
+
description: "Cron schedules that send a message into this queue, keyed by schedule name.",
|
|
3783
|
+
propertyNames: {
|
|
3784
|
+
maxLength: 128,
|
|
3785
|
+
pattern: "^[A-Za-z0-9_][A-Za-z0-9_.-]*$"
|
|
3786
|
+
},
|
|
3787
|
+
additionalProperties: {
|
|
3788
|
+
type: "object",
|
|
3789
|
+
required: ["cron"],
|
|
3790
|
+
additionalProperties: false,
|
|
3791
|
+
properties: {
|
|
3792
|
+
cron: {
|
|
3793
|
+
type: "string",
|
|
3794
|
+
minLength: 1,
|
|
3795
|
+
maxLength: 255,
|
|
3796
|
+
description: "Five-field cron expression, or a macro such as @hourly or @daily."
|
|
3797
|
+
},
|
|
3798
|
+
timezone: {
|
|
3799
|
+
type: "string",
|
|
3800
|
+
description: "IANA time zone the expression is evaluated in. Defaults to UTC."
|
|
3801
|
+
},
|
|
3802
|
+
body: {
|
|
3803
|
+
description: "Message body. Strings are sent as is; any other value is sent as JSON."
|
|
3804
|
+
},
|
|
3805
|
+
contentType: {
|
|
3806
|
+
type: "string",
|
|
3807
|
+
description: "Content type of the body. Defaults to text/plain for a string body and application/json otherwise."
|
|
3808
|
+
},
|
|
3809
|
+
headers: {
|
|
3810
|
+
type: "object",
|
|
3811
|
+
additionalProperties: {
|
|
3812
|
+
type: "string"
|
|
3813
|
+
},
|
|
3814
|
+
description: "Headers delivered with every message from this schedule."
|
|
3815
|
+
},
|
|
3816
|
+
enabled: {
|
|
3817
|
+
type: "boolean",
|
|
3818
|
+
description: "Set to false to keep the schedule without sending. Defaults to true."
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
}
|
|
3822
|
+
}
|
|
3823
|
+
}
|
|
3824
|
+
}
|
|
3825
|
+
]
|
|
3826
|
+
}
|
|
2474
3827
|
}
|
|
2475
3828
|
}
|
|
2476
3829
|
}
|
|
2477
3830
|
},
|
|
2478
3831
|
$defs: {
|
|
3832
|
+
schedule: {
|
|
3833
|
+
type: "string",
|
|
3834
|
+
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]+))?)*)[)])$"
|
|
3835
|
+
},
|
|
3836
|
+
stringOrStringArray: {
|
|
3837
|
+
oneOf: [
|
|
3838
|
+
{
|
|
3839
|
+
type: "string",
|
|
3840
|
+
minLength: 1,
|
|
3841
|
+
maxLength: 4096
|
|
3842
|
+
},
|
|
3843
|
+
{
|
|
3844
|
+
type: "array",
|
|
3845
|
+
maxItems: 256,
|
|
3846
|
+
items: {
|
|
3847
|
+
type: "string",
|
|
3848
|
+
maxLength: 4096
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
]
|
|
3852
|
+
},
|
|
3853
|
+
queueDuration: {
|
|
3854
|
+
oneOf: [
|
|
3855
|
+
{
|
|
3856
|
+
type: "integer",
|
|
3857
|
+
minimum: 0
|
|
3858
|
+
},
|
|
3859
|
+
{
|
|
3860
|
+
type: "string",
|
|
3861
|
+
pattern: "^[0-9]+(\\.[0-9]+)?(s|m|h|d)$"
|
|
3862
|
+
}
|
|
3863
|
+
],
|
|
3864
|
+
description: "A duration in seconds, or a string such as 30s, 10m, 1.5h or 4d."
|
|
3865
|
+
},
|
|
2479
3866
|
runtimes: {
|
|
2480
3867
|
type: "string",
|
|
2481
3868
|
enum: ["php-84", "php-83", "php-81", "node-22", "node-20", "node-18", "node-16", "bun-1"]
|
|
@@ -2532,7 +3919,7 @@ var schema_default = {
|
|
|
2532
3919
|
};
|
|
2533
3920
|
|
|
2534
3921
|
// src/parse-config.ts
|
|
2535
|
-
var parseConfigRaw =
|
|
3922
|
+
var parseConfigRaw = Effect21.fn("parseConfigRaw")(function* (filePath, projectFolder) {
|
|
2536
3923
|
const rawReader = yield* RawConfigReader;
|
|
2537
3924
|
const validator = yield* SchemaValidator;
|
|
2538
3925
|
const v4Parser = yield* V4ConfigParser;
|
|
@@ -2543,7 +3930,7 @@ var parseConfigRaw = Effect18.fn("parseConfigRaw")(function* (filePath, projectF
|
|
|
2543
3930
|
};
|
|
2544
3931
|
const schema = schemaMap[version];
|
|
2545
3932
|
if (!schema) {
|
|
2546
|
-
return yield*
|
|
3933
|
+
return yield* Effect21.fail(
|
|
2547
3934
|
new ConfigVersionError({
|
|
2548
3935
|
message: `Config file at ${filePath} has an unsupported version: ${version}`,
|
|
2549
3936
|
filePath,
|
|
@@ -2554,14 +3941,42 @@ var parseConfigRaw = Effect18.fn("parseConfigRaw")(function* (filePath, projectF
|
|
|
2554
3941
|
yield* validator.validate(parsed, schema, filePath);
|
|
2555
3942
|
return yield* v4Parser.parse(parsed, projectFolder);
|
|
2556
3943
|
});
|
|
2557
|
-
var parseConfig =
|
|
3944
|
+
var parseConfig = Effect21.fn("parseConfig")(function* (filePath, projectFolder) {
|
|
2558
3945
|
const parseResult = yield* parseConfigRaw(filePath, projectFolder);
|
|
2559
3946
|
return yield* postProcessConfig(parseResult, projectFolder);
|
|
2560
3947
|
});
|
|
2561
|
-
var postProcessConfig =
|
|
3948
|
+
var postProcessConfig = Effect21.fn("postProcessConfig")(function* (config, projectFolder) {
|
|
2562
3949
|
const vercelParser = yield* VercelBuildOutputParser;
|
|
2563
3950
|
let result = yield* vercelParser.parse(config, projectFolder);
|
|
2564
3951
|
const hasAssets = (result.assets?.paths?.length ?? 0) > 0 || (result.assets?.prefixes?.length ?? 0) > 0 || (result.assets?.manifests?.length ?? 0) > 0;
|
|
3952
|
+
const containerFunctions = result.entrypoints.filter((entrypoint) => entrypoint.runtime === CONTAINER_RUNTIME);
|
|
3953
|
+
const [onlyFunction] = result.entrypoints;
|
|
3954
|
+
if (onlyFunction !== void 0 && onlyFunction.runtime === CONTAINER_RUNTIME && result.entrypoints.length === 1 && result.routes.length === 0 && !hasAssets) {
|
|
3955
|
+
result = {
|
|
3956
|
+
...result,
|
|
3957
|
+
routes: [
|
|
3958
|
+
{
|
|
3959
|
+
path: "/*",
|
|
3960
|
+
destination: onlyFunction.path,
|
|
3961
|
+
handler: onlyFunction.streaming === true ? "SERVERLESS_FUNCTION_STREAMING" : "SERVERLESS_FUNCTION",
|
|
3962
|
+
methods: ["ANY"],
|
|
3963
|
+
headers: {}
|
|
3964
|
+
}
|
|
3965
|
+
]
|
|
3966
|
+
};
|
|
3967
|
+
} else {
|
|
3968
|
+
for (const entrypoint of containerFunctions) {
|
|
3969
|
+
const routed = result.routes.some((route) => route.destination.replace(/^\/+/, "") === entrypoint.path);
|
|
3970
|
+
if (!routed && entrypoint.schedule === void 0) {
|
|
3971
|
+
result.warnings.push(
|
|
3972
|
+
`Container function '${entrypoint.displayName ?? entrypoint.path}' has no route and no schedule, so nothing reaches it. Add a route with destination '${entrypoint.path}'.`
|
|
3973
|
+
);
|
|
3974
|
+
}
|
|
3975
|
+
}
|
|
3976
|
+
}
|
|
3977
|
+
if ((result.sidecars?.length ?? 0) > 0 && result.entrypoints.length === 0) {
|
|
3978
|
+
result.warnings.push("Sidecars run next to functions, and this deployment has none, so no sidecar will start.");
|
|
3979
|
+
}
|
|
2565
3980
|
if (result.entrypoints.length === 0 && !hasAssets && result.routes.length === 0) {
|
|
2566
3981
|
result.errors.push(
|
|
2567
3982
|
"The current project config does not resolve to any functions, assets or routes and can not be deployed."
|
|
@@ -2599,6 +4014,9 @@ export {
|
|
|
2599
4014
|
ALLOWED_CONFIG_NAMES,
|
|
2600
4015
|
AVAILABLE_REGIONS,
|
|
2601
4016
|
AVAILABLE_RUNTIMES,
|
|
4017
|
+
COMPOSE_FILE_NAMES,
|
|
4018
|
+
CONTAINER_ENTRYPOINT_PREFIX,
|
|
4019
|
+
CONTAINER_RUNTIME,
|
|
2602
4020
|
ConfigFileEmptyError,
|
|
2603
4021
|
ConfigFileNotFoundError,
|
|
2604
4022
|
ConfigFileParseError,
|
|
@@ -2606,7 +4024,10 @@ export {
|
|
|
2606
4024
|
ConfigModuleLoader,
|
|
2607
4025
|
ConfigSchemaValidationError,
|
|
2608
4026
|
ConfigVersionError,
|
|
4027
|
+
ContainerConfigError,
|
|
4028
|
+
DEFAULT_CONTAINER_MEMORY_MB,
|
|
2609
4029
|
DEFAULT_FUNCTION_DURATION_SECONDS,
|
|
4030
|
+
DEFAULT_SIDECAR_MEMORY_MB,
|
|
2610
4031
|
FRAMEWORK_DEFINITIONS,
|
|
2611
4032
|
FrameworkNotDetectedError,
|
|
2612
4033
|
FunctionConfigError,
|
|
@@ -2623,6 +4044,7 @@ export {
|
|
|
2623
4044
|
GigadriveNextServerDescriptorSchema,
|
|
2624
4045
|
GigadriveNextStaticAssetPrefixSchema,
|
|
2625
4046
|
MAX_FUNCTION_DURATION_SECONDS,
|
|
4047
|
+
MAX_SIDECARS,
|
|
2626
4048
|
ManifestNotFoundError,
|
|
2627
4049
|
ManifestParseError,
|
|
2628
4050
|
ManifestReadError,
|
|
@@ -2635,19 +4057,26 @@ export {
|
|
|
2635
4057
|
V4ConfigParser,
|
|
2636
4058
|
VercelBuildOutputParser,
|
|
2637
4059
|
collectAssetFiles,
|
|
4060
|
+
composeDeclaresApp,
|
|
4061
|
+
containerEntrypointPath,
|
|
2638
4062
|
defineConfig,
|
|
4063
|
+
detectContainerProject,
|
|
2639
4064
|
detectFramework,
|
|
2640
4065
|
detectPackageManager,
|
|
4066
|
+
dockerFunctionContainerName,
|
|
2641
4067
|
filterFunctionsFromAssets,
|
|
2642
4068
|
generateConfig,
|
|
2643
4069
|
getFunctionSettings,
|
|
2644
4070
|
mergeWithFrameworkDefaults,
|
|
4071
|
+
normalizeContainers,
|
|
2645
4072
|
parseConfig,
|
|
2646
4073
|
parseConfigRaw,
|
|
2647
4074
|
parseGigadriveNextBuildManifest,
|
|
2648
4075
|
parseGigadriveNextPrerenderManifest,
|
|
2649
4076
|
parseStaticAssetManifest,
|
|
2650
4077
|
postProcessConfig,
|
|
2651
|
-
|
|
4078
|
+
readComposeContainers,
|
|
4079
|
+
readDependencies,
|
|
4080
|
+
splitCommandWords
|
|
2652
4081
|
};
|
|
2653
4082
|
//# sourceMappingURL=index.mjs.map
|