@gigadrive/network-config 5.3.1 → 5.5.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/index.mjs CHANGED
@@ -905,8 +905,8 @@ var detectContainerProject = Effect3.fn("detectContainerProject")(function* (pro
905
905
  });
906
906
 
907
907
  // src/detection/detect-framework.ts
908
- import { FileSystem as FileSystem12, Path as Path10 } from "@effect/platform";
909
- import { Effect as Effect14 } from "effect";
908
+ import { FileSystem as FileSystem16, Path as Path14 } from "@effect/platform";
909
+ import { Effect as Effect20 } from "effect";
910
910
 
911
911
  // src/detection/detect-package-manager.ts
912
912
  import { FileSystem as FileSystem4, Path as Path4 } from "@effect/platform";
@@ -916,7 +916,10 @@ var LOCKFILE_MAP = [
916
916
  { files: ["pnpm-lock.yaml"], pm: "pnpm" },
917
917
  { files: ["yarn.lock"], pm: "yarn" },
918
918
  { files: ["package-lock.json"], pm: "npm" },
919
- { files: ["composer.lock"], pm: "composer" }
919
+ { files: ["composer.lock"], pm: "composer" },
920
+ // A Gemfile is checked last and counts even without its lockfile: Bundler
921
+ // resolves and writes Gemfile.lock on the first install.
922
+ { files: ["Gemfile.lock", "Gemfile"], pm: "bundler" }
920
923
  ];
921
924
  var detectPackageManager = Effect4.fn("detectPackageManager")(function* (projectFolder) {
922
925
  const fs = yield* FileSystem4.FileSystem;
@@ -955,6 +958,192 @@ var astro = {
955
958
  })
956
959
  };
957
960
 
961
+ // src/detection/frameworks/ruby-runtime.ts
962
+ import { FileSystem as FileSystem5, Path as Path5 } from "@effect/platform";
963
+ import { Effect as Effect5 } from "effect";
964
+
965
+ // src/detection/frameworks/ruby-requirement.ts
966
+ var RUBY_VERSION = /^(?:ruby-)?(\d+(?:\.\d+)*)(?:p\d+)?(?:[-.]?(?:preview|rc|dev|alpha|beta|pre)\d*)?$/i;
967
+ var REQUIREMENT_ATOM = /^(~>|>=|<=|!=|=|>|<)?\s*(\S+)$/;
968
+ var parseRubyVersion = (text) => {
969
+ const match = RUBY_VERSION.exec(text);
970
+ return match ? match[1].split(".").map(Number) : void 0;
971
+ };
972
+ var compareRubyVersions = (a, b) => {
973
+ for (let index = 0; index < Math.max(a.length, b.length); index++) {
974
+ const difference = (a[index] ?? 0) - (b[index] ?? 0);
975
+ if (difference !== 0) {
976
+ return difference;
977
+ }
978
+ }
979
+ return 0;
980
+ };
981
+ var pessimisticUpperBound = (segments) => {
982
+ const kept = segments.length > 1 ? segments.slice(0, -1) : [...segments];
983
+ kept[kept.length - 1] += 1;
984
+ return kept;
985
+ };
986
+ var parseRubyRequirement = (requirement) => {
987
+ const parts = requirement.split(",").map((part) => part.trim());
988
+ const atoms = [];
989
+ for (const part of parts) {
990
+ const match = REQUIREMENT_ATOM.exec(part);
991
+ const segments = match ? parseRubyVersion(match[2]) : void 0;
992
+ if (!match || !segments) {
993
+ return void 0;
994
+ }
995
+ atoms.push({ operator: match[1] ?? "=", segments });
996
+ }
997
+ return atoms;
998
+ };
999
+ var atomAllows = ({ operator, segments }, version) => {
1000
+ const comparison = compareRubyVersions(version, segments);
1001
+ switch (operator) {
1002
+ case "=":
1003
+ return comparison === 0;
1004
+ case "!=":
1005
+ return comparison !== 0;
1006
+ case ">":
1007
+ return comparison > 0;
1008
+ case "<":
1009
+ return comparison < 0;
1010
+ case ">=":
1011
+ return comparison >= 0;
1012
+ case "<=":
1013
+ return comparison <= 0;
1014
+ case "~>":
1015
+ return comparison >= 0 && compareRubyVersions(version, pessimisticUpperBound(segments)) < 0;
1016
+ }
1017
+ };
1018
+ var rubyRequirementAllows = (requirement, version) => {
1019
+ const atoms = parseRubyRequirement(requirement);
1020
+ const segments = parseRubyVersion(version);
1021
+ if (!atoms || !segments) {
1022
+ return void 0;
1023
+ }
1024
+ return atoms.every((atom) => atomAllows(atom, segments));
1025
+ };
1026
+
1027
+ // src/detection/frameworks/ruby-runtime.ts
1028
+ var DEFAULT_RUBY_RUNTIME = "ruby-34";
1029
+ var RUBY_RUNTIME_CANDIDATES = [
1030
+ { runtime: "ruby-40", series: [4, 0], newestVersion: "4.0.9999" },
1031
+ { runtime: "ruby-34", series: [3, 4], newestVersion: "3.4.9999" },
1032
+ { runtime: "ruby-33", series: [3, 3], newestVersion: "3.3.9999" }
1033
+ ];
1034
+ var rubyRuntimeForVersion = (version) => {
1035
+ const segments = parseRubyVersion(version);
1036
+ if (!segments) {
1037
+ return void 0;
1038
+ }
1039
+ const series = [segments[0], segments[1] ?? 0];
1040
+ const candidate = RUBY_RUNTIME_CANDIDATES.find((candidate2) => compareRubyVersions(candidate2.series, series) <= 0);
1041
+ return (candidate ?? RUBY_RUNTIME_CANDIDATES[RUBY_RUNTIME_CANDIDATES.length - 1]).runtime;
1042
+ };
1043
+ var rubyRuntimeForRequirement = (requirement) => {
1044
+ const atoms = parseRubyRequirement(requirement);
1045
+ if (!atoms) {
1046
+ return void 0;
1047
+ }
1048
+ if (atoms.length === 1 && atoms[0].operator === "=") {
1049
+ return rubyRuntimeForVersion(atoms[0].segments.join("."));
1050
+ }
1051
+ return RUBY_RUNTIME_CANDIDATES.find(({ newestVersion }) => rubyRequirementAllows(requirement, newestVersion) === true)?.runtime;
1052
+ };
1053
+ var versionFromRubyVersionFile = (content) => content.split(/\r?\n/).map((line) => line.trim()).find((line) => line !== "" && !line.startsWith("#"))?.split(/\s/)[0]?.split("@")[0];
1054
+ var versionFromToolVersionsFile = (content) => /^\s*ruby\s+(\S+)/m.exec(content)?.[1];
1055
+ var versionFromGemfileLock = (content) => /^RUBY VERSION\r?\n\s+ruby\s+(\S+)/m.exec(content)?.[1];
1056
+ var GEMFILE_RUBY_DIRECTIVE = /^\s*ruby[\s(]+(.+)$/m;
1057
+ var GEMFILE_RUBY_FILE = /^(?:file:|:file\s*=>|File\.read\s*\(?)\s*(['"])([^'"]+)\1/;
1058
+ var LEADING_STRINGS = /^\s*(['"])([^'"]*)\1\s*(?:,|\)|#|$)/;
1059
+ var RUBY_VERSION_FILES = [".ruby-version", ".tool-versions", "Gemfile", "Gemfile.lock"];
1060
+ var gemfileRubyDirective = (gemfile) => GEMFILE_RUBY_DIRECTIVE.exec(gemfile)?.[1]?.trim();
1061
+ var gemfileRubyVersionFile = (gemfile) => {
1062
+ const directive = gemfileRubyDirective(gemfile);
1063
+ return directive === void 0 ? void 0 : GEMFILE_RUBY_FILE.exec(directive)?.[2];
1064
+ };
1065
+ var runtimeFromVersionFile = (file, content) => {
1066
+ if (content === void 0) {
1067
+ return void 0;
1068
+ }
1069
+ const parse = file.split("/").at(-1) === ".tool-versions" ? versionFromToolVersionsFile : versionFromRubyVersionFile;
1070
+ const version = parse(content);
1071
+ return version === void 0 ? void 0 : rubyRuntimeForVersion(version);
1072
+ };
1073
+ var runtimeFromGemfile = (gemfile, readFile) => {
1074
+ const directive = gemfile === void 0 ? void 0 : gemfileRubyDirective(gemfile);
1075
+ if (directive === void 0) {
1076
+ return void 0;
1077
+ }
1078
+ const versionFile = GEMFILE_RUBY_FILE.exec(directive)?.[2];
1079
+ if (versionFile !== void 0) {
1080
+ return runtimeFromVersionFile(versionFile, readFile(versionFile));
1081
+ }
1082
+ const requirements = [];
1083
+ let rest = directive;
1084
+ for (let match = LEADING_STRINGS.exec(rest); match; match = LEADING_STRINGS.exec(rest)) {
1085
+ requirements.push(match[2]);
1086
+ rest = rest.slice(match[0].length);
1087
+ }
1088
+ return requirements.length === 0 ? void 0 : rubyRuntimeForRequirement(requirements.join(","));
1089
+ };
1090
+ var runtimeFromGemfileLock = (lockfile) => {
1091
+ const version = lockfile === void 0 ? void 0 : versionFromGemfileLock(lockfile);
1092
+ return version === void 0 ? void 0 : rubyRuntimeForVersion(version);
1093
+ };
1094
+ var rubyRuntimeFromProjectFiles = (readFile) => runtimeFromVersionFile(".ruby-version", readFile(".ruby-version")) ?? runtimeFromVersionFile(".tool-versions", readFile(".tool-versions")) ?? runtimeFromGemfile(readFile("Gemfile"), readFile) ?? runtimeFromGemfileLock(readFile("Gemfile.lock"));
1095
+ var readProjectFile = Effect5.fn("readProjectFile")(
1096
+ function* (projectFolder, file) {
1097
+ const fs = yield* FileSystem5.FileSystem;
1098
+ const pathService = yield* Path5.Path;
1099
+ return yield* fs.readFileString(pathService.join(projectFolder, file));
1100
+ },
1101
+ Effect5.catchAll(() => Effect5.succeed(void 0))
1102
+ );
1103
+ var detectRubyRuntime = Effect5.fn("detectRubyRuntime")(function* (projectFolder) {
1104
+ const files = /* @__PURE__ */ new Map();
1105
+ for (const file of RUBY_VERSION_FILES) {
1106
+ files.set(file, yield* readProjectFile(projectFolder, file));
1107
+ }
1108
+ const gemfile = files.get("Gemfile");
1109
+ const versionFile = gemfile === void 0 ? void 0 : gemfileRubyVersionFile(gemfile);
1110
+ if (versionFile !== void 0 && !files.has(versionFile)) {
1111
+ files.set(versionFile, yield* readProjectFile(projectFolder, versionFile));
1112
+ }
1113
+ return rubyRuntimeFromProjectFiles((file) => files.get(file));
1114
+ });
1115
+ var refineRubyRuntime = Effect5.fn("refineRubyRuntime")(function* (defaults, projectFolder) {
1116
+ const runtime = yield* detectRubyRuntime(projectFolder);
1117
+ return runtime ? { ...defaults, runtime } : defaults;
1118
+ });
1119
+ var withRubyRuntime = (framework) => ({
1120
+ ...framework,
1121
+ refineDefaultConfig: (defaults, projectFolder) => Effect5.gen(function* () {
1122
+ const refined = framework.refineDefaultConfig ? yield* framework.refineDefaultConfig(defaults, projectFolder) : defaults;
1123
+ return yield* refineRubyRuntime(refined, projectFolder);
1124
+ })
1125
+ });
1126
+
1127
+ // src/detection/frameworks/bridgetown.ts
1128
+ var bridgetown = {
1129
+ slug: "bridgetown",
1130
+ name: "Bridgetown",
1131
+ language: "ruby",
1132
+ detectors: [{ matchPackage: "bridgetown" }],
1133
+ priority: 70,
1134
+ getDefaultConfig: () => ({
1135
+ runtime: DEFAULT_RUBY_RUNTIME,
1136
+ memory: 128,
1137
+ maxDuration: 30,
1138
+ streaming: false,
1139
+ commands: ["bin/bridgetown deploy"],
1140
+ assetsDir: "output",
1141
+ populateAssetCache: true,
1142
+ routes: [],
1143
+ environmentVariables: { BRIDGETOWN_ENV: "production" }
1144
+ })
1145
+ };
1146
+
958
1147
  // src/detection/generated-secret.ts
959
1148
  var generatedSecret = (format) => `{{gigadrive.secret:${format}}}`;
960
1149
 
@@ -1029,8 +1218,8 @@ var codeigniter = {
1029
1218
  };
1030
1219
 
1031
1220
  // src/detection/frameworks/resolve-node-entrypoint.ts
1032
- import { FileSystem as FileSystem5, Path as Path5 } from "@effect/platform";
1033
- import { Effect as Effect5 } from "effect";
1221
+ import { FileSystem as FileSystem6, Path as Path6 } from "@effect/platform";
1222
+ import { Effect as Effect6 } from "effect";
1034
1223
  var SCRIPT_RUNNERS = /* @__PURE__ */ new Set(["node", "bun", "tsx", "ts-node"]);
1035
1224
  var COMMON_ENTRYPOINT_CANDIDATES = [
1036
1225
  "index.js",
@@ -1078,14 +1267,14 @@ var applyEntrypoint = (defaults, entrypoint) => ({
1078
1267
  (route) => route.destination === defaults.entrypoint ? { ...route, destination: entrypoint } : route
1079
1268
  )
1080
1269
  });
1081
- var resolveNodeServerEntrypoint = (defaults, projectFolder) => Effect5.gen(function* () {
1082
- const fs = yield* FileSystem5.FileSystem;
1083
- const pathService = yield* Path5.Path;
1270
+ var resolveNodeServerEntrypoint = (defaults, projectFolder) => Effect6.gen(function* () {
1271
+ const fs = yield* FileSystem6.FileSystem;
1272
+ const pathService = yield* Path6.Path;
1084
1273
  const isFile = (relativePath) => fs.stat(pathService.join(projectFolder, relativePath)).pipe(
1085
- Effect5.map((info) => info.type === "File"),
1086
- Effect5.catchAll(() => Effect5.succeed(false))
1274
+ Effect6.map((info) => info.type === "File"),
1275
+ Effect6.catchAll(() => Effect6.succeed(false))
1087
1276
  );
1088
- const content = yield* fs.readFileString(pathService.join(projectFolder, "package.json")).pipe(Effect5.catchAll(() => Effect5.succeed(void 0)));
1277
+ const content = yield* fs.readFileString(pathService.join(projectFolder, "package.json")).pipe(Effect6.catchAll(() => Effect6.succeed(void 0)));
1089
1278
  const manifest = content ? parsePackageJson(content) : void 0;
1090
1279
  const startScript = typeof manifest?.scripts?.start === "string" ? manifest.scripts.start : void 0;
1091
1280
  const candidates = [
@@ -1165,6 +1354,189 @@ var fastify = {
1165
1354
  refineDefaultConfig: resolveNodeServerEntrypoint
1166
1355
  };
1167
1356
 
1357
+ // src/detection/frameworks/hanami.ts
1358
+ import { Effect as Effect10 } from "effect";
1359
+
1360
+ // src/detection/read-dependencies.ts
1361
+ import { FileSystem as FileSystem7, Path as Path7 } from "@effect/platform";
1362
+ import { Effect as Effect8 } from "effect";
1363
+
1364
+ // src/detection/types.ts
1365
+ import { Schema as Schema4 } from "effect";
1366
+ var ManifestNotFoundError = class extends Schema4.TaggedError()("ManifestNotFoundError", {
1367
+ message: Schema4.String,
1368
+ filePath: Schema4.String
1369
+ }) {
1370
+ };
1371
+ var ManifestReadError = class extends Schema4.TaggedError()("ManifestReadError", {
1372
+ message: Schema4.String,
1373
+ filePath: Schema4.String
1374
+ }) {
1375
+ };
1376
+ var ManifestParseError = class extends Schema4.TaggedError()("ManifestParseError", {
1377
+ message: Schema4.String,
1378
+ filePath: Schema4.String
1379
+ }) {
1380
+ };
1381
+ var FrameworkNotDetectedError = class extends Schema4.TaggedError()(
1382
+ "FrameworkNotDetectedError",
1383
+ {
1384
+ message: Schema4.String,
1385
+ directory: Schema4.String
1386
+ }
1387
+ ) {
1388
+ };
1389
+
1390
+ // src/detection/read-dependencies.ts
1391
+ var MANIFEST_CONFIG = {
1392
+ node: { file: "package.json", depKeys: ["dependencies", "devDependencies"] },
1393
+ php: { file: "composer.json", depKeys: ["require", "require-dev"] }
1394
+ };
1395
+ var GEMFILE_LOCK_SOURCE_SECTIONS = /* @__PURE__ */ new Set(["GEM", "GIT", "PATH"]);
1396
+ var GEMFILE_LOCK_SPEC = /^ {4}([A-Za-z0-9_.-]+) \(/;
1397
+ var GEMFILE_GEM = /^\s*gem[\s(]+['"]([^'"]+)['"]/;
1398
+ var parseGemfileLock = (content) => {
1399
+ const gems = /* @__PURE__ */ new Set();
1400
+ let inSourceSection = false;
1401
+ for (const line of content.split(/\r?\n/)) {
1402
+ if (/^\S/.test(line)) {
1403
+ inSourceSection = GEMFILE_LOCK_SOURCE_SECTIONS.has(line.trim());
1404
+ continue;
1405
+ }
1406
+ const match = inSourceSection ? GEMFILE_LOCK_SPEC.exec(line) : null;
1407
+ if (match) {
1408
+ gems.add(match[1]);
1409
+ }
1410
+ }
1411
+ return gems;
1412
+ };
1413
+ var parseGemfile = (content) => {
1414
+ const gems = /* @__PURE__ */ new Set();
1415
+ for (const line of content.split(/\r?\n/)) {
1416
+ const match = GEMFILE_GEM.exec(line);
1417
+ if (match) {
1418
+ gems.add(match[1]);
1419
+ }
1420
+ }
1421
+ return gems;
1422
+ };
1423
+ var readOptionalText = Effect8.fn("readOptionalText")(function* (filePath) {
1424
+ const fs = yield* FileSystem7.FileSystem;
1425
+ const exists = yield* fs.exists(filePath).pipe(Effect8.catchAll(() => Effect8.succeed(false)));
1426
+ if (!exists) {
1427
+ return void 0;
1428
+ }
1429
+ return yield* fs.readFileString(filePath).pipe(Effect8.mapError(() => new ManifestReadError({ message: "Failed to read manifest", filePath })));
1430
+ });
1431
+ var readGemNames = Effect8.fn("readGemNames")(function* (projectFolder) {
1432
+ const pathService = yield* Path7.Path;
1433
+ const lockfile = yield* readOptionalText(pathService.join(projectFolder, "Gemfile.lock"));
1434
+ if (lockfile !== void 0) {
1435
+ return parseGemfileLock(lockfile);
1436
+ }
1437
+ const gemfile = yield* readOptionalText(pathService.join(projectFolder, "Gemfile"));
1438
+ return gemfile === void 0 ? /* @__PURE__ */ new Set() : parseGemfile(gemfile);
1439
+ });
1440
+ var readManifest = Effect8.fn("readManifest")(function* (filePath) {
1441
+ const fs = yield* FileSystem7.FileSystem;
1442
+ const exists = yield* fs.exists(filePath).pipe(Effect8.catchAll(() => Effect8.succeed(false)));
1443
+ if (!exists) {
1444
+ return yield* Effect8.fail(new ManifestNotFoundError({ message: "Manifest not found", filePath }));
1445
+ }
1446
+ const content = yield* fs.readFileString(filePath).pipe(Effect8.mapError(() => new ManifestReadError({ message: "Failed to read manifest", filePath })));
1447
+ const parsed = yield* Effect8.try({
1448
+ try: () => JSON.parse(content),
1449
+ catch: () => new ManifestParseError({ message: "Failed to parse manifest JSON", filePath })
1450
+ });
1451
+ return parsed;
1452
+ });
1453
+ var readDependencies = Effect8.fn("readDependencies")(function* (projectFolder, language) {
1454
+ if (language === "ruby") {
1455
+ return yield* readGemNames(projectFolder);
1456
+ }
1457
+ const pathService = yield* Path7.Path;
1458
+ const config = MANIFEST_CONFIG[language];
1459
+ const filePath = pathService.join(projectFolder, config.file);
1460
+ const manifest = yield* readManifest(filePath).pipe(
1461
+ Effect8.catchTag("ManifestNotFoundError", () => Effect8.succeed(null))
1462
+ );
1463
+ if (!manifest) {
1464
+ return /* @__PURE__ */ new Set();
1465
+ }
1466
+ const deps = /* @__PURE__ */ new Set();
1467
+ for (const key of config.depKeys) {
1468
+ const section = manifest[key];
1469
+ if (section && typeof section === "object" && !Array.isArray(section)) {
1470
+ for (const name of Object.keys(section)) {
1471
+ deps.add(name);
1472
+ }
1473
+ }
1474
+ }
1475
+ return deps;
1476
+ });
1477
+
1478
+ // src/detection/frameworks/ruby-server.ts
1479
+ import { FileSystem as FileSystem8, Path as Path8 } from "@effect/platform";
1480
+ import { Effect as Effect9 } from "effect";
1481
+ var rubyServerDefaults = ({
1482
+ entrypoint = "config.ru",
1483
+ memory = 256,
1484
+ commands = [],
1485
+ environmentVariables,
1486
+ excludeFiles,
1487
+ writablePaths = []
1488
+ }) => ({
1489
+ runtime: DEFAULT_RUBY_RUNTIME,
1490
+ memory,
1491
+ maxDuration: 30,
1492
+ streaming: true,
1493
+ commands,
1494
+ entrypoint,
1495
+ assetsDir: "public",
1496
+ populateAssetCache: true,
1497
+ routes: [{ source: "/*", destination: entrypoint }],
1498
+ environmentVariables,
1499
+ ...excludeFiles ? { excludeFiles } : {},
1500
+ ...writablePaths.length > 0 ? { package: { writablePaths } } : {}
1501
+ });
1502
+ var refineRubyPublicDirectory = Effect9.fn("refineRubyPublicDirectory")(function* (defaults, projectFolder) {
1503
+ if (!defaults.assetsDir) {
1504
+ return defaults;
1505
+ }
1506
+ const fs = yield* FileSystem8.FileSystem;
1507
+ const pathService = yield* Path8.Path;
1508
+ const exists = yield* fs.exists(pathService.join(projectFolder, defaults.assetsDir)).pipe(Effect9.catchAll(() => Effect9.succeed(false)));
1509
+ if (exists) {
1510
+ return defaults;
1511
+ }
1512
+ const withoutAssets = { ...defaults };
1513
+ delete withoutAssets.assetsDir;
1514
+ delete withoutAssets.populateAssetCache;
1515
+ return withoutAssets;
1516
+ });
1517
+
1518
+ // src/detection/frameworks/hanami.ts
1519
+ var refineHanamiAssets = Effect10.fn("refineHanamiAssets")(function* (defaults, projectFolder) {
1520
+ const gems = yield* readDependencies(projectFolder, "ruby").pipe(
1521
+ Effect10.catchAll(() => Effect10.succeed(/* @__PURE__ */ new Set()))
1522
+ );
1523
+ const withPublicDirectory = yield* refineRubyPublicDirectory(defaults, projectFolder);
1524
+ return gems.has("hanami-assets") ? { ...withPublicDirectory, commands: [...withPublicDirectory.commands, "bundle exec hanami assets compile"] } : withPublicDirectory;
1525
+ });
1526
+ var hanami = {
1527
+ slug: "hanami",
1528
+ name: "Hanami",
1529
+ language: "ruby",
1530
+ detectors: [{ matchPackage: "hanami" }, { path: "config.ru" }],
1531
+ priority: 75,
1532
+ getDefaultConfig: () => rubyServerDefaults({
1533
+ excludeFiles: ["tmp/", "log/", "spec/", "node_modules/", ".git/"],
1534
+ writablePaths: ["tmp", "log"],
1535
+ environmentVariables: { HANAMI_ENV: "production", RACK_ENV: "production" }
1536
+ }),
1537
+ refineDefaultConfig: refineHanamiAssets
1538
+ };
1539
+
1168
1540
  // src/detection/frameworks/hono.ts
1169
1541
  var hono = {
1170
1542
  slug: "hono",
@@ -1185,6 +1557,30 @@ var hono = {
1185
1557
  refineDefaultConfig: resolveNodeServerEntrypoint
1186
1558
  };
1187
1559
 
1560
+ // src/detection/frameworks/jekyll.ts
1561
+ var jekyll = {
1562
+ slug: "jekyll",
1563
+ name: "Jekyll",
1564
+ language: "ruby",
1565
+ detectors: [{ matchPackage: "jekyll" }],
1566
+ priority: 70,
1567
+ getDefaultConfig: () => ({
1568
+ runtime: DEFAULT_RUBY_RUNTIME,
1569
+ memory: 128,
1570
+ maxDuration: 30,
1571
+ streaming: false,
1572
+ commands: ["bundle exec jekyll build"],
1573
+ assetsDir: "_site",
1574
+ populateAssetCache: true,
1575
+ routes: [],
1576
+ environmentVariables: { JEKYLL_ENV: "production" }
1577
+ })
1578
+ };
1579
+ var jekyllPresets = [
1580
+ jekyll,
1581
+ { ...jekyll, detectors: [{ matchPackage: "github-pages" }] }
1582
+ ];
1583
+
1188
1584
  // src/detection/frameworks/laminas.ts
1189
1585
  var laminas = {
1190
1586
  slug: "laminas",
@@ -1264,8 +1660,8 @@ var mezzio = {
1264
1660
  };
1265
1661
 
1266
1662
  // src/detection/frameworks/nestjs.ts
1267
- import { FileSystem as FileSystem6 } from "@effect/platform";
1268
- import { Effect as Effect6 } from "effect";
1663
+ import { FileSystem as FileSystem9 } from "@effect/platform";
1664
+ import { Effect as Effect11 } from "effect";
1269
1665
  var isRecord3 = (value) => typeof value === "object" && value !== null;
1270
1666
  var parseNestCliJson = (content) => {
1271
1667
  try {
@@ -1316,9 +1712,9 @@ var nestjs = {
1316
1712
  detectors: [{ matchPackage: "@nestjs/core" }],
1317
1713
  priority: 90,
1318
1714
  getDefaultConfig: () => createNestConfig("dist"),
1319
- refineDefaultConfig: (defaults, projectFolder) => Effect6.gen(function* () {
1320
- const fs = yield* FileSystem6.FileSystem;
1321
- const content = yield* fs.readFileString(`${projectFolder}/nest-cli.json`).pipe(Effect6.catchAll(() => Effect6.succeed(void 0)));
1715
+ refineDefaultConfig: (defaults, projectFolder) => Effect11.gen(function* () {
1716
+ const fs = yield* FileSystem9.FileSystem;
1717
+ const content = yield* fs.readFileString(`${projectFolder}/nest-cli.json`).pipe(Effect11.catchAll(() => Effect11.succeed(void 0)));
1322
1718
  if (!content) return defaults;
1323
1719
  const nestConfig = parseNestCliJson(content);
1324
1720
  const outputPath = nestConfig ? getProjectOutputPath(nestConfig) : void 0;
@@ -1327,28 +1723,28 @@ var nestjs = {
1327
1723
  };
1328
1724
 
1329
1725
  // src/detection/frameworks/nextjs.ts
1330
- import { FileSystem as FileSystem8, Path as Path7 } from "@effect/platform";
1331
- import { Effect as Effect8 } from "effect";
1726
+ import { FileSystem as FileSystem11, Path as Path10 } from "@effect/platform";
1727
+ import { Effect as Effect13 } from "effect";
1332
1728
 
1333
1729
  // src/build-output-v3/get-default-path-map.ts
1334
- import { FileSystem as FileSystem7, Path as Path6 } from "@effect/platform";
1335
- import { Effect as Effect7 } from "effect";
1336
- var getDefaultPathMap = Effect7.fn("getDefaultPathMap")(function* (directory) {
1337
- const fs = yield* FileSystem7.FileSystem;
1338
- const pathService = yield* Path6.Path;
1730
+ import { FileSystem as FileSystem10, Path as Path9 } from "@effect/platform";
1731
+ import { Effect as Effect12 } from "effect";
1732
+ var getDefaultPathMap = Effect12.fn("getDefaultPathMap")(function* (directory) {
1733
+ const fs = yield* FileSystem10.FileSystem;
1734
+ const pathService = yield* Path9.Path;
1339
1735
  const result = {};
1340
- const exists = yield* fs.exists(directory).pipe(Effect7.catchAll(() => Effect7.succeed(false)));
1736
+ const exists = yield* fs.exists(directory).pipe(Effect12.catchAll(() => Effect12.succeed(false)));
1341
1737
  if (!exists) {
1342
1738
  return result;
1343
1739
  }
1344
1740
  const MAX_DEPTH = 100;
1345
- const processDirectory = (currentPath, basePath = "", depth = 0) => Effect7.gen(function* () {
1741
+ const processDirectory = (currentPath, basePath = "", depth = 0) => Effect12.gen(function* () {
1346
1742
  if (depth > MAX_DEPTH) return;
1347
- const entries = yield* fs.readDirectory(currentPath).pipe(Effect7.catchAll(() => Effect7.succeed([])));
1743
+ const entries = yield* fs.readDirectory(currentPath).pipe(Effect12.catchAll(() => Effect12.succeed([])));
1348
1744
  for (const name of entries) {
1349
1745
  const fullPath = pathService.join(currentPath, name);
1350
1746
  const relativePath = basePath ? pathService.join(basePath, name) : name;
1351
- const stat = yield* fs.stat(fullPath).pipe(Effect7.catchAll(() => Effect7.succeed(null)));
1747
+ const stat = yield* fs.stat(fullPath).pipe(Effect12.catchAll(() => Effect12.succeed(null)));
1352
1748
  if (!stat) continue;
1353
1749
  if (stat.type === "Directory") {
1354
1750
  yield* processDirectory(fullPath, relativePath, depth + 1);
@@ -1365,244 +1761,244 @@ var getDefaultPathMap = Effect7.fn("getDefaultPathMap")(function* (directory) {
1365
1761
  var MAXIMUM_ENTRY_PAGE_PATHS = 50;
1366
1762
 
1367
1763
  // src/nextjs-manifest.ts
1368
- import { Schema as Schema4 } from "effect";
1369
- var StringArraySchema = Schema4.mutable(Schema4.Array(Schema4.String));
1370
- var StringRecordSchema = Schema4.mutable(Schema4.Record({ key: Schema4.String, value: Schema4.String }));
1371
- var JsonValueSchema = Schema4.suspend(
1372
- () => Schema4.Union(
1373
- Schema4.Null,
1374
- Schema4.Boolean,
1375
- Schema4.Number,
1376
- Schema4.String,
1377
- Schema4.mutable(Schema4.Array(JsonValueSchema)),
1378
- Schema4.mutable(Schema4.Record({ key: Schema4.String, value: JsonValueSchema }))
1764
+ import { Schema as Schema5 } from "effect";
1765
+ var StringArraySchema = Schema5.mutable(Schema5.Array(Schema5.String));
1766
+ var StringRecordSchema = Schema5.mutable(Schema5.Record({ key: Schema5.String, value: Schema5.String }));
1767
+ var JsonValueSchema = Schema5.suspend(
1768
+ () => Schema5.Union(
1769
+ Schema5.Null,
1770
+ Schema5.Boolean,
1771
+ Schema5.Number,
1772
+ Schema5.String,
1773
+ Schema5.mutable(Schema5.Array(JsonValueSchema)),
1774
+ Schema5.mutable(Schema5.Record({ key: Schema5.String, value: JsonValueSchema }))
1379
1775
  )
1380
1776
  );
1381
- var ImageLocalPatternSchema = Schema4.mutable(
1382
- Schema4.Struct({
1383
- pathname: Schema4.optional(Schema4.String),
1384
- search: Schema4.optional(Schema4.String)
1777
+ var ImageLocalPatternSchema = Schema5.mutable(
1778
+ Schema5.Struct({
1779
+ pathname: Schema5.optional(Schema5.String),
1780
+ search: Schema5.optional(Schema5.String)
1385
1781
  })
1386
1782
  );
1387
- var ImageRemotePatternSchema = Schema4.mutable(
1388
- Schema4.Struct({
1389
- protocol: Schema4.optional(Schema4.Literal("http", "https")),
1390
- hostname: Schema4.String,
1391
- port: Schema4.optional(Schema4.String),
1392
- pathname: Schema4.optional(Schema4.String),
1393
- search: Schema4.optional(Schema4.String)
1783
+ var ImageRemotePatternSchema = Schema5.mutable(
1784
+ Schema5.Struct({
1785
+ protocol: Schema5.optional(Schema5.Literal("http", "https")),
1786
+ hostname: Schema5.String,
1787
+ port: Schema5.optional(Schema5.String),
1788
+ pathname: Schema5.optional(Schema5.String),
1789
+ search: Schema5.optional(Schema5.String)
1394
1790
  })
1395
1791
  );
1396
- var ImageVariantSchema = Schema4.mutable(
1397
- Schema4.Struct({
1398
- width: Schema4.optional(Schema4.Number),
1399
- height: Schema4.optional(Schema4.Number),
1400
- quality: Schema4.optional(Schema4.Number),
1401
- format: Schema4.optional(Schema4.Literal("image/avif", "image/webp", "image/jpeg", "image/png")),
1402
- fit: Schema4.optional(Schema4.Literal("contain", "cover", "fill", "inside", "outside"))
1792
+ var ImageVariantSchema = Schema5.mutable(
1793
+ Schema5.Struct({
1794
+ width: Schema5.optional(Schema5.Number),
1795
+ height: Schema5.optional(Schema5.Number),
1796
+ quality: Schema5.optional(Schema5.Number),
1797
+ format: Schema5.optional(Schema5.Literal("image/avif", "image/webp", "image/jpeg", "image/png")),
1798
+ fit: Schema5.optional(Schema5.Literal("contain", "cover", "fill", "inside", "outside"))
1403
1799
  })
1404
1800
  );
1405
- var PositiveIntSchema = Schema4.Int.pipe(Schema4.greaterThan(0));
1406
- var ImagePolicySchema = Schema4.mutable(
1407
- Schema4.Struct({
1408
- localPatterns: Schema4.mutable(Schema4.Array(ImageLocalPatternSchema)),
1409
- remotePatterns: Schema4.mutable(Schema4.Array(ImageRemotePatternSchema)),
1410
- widths: Schema4.mutable(Schema4.Array(PositiveIntSchema)),
1411
- heights: Schema4.mutable(Schema4.Array(PositiveIntSchema)),
1412
- qualities: Schema4.mutable(Schema4.Array(Schema4.Number.pipe(Schema4.between(1, 100)))),
1413
- formats: Schema4.mutable(Schema4.Array(Schema4.Literal("image/avif", "image/webp", "image/jpeg", "image/png"))),
1414
- minimumCacheTTL: Schema4.Number,
1415
- dangerouslyAllowSVG: Schema4.Boolean,
1416
- contentSecurityPolicy: Schema4.String,
1417
- contentDispositionType: Schema4.Literal("inline", "attachment"),
1418
- maximumRedirects: Schema4.Number,
1419
- maximumResponseBody: Schema4.Number,
1420
- variants: Schema4.mutable(Schema4.Record({ key: Schema4.String, value: ImageVariantSchema }))
1801
+ var PositiveIntSchema = Schema5.Int.pipe(Schema5.greaterThan(0));
1802
+ var ImagePolicySchema = Schema5.mutable(
1803
+ Schema5.Struct({
1804
+ localPatterns: Schema5.mutable(Schema5.Array(ImageLocalPatternSchema)),
1805
+ remotePatterns: Schema5.mutable(Schema5.Array(ImageRemotePatternSchema)),
1806
+ widths: Schema5.mutable(Schema5.Array(PositiveIntSchema)),
1807
+ heights: Schema5.mutable(Schema5.Array(PositiveIntSchema)),
1808
+ qualities: Schema5.mutable(Schema5.Array(Schema5.Number.pipe(Schema5.between(1, 100)))),
1809
+ formats: Schema5.mutable(Schema5.Array(Schema5.Literal("image/avif", "image/webp", "image/jpeg", "image/png"))),
1810
+ minimumCacheTTL: Schema5.Number,
1811
+ dangerouslyAllowSVG: Schema5.Boolean,
1812
+ contentSecurityPolicy: Schema5.String,
1813
+ contentDispositionType: Schema5.Literal("inline", "attachment"),
1814
+ maximumRedirects: Schema5.Number,
1815
+ maximumResponseBody: Schema5.Number,
1816
+ variants: Schema5.mutable(Schema5.Record({ key: Schema5.String, value: ImageVariantSchema }))
1421
1817
  })
1422
1818
  );
1423
1819
  var GigadriveNextPrerenderOutputFields = {
1424
- id: Schema4.String,
1425
- type: Schema4.Literal("PRERENDER"),
1820
+ id: Schema5.String,
1821
+ type: Schema5.Literal("PRERENDER"),
1426
1822
  pathname: UrlPathnameSchema,
1427
- route: Schema4.optional(UrlPathnameSchema),
1428
- parentOutputId: Schema4.String,
1429
- groupId: Schema4.Number,
1430
- pprChain: Schema4.optional(Schema4.mutable(Schema4.Struct({ headers: HttpSingleValueHeadersSchema }))),
1431
- parentFallbackMode: Schema4.optional(JsonValueSchema),
1432
- fallback: Schema4.optional(
1433
- Schema4.mutable(
1434
- Schema4.Struct({
1435
- filePath: Schema4.optional(PortableRelativePathSchema),
1436
- initialStatus: Schema4.optional(Schema4.Int.pipe(Schema4.between(100, 599))),
1437
- initialHeaders: Schema4.optional(HttpHeadersSchema),
1438
- initialExpiration: Schema4.optional(Schema4.Number),
1439
- initialRevalidate: Schema4.optional(Schema4.Union(Schema4.Number, Schema4.Literal(false))),
1440
- postponedState: Schema4.optional(Schema4.String)
1823
+ route: Schema5.optional(UrlPathnameSchema),
1824
+ parentOutputId: Schema5.String,
1825
+ groupId: Schema5.Number,
1826
+ pprChain: Schema5.optional(Schema5.mutable(Schema5.Struct({ headers: HttpSingleValueHeadersSchema }))),
1827
+ parentFallbackMode: Schema5.optional(JsonValueSchema),
1828
+ fallback: Schema5.optional(
1829
+ Schema5.mutable(
1830
+ Schema5.Struct({
1831
+ filePath: Schema5.optional(PortableRelativePathSchema),
1832
+ initialStatus: Schema5.optional(Schema5.Int.pipe(Schema5.between(100, 599))),
1833
+ initialHeaders: Schema5.optional(HttpHeadersSchema),
1834
+ initialExpiration: Schema5.optional(Schema5.Number),
1835
+ initialRevalidate: Schema5.optional(Schema5.Union(Schema5.Number, Schema5.Literal(false))),
1836
+ postponedState: Schema5.optional(Schema5.String)
1441
1837
  })
1442
1838
  )
1443
1839
  ),
1444
- config: Schema4.mutable(
1445
- Schema4.Struct({
1446
- allowQuery: Schema4.optional(StringArraySchema),
1447
- allowHeader: Schema4.optional(StringArraySchema),
1448
- bypassFor: Schema4.optional(Schema4.mutable(Schema4.Array(JsonValueSchema))),
1449
- renderingMode: Schema4.optional(Schema4.String),
1450
- partialFallback: Schema4.optional(Schema4.Boolean),
1451
- bypassToken: Schema4.optional(Schema4.String)
1840
+ config: Schema5.mutable(
1841
+ Schema5.Struct({
1842
+ allowQuery: Schema5.optional(StringArraySchema),
1843
+ allowHeader: Schema5.optional(StringArraySchema),
1844
+ bypassFor: Schema5.optional(Schema5.mutable(Schema5.Array(JsonValueSchema))),
1845
+ renderingMode: Schema5.optional(Schema5.String),
1846
+ partialFallback: Schema5.optional(Schema5.Boolean),
1847
+ bypassToken: Schema5.optional(Schema5.String)
1452
1848
  })
1453
1849
  )
1454
1850
  };
1455
- var GigadriveNextPrerenderClassificationSchema = Schema4.Struct({
1456
- routeType: Schema4.Literal("route", "fallback", "shell", "page"),
1457
- response: Schema4.Literal("empty", "initial", "complete"),
1458
- compute: Schema4.Literal("blocking", "resuming", "static"),
1459
- htmlSize: Schema4.optional(Schema4.Number)
1851
+ var GigadriveNextPrerenderClassificationSchema = Schema5.Struct({
1852
+ routeType: Schema5.Literal("route", "fallback", "shell", "page"),
1853
+ response: Schema5.Literal("empty", "initial", "complete"),
1854
+ compute: Schema5.Literal("blocking", "resuming", "static"),
1855
+ htmlSize: Schema5.optional(Schema5.Number)
1460
1856
  });
1461
- var GigadriveNextPrerenderWithoutClassificationSchema = Schema4.Struct({
1462
- routeType: Schema4.optional(Schema4.Never),
1463
- response: Schema4.optional(Schema4.Never),
1464
- compute: Schema4.optional(Schema4.Never),
1465
- htmlSize: Schema4.optional(Schema4.Never)
1857
+ var GigadriveNextPrerenderWithoutClassificationSchema = Schema5.Struct({
1858
+ routeType: Schema5.optional(Schema5.Never),
1859
+ response: Schema5.optional(Schema5.Never),
1860
+ compute: Schema5.optional(Schema5.Never),
1861
+ htmlSize: Schema5.optional(Schema5.Never)
1466
1862
  });
1467
- var GigadriveNextPrerenderOutputSchema = Schema4.Union(
1468
- Schema4.mutable(
1469
- Schema4.Struct({ ...GigadriveNextPrerenderOutputFields, ...GigadriveNextPrerenderClassificationSchema.fields })
1863
+ var GigadriveNextPrerenderOutputSchema = Schema5.Union(
1864
+ Schema5.mutable(
1865
+ Schema5.Struct({ ...GigadriveNextPrerenderOutputFields, ...GigadriveNextPrerenderClassificationSchema.fields })
1470
1866
  ),
1471
- Schema4.mutable(
1472
- Schema4.Struct({
1867
+ Schema5.mutable(
1868
+ Schema5.Struct({
1473
1869
  ...GigadriveNextPrerenderOutputFields,
1474
1870
  ...GigadriveNextPrerenderWithoutClassificationSchema.fields
1475
1871
  })
1476
1872
  )
1477
1873
  );
1478
- var GigadriveNextStaticAssetPrefixSchema = Schema4.mutable(
1479
- Schema4.Struct({
1874
+ var GigadriveNextStaticAssetPrefixSchema = Schema5.mutable(
1875
+ Schema5.Struct({
1480
1876
  sourceDir: PortableRelativePathSchema,
1481
1877
  urlPrefix: PortableRelativePathSchema,
1482
- immutable: Schema4.Boolean
1878
+ immutable: Schema5.Boolean
1483
1879
  })
1484
1880
  );
1485
- var GigadriveNextRouteConditionSchema = Schema4.Union(
1486
- Schema4.mutable(
1487
- Schema4.Struct({
1488
- type: Schema4.Literal("header", "cookie", "query"),
1489
- key: Schema4.String,
1490
- value: Schema4.optional(Schema4.String)
1881
+ var GigadriveNextRouteConditionSchema = Schema5.Union(
1882
+ Schema5.mutable(
1883
+ Schema5.Struct({
1884
+ type: Schema5.Literal("header", "cookie", "query"),
1885
+ key: Schema5.String,
1886
+ value: Schema5.optional(Schema5.String)
1491
1887
  })
1492
1888
  ),
1493
- Schema4.mutable(
1494
- Schema4.Struct({
1495
- type: Schema4.Literal("host"),
1496
- value: Schema4.String
1889
+ Schema5.mutable(
1890
+ Schema5.Struct({
1891
+ type: Schema5.Literal("host"),
1892
+ value: Schema5.String
1497
1893
  })
1498
1894
  )
1499
1895
  );
1500
- var GigadriveNextMiddlewareMatcherSchema = Schema4.mutable(
1501
- Schema4.Struct({
1502
- source: Schema4.String,
1503
- sourceRegex: Schema4.String,
1504
- has: Schema4.optional(Schema4.mutable(Schema4.Array(GigadriveNextRouteConditionSchema))),
1505
- missing: Schema4.optional(Schema4.mutable(Schema4.Array(GigadriveNextRouteConditionSchema)))
1896
+ var GigadriveNextMiddlewareMatcherSchema = Schema5.mutable(
1897
+ Schema5.Struct({
1898
+ source: Schema5.String,
1899
+ sourceRegex: Schema5.String,
1900
+ has: Schema5.optional(Schema5.mutable(Schema5.Array(GigadriveNextRouteConditionSchema))),
1901
+ missing: Schema5.optional(Schema5.mutable(Schema5.Array(GigadriveNextRouteConditionSchema)))
1506
1902
  })
1507
1903
  );
1508
- var GigadriveNextMiddlewareDescriptorSchema = Schema4.Union(
1509
- Schema4.mutable(
1510
- Schema4.Struct({
1511
- present: Schema4.Literal(true),
1512
- matchers: Schema4.mutable(Schema4.Array(GigadriveNextMiddlewareMatcherSchema))
1904
+ var GigadriveNextMiddlewareDescriptorSchema = Schema5.Union(
1905
+ Schema5.mutable(
1906
+ Schema5.Struct({
1907
+ present: Schema5.Literal(true),
1908
+ matchers: Schema5.mutable(Schema5.Array(GigadriveNextMiddlewareMatcherSchema))
1513
1909
  })
1514
1910
  ),
1515
- Schema4.mutable(
1516
- Schema4.Struct({
1517
- present: Schema4.Literal(false),
1518
- matchers: Schema4.mutable(Schema4.Tuple())
1911
+ Schema5.mutable(
1912
+ Schema5.Struct({
1913
+ present: Schema5.Literal(false),
1914
+ matchers: Schema5.mutable(Schema5.Tuple())
1519
1915
  })
1520
1916
  )
1521
1917
  );
1522
- var GigadriveNextServerDescriptorSchema = Schema4.mutable(
1523
- Schema4.Struct({
1524
- maxDuration: Schema4.optional(Schema4.Number),
1525
- preferredRegion: Schema4.optional(Schema4.Union(Schema4.String, StringArraySchema)),
1526
- env: Schema4.optional(StringRecordSchema)
1918
+ var GigadriveNextServerDescriptorSchema = Schema5.mutable(
1919
+ Schema5.Struct({
1920
+ maxDuration: Schema5.optional(Schema5.Number),
1921
+ preferredRegion: Schema5.optional(Schema5.Union(Schema5.String, StringArraySchema)),
1922
+ env: Schema5.optional(StringRecordSchema)
1527
1923
  })
1528
1924
  );
1529
- var PrerenderArraySchema = Schema4.mutable(Schema4.Array(GigadriveNextPrerenderOutputSchema));
1530
- var StaticAssetArraySchema = Schema4.mutable(Schema4.Array(GigadriveNextStaticAssetPrefixSchema));
1531
- var JsonValueArraySchema = Schema4.mutable(Schema4.Array(JsonValueSchema));
1532
- var GigadriveNextPrerenderSeedMethodsSchema = Schema4.mutable(
1533
- Schema4.Tuple(Schema4.Literal("GET"), Schema4.Literal("HEAD"))
1925
+ var PrerenderArraySchema = Schema5.mutable(Schema5.Array(GigadriveNextPrerenderOutputSchema));
1926
+ var StaticAssetArraySchema = Schema5.mutable(Schema5.Array(GigadriveNextStaticAssetPrefixSchema));
1927
+ var JsonValueArraySchema = Schema5.mutable(Schema5.Array(JsonValueSchema));
1928
+ var GigadriveNextPrerenderSeedMethodsSchema = Schema5.mutable(
1929
+ Schema5.Tuple(Schema5.Literal("GET"), Schema5.Literal("HEAD"))
1534
1930
  );
1535
- var GigadriveNextBuildManifestV1Schema = Schema4.mutable(
1536
- Schema4.Struct({
1537
- version: Schema4.Literal(1),
1538
- output: Schema4.Literal("standalone", "export"),
1931
+ var GigadriveNextBuildManifestV1Schema = Schema5.mutable(
1932
+ Schema5.Struct({
1933
+ version: Schema5.Literal(1),
1934
+ output: Schema5.Literal("standalone", "export"),
1539
1935
  distDir: PortableRelativePathSchema,
1540
1936
  repoRootToProject: RepositoryRelativePathSchema,
1541
- nextVersion: Schema4.String,
1542
- buildId: Schema4.String
1937
+ nextVersion: Schema5.String,
1938
+ buildId: Schema5.String
1543
1939
  })
1544
1940
  );
1545
- var GigadriveNextBuildManifestV2ExportSchema = Schema4.mutable(
1546
- Schema4.Struct({
1547
- version: Schema4.Literal(2),
1548
- mode: Schema4.Literal("export"),
1941
+ var GigadriveNextBuildManifestV2ExportSchema = Schema5.mutable(
1942
+ Schema5.Struct({
1943
+ version: Schema5.Literal(2),
1944
+ mode: Schema5.Literal("export"),
1549
1945
  distDir: PortableRelativePathSchema,
1550
1946
  repoRootToProject: RepositoryRelativePathSchema,
1551
- nextVersion: Schema4.String,
1552
- buildId: Schema4.String
1947
+ nextVersion: Schema5.String,
1948
+ buildId: Schema5.String
1553
1949
  })
1554
1950
  );
1555
- var GigadriveNextBuildManifestV2StandaloneSchema = Schema4.mutable(
1556
- Schema4.Struct({
1557
- version: Schema4.Literal(2),
1558
- mode: Schema4.Literal("standalone-v2"),
1951
+ var GigadriveNextBuildManifestV2StandaloneSchema = Schema5.mutable(
1952
+ Schema5.Struct({
1953
+ version: Schema5.Literal(2),
1954
+ mode: Schema5.Literal("standalone-v2"),
1559
1955
  distDir: PortableRelativePathSchema,
1560
1956
  repoRootToProject: RepositoryRelativePathSchema,
1561
- nextVersion: Schema4.String,
1562
- buildId: Schema4.String,
1957
+ nextVersion: Schema5.String,
1958
+ buildId: Schema5.String,
1563
1959
  server: GigadriveNextServerDescriptorSchema,
1564
- config: Schema4.mutable(
1565
- Schema4.Struct({
1566
- basePath: Schema4.String,
1567
- trailingSlash: Schema4.Boolean,
1568
- cacheComponents: Schema4.Boolean,
1569
- i18n: Schema4.optional(JsonValueSchema),
1570
- images: Schema4.optional(ImagePolicySchema)
1960
+ config: Schema5.mutable(
1961
+ Schema5.Struct({
1962
+ basePath: Schema5.String,
1963
+ trailingSlash: Schema5.Boolean,
1964
+ cacheComponents: Schema5.Boolean,
1965
+ i18n: Schema5.optional(JsonValueSchema),
1966
+ images: Schema5.optional(ImagePolicySchema)
1571
1967
  })
1572
1968
  ),
1573
- routing: Schema4.mutable(
1574
- Schema4.Struct({
1969
+ routing: Schema5.mutable(
1970
+ Schema5.Struct({
1575
1971
  beforeMiddleware: JsonValueArraySchema,
1576
1972
  beforeFiles: JsonValueArraySchema,
1577
1973
  afterFiles: JsonValueArraySchema,
1578
1974
  dynamicRoutes: JsonValueArraySchema,
1579
1975
  onMatch: JsonValueArraySchema,
1580
1976
  fallback: JsonValueArraySchema,
1581
- shouldNormalizeNextData: Schema4.Boolean,
1977
+ shouldNormalizeNextData: Schema5.Boolean,
1582
1978
  rsc: JsonValueSchema
1583
1979
  })
1584
1980
  ),
1585
- outputs: Schema4.mutable(
1586
- Schema4.Struct({
1981
+ outputs: Schema5.mutable(
1982
+ Schema5.Struct({
1587
1983
  prerenders: PrerenderArraySchema,
1588
- prerenderManifest: Schema4.optional(PortableRelativePathSchema),
1589
- assetManifest: Schema4.optional(PortableRelativePathSchema),
1590
- entryPagePaths: Schema4.optional(Schema4.mutable(Schema4.Array(UrlPathnameSchema))),
1984
+ prerenderManifest: Schema5.optional(PortableRelativePathSchema),
1985
+ assetManifest: Schema5.optional(PortableRelativePathSchema),
1986
+ entryPagePaths: Schema5.optional(Schema5.mutable(Schema5.Array(UrlPathnameSchema))),
1591
1987
  staticAssets: StaticAssetArraySchema,
1592
- middleware: Schema4.optional(GigadriveNextMiddlewareDescriptorSchema)
1988
+ middleware: Schema5.optional(GigadriveNextMiddlewareDescriptorSchema)
1593
1989
  })
1594
1990
  )
1595
1991
  })
1596
1992
  );
1597
- var GigadriveNextBuildManifestSchema = Schema4.Union(
1993
+ var GigadriveNextBuildManifestSchema = Schema5.Union(
1598
1994
  GigadriveNextBuildManifestV1Schema,
1599
1995
  GigadriveNextBuildManifestV2ExportSchema,
1600
1996
  GigadriveNextBuildManifestV2StandaloneSchema
1601
1997
  );
1602
- var GigadriveNextPrerenderManifestV1Schema = Schema4.mutable(
1603
- Schema4.Struct({
1604
- version: Schema4.Literal(1),
1605
- seedMethods: Schema4.optional(GigadriveNextPrerenderSeedMethodsSchema),
1998
+ var GigadriveNextPrerenderManifestV1Schema = Schema5.mutable(
1999
+ Schema5.Struct({
2000
+ version: Schema5.Literal(1),
2001
+ seedMethods: Schema5.optional(GigadriveNextPrerenderSeedMethodsSchema),
1606
2002
  prerenders: PrerenderArraySchema
1607
2003
  })
1608
2004
  );
@@ -1612,22 +2008,22 @@ var parseGigadriveNextPrerenderManifest = (content) => decodeJson(GigadriveNextP
1612
2008
  // src/detection/frameworks/nextjs.ts
1613
2009
  var toPortablePath = (value) => value.replaceAll("\\", "/");
1614
2010
  var STANDALONE_SERVER_MEMORY_MB = 1024;
1615
- var resolveStandaloneServer = Effect8.fn("nextjs.resolveStandaloneServer")(function* (projectFolder, distDir, repoRootToProject) {
1616
- const fs = yield* FileSystem8.FileSystem;
1617
- const pathService = yield* Path7.Path;
2011
+ var resolveStandaloneServer = Effect13.fn("nextjs.resolveStandaloneServer")(function* (projectFolder, distDir, repoRootToProject) {
2012
+ const fs = yield* FileSystem11.FileSystem;
2013
+ const pathService = yield* Path10.Path;
1618
2014
  const standaloneRoot = pathService.join(projectFolder, distDir, "standalone");
1619
2015
  const monorepoServer = pathService.join(standaloneRoot, repoRootToProject, "server.js");
1620
2016
  const rootServer = pathService.join(standaloneRoot, "server.js");
1621
- const monorepoServerExists = yield* fs.exists(monorepoServer).pipe(Effect8.catchAll(() => Effect8.succeed(false)));
2017
+ const monorepoServerExists = yield* fs.exists(monorepoServer).pipe(Effect13.catchAll(() => Effect13.succeed(false)));
1622
2018
  const serverPath = monorepoServerExists ? monorepoServer : rootServer;
1623
- const serverExists = yield* fs.exists(serverPath).pipe(Effect8.catchAll(() => Effect8.succeed(false)));
2019
+ const serverExists = yield* fs.exists(serverPath).pipe(Effect13.catchAll(() => Effect13.succeed(false)));
1624
2020
  if (!serverExists) return void 0;
1625
2021
  const serverDirectory = pathService.dirname(serverPath);
1626
2022
  const entrypoint = toPortablePath(pathService.relative(standaloneRoot, serverPath));
1627
2023
  return { standaloneRoot, serverDirectory, entrypoint };
1628
2024
  });
1629
- var buildStandalonePublicAssets = Effect8.fn("nextjs.buildStandalonePublicAssets")(function* (projectFolder, standaloneRoot, serverDirectory) {
1630
- const pathService = yield* Path7.Path;
2025
+ var buildStandalonePublicAssets = Effect13.fn("nextjs.buildStandalonePublicAssets")(function* (projectFolder, standaloneRoot, serverDirectory) {
2026
+ const pathService = yield* Path10.Path;
1631
2027
  const publicFiles = yield* getDefaultPathMap(pathService.join(projectFolder, "public"));
1632
2028
  const assetPaths = [];
1633
2029
  const assetOverrides = {};
@@ -1643,8 +2039,8 @@ var buildStandalonePublicAssets = Effect8.fn("nextjs.buildStandalonePublicAssets
1643
2039
  }
1644
2040
  return { assetPaths, assetOverrides, filePathMap };
1645
2041
  });
1646
- var createStaticExportConfig = Effect8.fn("nextjs.createStaticExportConfig")(function* (defaults, projectFolder) {
1647
- const pathService = yield* Path7.Path;
2042
+ var createStaticExportConfig = Effect13.fn("nextjs.createStaticExportConfig")(function* (defaults, projectFolder) {
2043
+ const pathService = yield* Path10.Path;
1648
2044
  const outputDirectory = pathService.join(projectFolder, "out");
1649
2045
  const files = yield* getDefaultPathMap(outputDirectory);
1650
2046
  const assetPaths = [];
@@ -1667,8 +2063,8 @@ var createStaticExportConfig = Effect8.fn("nextjs.createStaticExportConfig")(fun
1667
2063
  package: void 0
1668
2064
  };
1669
2065
  });
1670
- var createStandaloneConfig = Effect8.fn("nextjs.createStandaloneConfig")(function* (defaults, projectFolder, manifest) {
1671
- const pathService = yield* Path7.Path;
2066
+ var createStandaloneConfig = Effect13.fn("nextjs.createStandaloneConfig")(function* (defaults, projectFolder, manifest) {
2067
+ const pathService = yield* Path10.Path;
1672
2068
  const resolved = yield* resolveStandaloneServer(projectFolder, manifest.distDir, manifest.repoRootToProject);
1673
2069
  if (!resolved) return defaults;
1674
2070
  const { standaloneRoot, serverDirectory, entrypoint } = resolved;
@@ -1701,7 +2097,7 @@ var createStandaloneConfig = Effect8.fn("nextjs.createStandaloneConfig")(functio
1701
2097
  }
1702
2098
  };
1703
2099
  });
1704
- var createStandaloneV2Config = Effect8.fn("nextjs.createStandaloneV2Config")(function* (defaults, projectFolder, manifest) {
2100
+ var createStandaloneV2Config = Effect13.fn("nextjs.createStandaloneV2Config")(function* (defaults, projectFolder, manifest) {
1705
2101
  const resolved = yield* resolveStandaloneServer(projectFolder, manifest.distDir, manifest.repoRootToProject);
1706
2102
  if (!resolved) return defaults;
1707
2103
  const { standaloneRoot, serverDirectory, entrypoint } = resolved;
@@ -1809,9 +2205,9 @@ var nextjs = {
1809
2205
  routes: [{ source: "/*", destination: ".next/standalone/server.js" }],
1810
2206
  environmentVariables: { NODE_ENV: "production" }
1811
2207
  }),
1812
- refineDefaultConfig: (defaults, projectFolder) => Effect8.gen(function* () {
1813
- const fs = yield* FileSystem8.FileSystem;
1814
- const manifestContent = yield* fs.readFileString(`${projectFolder}/.gigadrive/nextjs.json`).pipe(Effect8.catchAll(() => Effect8.succeed(void 0)));
2208
+ refineDefaultConfig: (defaults, projectFolder) => Effect13.gen(function* () {
2209
+ const fs = yield* FileSystem11.FileSystem;
2210
+ const manifestContent = yield* fs.readFileString(`${projectFolder}/.gigadrive/nextjs.json`).pipe(Effect13.catchAll(() => Effect13.succeed(void 0)));
1815
2211
  const manifest = manifestContent ? parseGigadriveNextBuildManifest(manifestContent) : void 0;
1816
2212
  if (!manifest) return defaults;
1817
2213
  if (manifest.version === 2) {
@@ -1822,8 +2218,8 @@ var nextjs = {
1822
2218
  };
1823
2219
 
1824
2220
  // src/detection/frameworks/nuxt.ts
1825
- import { FileSystem as FileSystem9 } from "@effect/platform";
1826
- import { Effect as Effect9 } from "effect";
2221
+ import { FileSystem as FileSystem12 } from "@effect/platform";
2222
+ import { Effect as Effect14 } from "effect";
1827
2223
  var isVercelBuildOutputV3 = (content) => {
1828
2224
  try {
1829
2225
  const config = JSON.parse(content);
@@ -1850,9 +2246,9 @@ var nuxt = {
1850
2246
  routes: [{ source: "/*", destination: ".output/server/index.mjs" }],
1851
2247
  environmentVariables: { NODE_ENV: "production", NITRO_PRESET: "node-server" }
1852
2248
  }),
1853
- refineDefaultConfig: (defaults, projectFolder) => Effect9.gen(function* () {
1854
- const fs = yield* FileSystem9.FileSystem;
1855
- const buildOutputConfig = yield* fs.readFileString(`${projectFolder}/.vercel/output/config.json`).pipe(Effect9.catchAll(() => Effect9.succeed(void 0)));
2249
+ refineDefaultConfig: (defaults, projectFolder) => Effect14.gen(function* () {
2250
+ const fs = yield* FileSystem12.FileSystem;
2251
+ const buildOutputConfig = yield* fs.readFileString(`${projectFolder}/.vercel/output/config.json`).pipe(Effect14.catchAll(() => Effect14.succeed(void 0)));
1856
2252
  if (!buildOutputConfig || !isVercelBuildOutputV3(buildOutputConfig)) {
1857
2253
  return defaults;
1858
2254
  }
@@ -1867,16 +2263,16 @@ var nuxt = {
1867
2263
  };
1868
2264
 
1869
2265
  // src/detection/frameworks/php.ts
1870
- import { FileSystem as FileSystem10, Path as Path8 } from "@effect/platform";
1871
- import { Effect as Effect10 } from "effect";
2266
+ import { FileSystem as FileSystem13, Path as Path11 } from "@effect/platform";
2267
+ import { Effect as Effect15 } from "effect";
1872
2268
  var COMPOSER_FILES = ["composer.json", "composer.lock"];
1873
2269
  var DOCUMENT_ROOTS = ["public", "web", "webroot", "public_html", "htdocs", "."];
1874
- var refinePhpDocumentRoot = (defaults, projectFolder) => Effect10.gen(function* () {
1875
- const fs = yield* FileSystem10.FileSystem;
1876
- const pathService = yield* Path8.Path;
2270
+ var refinePhpDocumentRoot = (defaults, projectFolder) => Effect15.gen(function* () {
2271
+ const fs = yield* FileSystem13.FileSystem;
2272
+ const pathService = yield* Path11.Path;
1877
2273
  for (const documentRoot of DOCUMENT_ROOTS) {
1878
2274
  const frontController = pathService.join(projectFolder, documentRoot, "index.php");
1879
- if (yield* fs.exists(frontController).pipe(Effect10.catchAll(() => Effect10.succeed(false)))) {
2275
+ if (yield* fs.exists(frontController).pipe(Effect15.catchAll(() => Effect15.succeed(false)))) {
1880
2276
  return phpFrontControllerDefaults({ documentRoot, excludeFiles: COMPOSER_FILES });
1881
2277
  }
1882
2278
  }
@@ -1900,9 +2296,215 @@ var phpSites = DOCUMENT_ROOTS.map((documentRoot) => ({
1900
2296
  detectors: [{ path: frontControllerPath(documentRoot) }],
1901
2297
  priority: 6,
1902
2298
  getDefaultConfig: () => ({ ...getDefaultConfig(), installCommand: "" }),
1903
- refineDefaultConfig: (defaults, projectFolder) => refinePhpDocumentRoot(defaults, projectFolder).pipe(Effect10.map((refined) => ({ ...refined, installCommand: "" })))
2299
+ refineDefaultConfig: (defaults, projectFolder) => refinePhpDocumentRoot(defaults, projectFolder).pipe(Effect15.map((refined) => ({ ...refined, installCommand: "" })))
1904
2300
  }));
1905
2301
 
2302
+ // src/detection/frameworks/php-runtime.ts
2303
+ import { FileSystem as FileSystem14, Path as Path12 } from "@effect/platform";
2304
+ import { Effect as Effect16, Option as Option3 } from "effect";
2305
+
2306
+ // src/detection/frameworks/composer-constraint.ts
2307
+ var STABILITY_SUFFIX = /-(?:dev|alpha|beta|a|b|rc|patch|pl|p|stable)\.?\d*$/i;
2308
+ var parseVersion = (text) => {
2309
+ const parts = text.replace(/^v/i, "").replace(STABILITY_SUFFIX, "").split(".");
2310
+ if (parts.length > 4) {
2311
+ return void 0;
2312
+ }
2313
+ const segments = [];
2314
+ let wildcard = false;
2315
+ for (const part of parts) {
2316
+ if (/^[*x]$/i.test(part)) {
2317
+ wildcard = true;
2318
+ } else if (/^\d+$/.test(part) && !wildcard) {
2319
+ segments.push(Number(part));
2320
+ } else {
2321
+ return void 0;
2322
+ }
2323
+ }
2324
+ return { segments, wildcard };
2325
+ };
2326
+ var pad = (segments) => [segments[0] ?? 0, segments[1] ?? 0, segments[2] ?? 0, segments[3] ?? 0];
2327
+ var bump = (segments, position) => pad(segments.slice(0, position).map((segment, index) => index === position - 1 ? segment + 1 : segment));
2328
+ var compare = (a, b) => {
2329
+ for (let index = 0; index < 4; index++) {
2330
+ if (a[index] !== b[index]) {
2331
+ return a[index] - b[index];
2332
+ }
2333
+ }
2334
+ return 0;
2335
+ };
2336
+ var inRange = (version, lower, upper) => compare(version, lower) >= 0 && compare(version, upper) < 0;
2337
+ var allowsAtom = (atom, version) => {
2338
+ const match = /^(\^|~|>=|<=|<>|!=|==|=|>|<)?(.+)$/.exec(atom);
2339
+ const parsed = match ? parseVersion(match[2]) : void 0;
2340
+ if (!match || !parsed) {
2341
+ return void 0;
2342
+ }
2343
+ const operator = match[1];
2344
+ const { segments } = parsed;
2345
+ if (parsed.wildcard) {
2346
+ if (operator !== void 0) {
2347
+ return void 0;
2348
+ }
2349
+ return segments.length === 0 || inRange(version, pad(segments), bump(segments, segments.length));
2350
+ }
2351
+ const target = pad(segments);
2352
+ switch (operator) {
2353
+ case "^": {
2354
+ const position = segments[0] !== 0 || segments.length < 2 ? 1 : segments[1] !== 0 || segments.length < 3 ? 2 : 3;
2355
+ return inRange(version, target, bump(segments, position));
2356
+ }
2357
+ case "~":
2358
+ return inRange(version, target, bump(segments, Math.max(1, segments.length - 1)));
2359
+ case ">=":
2360
+ return compare(version, target) >= 0;
2361
+ case ">":
2362
+ return compare(version, target) > 0;
2363
+ case "<=":
2364
+ return compare(version, target) <= 0;
2365
+ case "<":
2366
+ return compare(version, target) < 0;
2367
+ case "!=":
2368
+ case "<>":
2369
+ return compare(version, target) !== 0;
2370
+ default:
2371
+ return compare(version, target) === 0;
2372
+ }
2373
+ };
2374
+ var allowsHyphenRange = (from, to, version) => {
2375
+ const lower = parseVersion(from);
2376
+ const upper = parseVersion(to);
2377
+ if (!lower || !upper || lower.wildcard || upper.wildcard) {
2378
+ return void 0;
2379
+ }
2380
+ const withinUpper = upper.segments.length >= 3 ? compare(version, pad(upper.segments)) <= 0 : compare(version, bump(upper.segments, upper.segments.length)) < 0;
2381
+ return compare(version, pad(lower.segments)) >= 0 && withinUpper;
2382
+ };
2383
+ var allowsAll = (branch, version) => {
2384
+ const tokens = branch.trim().replace(/([<>=!~^]+)\s+/g, "$1").split(/\s*,\s*|\s+/).filter((token) => token !== "");
2385
+ if (tokens.length === 0) {
2386
+ return void 0;
2387
+ }
2388
+ let allowed = true;
2389
+ for (let index = 0; index < tokens.length; index++) {
2390
+ let result;
2391
+ if (tokens[index + 1] === "-") {
2392
+ const to = tokens[index + 2];
2393
+ result = to === void 0 ? void 0 : allowsHyphenRange(tokens[index], to, version);
2394
+ index += 2;
2395
+ } else {
2396
+ result = allowsAtom(tokens[index], version);
2397
+ }
2398
+ if (result === void 0) {
2399
+ return void 0;
2400
+ }
2401
+ allowed &&= result;
2402
+ }
2403
+ return allowed;
2404
+ };
2405
+ var composerConstraintAllows = (constraint, version) => {
2406
+ const parsed = parseVersion(version);
2407
+ if (!parsed || parsed.wildcard || parsed.segments.length === 0) {
2408
+ return void 0;
2409
+ }
2410
+ const target = pad(parsed.segments);
2411
+ let allowed = false;
2412
+ for (const branch of constraint.replace(/@[a-z]+/gi, "").split(/\|\|?/)) {
2413
+ const result = allowsAll(branch, target);
2414
+ if (result === void 0) {
2415
+ return void 0;
2416
+ }
2417
+ allowed ||= result;
2418
+ }
2419
+ return allowed;
2420
+ };
2421
+
2422
+ // src/detection/frameworks/php-runtime.ts
2423
+ var PHP_RUNTIME_CANDIDATES = [
2424
+ { runtime: "php-84", newestVersion: "8.4.9999" },
2425
+ { runtime: "php-83", newestVersion: "8.3.9999" }
2426
+ ];
2427
+ var phpRuntimeForConstraint = (constraint) => PHP_RUNTIME_CANDIDATES.find(({ newestVersion }) => composerConstraintAllows(constraint, newestVersion) === true)?.runtime;
2428
+ var readPhpConstraint = Effect16.fn("readPhpConstraint")(
2429
+ function* (projectFolder) {
2430
+ const fs = yield* FileSystem14.FileSystem;
2431
+ const pathService = yield* Path12.Path;
2432
+ const content = yield* fs.readFileString(pathService.join(projectFolder, "composer.json"));
2433
+ const manifest = yield* Effect16.try(() => JSON.parse(content));
2434
+ const requires = manifest && typeof manifest === "object" && "require" in manifest ? manifest.require : void 0;
2435
+ const php = requires && typeof requires === "object" && "php" in requires ? requires.php : void 0;
2436
+ return typeof php === "string" ? Option3.some(php) : Option3.none();
2437
+ },
2438
+ Effect16.catchAll(() => Effect16.succeed(Option3.none()))
2439
+ );
2440
+ var refineComposerPhpRuntime = Effect16.fn("refineComposerPhpRuntime")(function* (defaults, projectFolder) {
2441
+ const constraint = yield* readPhpConstraint(projectFolder);
2442
+ const runtime = Option3.getOrUndefined(Option3.flatMapNullable(constraint, phpRuntimeForConstraint));
2443
+ return runtime ? { ...defaults, runtime } : defaults;
2444
+ });
2445
+ var withComposerPhpRuntime = (framework) => ({
2446
+ ...framework,
2447
+ refineDefaultConfig: (defaults, projectFolder) => Effect16.gen(function* () {
2448
+ const refined = framework.refineDefaultConfig ? yield* framework.refineDefaultConfig(defaults, projectFolder) : defaults;
2449
+ return yield* refineComposerPhpRuntime(refined, projectFolder);
2450
+ })
2451
+ });
2452
+
2453
+ // src/detection/frameworks/rack.ts
2454
+ var rack = {
2455
+ slug: "rack",
2456
+ name: "Rack",
2457
+ language: "ruby",
2458
+ detectors: [{ path: "config.ru" }, { path: "Gemfile" }],
2459
+ priority: 10,
2460
+ getDefaultConfig: () => rubyServerDefaults({ environmentVariables: { RACK_ENV: "production" } }),
2461
+ refineDefaultConfig: refineRubyPublicDirectory
2462
+ };
2463
+
2464
+ // src/detection/frameworks/rails.ts
2465
+ import { Effect as Effect17 } from "effect";
2466
+ var ASSET_PIPELINE_GEMS = ["propshaft", "sprockets", "sprockets-rails"];
2467
+ var refineRailsAssets = Effect17.fn("refineRailsAssets")(function* (defaults, projectFolder) {
2468
+ const gems = yield* readDependencies(projectFolder, "ruby").pipe(
2469
+ Effect17.catchAll(() => Effect17.succeed(/* @__PURE__ */ new Set()))
2470
+ );
2471
+ const withPublicDirectory = yield* refineRubyPublicDirectory(defaults, projectFolder);
2472
+ return ASSET_PIPELINE_GEMS.some((gem) => gems.has(gem)) ? {
2473
+ ...withPublicDirectory,
2474
+ commands: [...withPublicDirectory.commands, "SECRET_KEY_BASE_DUMMY=1 bundle exec rails assets:precompile"]
2475
+ } : withPublicDirectory;
2476
+ });
2477
+ var rails = {
2478
+ slug: "rails",
2479
+ name: "Ruby on Rails",
2480
+ language: "ruby",
2481
+ // `railties` is in every Rails application's Gemfile.lock, including ones
2482
+ // that require individual Rails gems instead of `rails`.
2483
+ detectors: [{ matchPackage: "railties" }, { path: "config/application.rb" }],
2484
+ priority: 80,
2485
+ getDefaultConfig: () => rubyServerDefaults({
2486
+ memory: 512,
2487
+ excludeFiles: ["tmp/", "log/", "storage/", "test/", "spec/", "node_modules/", ".git/"],
2488
+ // tmp/, log/ and storage/ are excluded, so the directories Rails writes
2489
+ // caches, pids, sockets, logs and Active Storage files to are created empty.
2490
+ writablePaths: ["tmp/cache", "tmp/pids", "tmp/sockets", "tmp/storage", "log", "storage"],
2491
+ environmentVariables: {
2492
+ RAILS_ENV: "production",
2493
+ RACK_ENV: "production",
2494
+ // Signs and encrypts cookies and sessions; Rails refuses to boot in production without it.
2495
+ SECRET_KEY_BASE: generatedSecret("hex"),
2496
+ RAILS_LOG_TO_STDOUT: "1",
2497
+ RAILS_SERVE_STATIC_FILES: "1",
2498
+ RAILS_MAX_THREADS: "5"
2499
+ }
2500
+ }),
2501
+ refineDefaultConfig: refineRailsAssets
2502
+ };
2503
+ var railsPresets = [
2504
+ rails,
2505
+ { ...rails, detectors: [{ matchPackage: "rails" }, { path: "config/application.rb" }] }
2506
+ ];
2507
+
1906
2508
  // src/detection/frameworks/remix.ts
1907
2509
  var remix = {
1908
2510
  slug: "remix",
@@ -1924,6 +2526,45 @@ var remix = {
1924
2526
  })
1925
2527
  };
1926
2528
 
2529
+ // src/detection/frameworks/roda.ts
2530
+ var roda = {
2531
+ slug: "roda",
2532
+ name: "Roda",
2533
+ language: "ruby",
2534
+ detectors: [{ matchPackage: "roda" }, { path: "config.ru" }],
2535
+ priority: 60,
2536
+ getDefaultConfig: () => rubyServerDefaults({ environmentVariables: { RACK_ENV: "production" } }),
2537
+ refineDefaultConfig: refineRubyPublicDirectory
2538
+ };
2539
+
2540
+ // src/detection/frameworks/sinatra.ts
2541
+ import { FileSystem as FileSystem15, Path as Path13 } from "@effect/platform";
2542
+ import { Effect as Effect18 } from "effect";
2543
+ var SINATRA_ENTRYPOINTS = ["config.ru", "app.rb", "main.rb", "server.rb", "application.rb"];
2544
+ var refineSinatraEntrypoint = Effect18.fn("refineSinatraEntrypoint")(function* (defaults, projectFolder) {
2545
+ const fs = yield* FileSystem15.FileSystem;
2546
+ const pathService = yield* Path13.Path;
2547
+ const entrypoint = yield* Effect18.findFirst(
2548
+ SINATRA_ENTRYPOINTS,
2549
+ (file) => fs.exists(pathService.join(projectFolder, file)).pipe(Effect18.catchAll(() => Effect18.succeed(false)))
2550
+ );
2551
+ const withPublicDirectory = yield* refineRubyPublicDirectory(defaults, projectFolder);
2552
+ return entrypoint._tag === "Some" ? {
2553
+ ...withPublicDirectory,
2554
+ entrypoint: entrypoint.value,
2555
+ routes: [{ source: "/*", destination: entrypoint.value }]
2556
+ } : withPublicDirectory;
2557
+ });
2558
+ var sinatra = {
2559
+ slug: "sinatra",
2560
+ name: "Sinatra",
2561
+ language: "ruby",
2562
+ detectors: [{ matchPackage: "sinatra" }],
2563
+ priority: 60,
2564
+ getDefaultConfig: () => rubyServerDefaults({ environmentVariables: { APP_ENV: "production", RACK_ENV: "production" } }),
2565
+ refineDefaultConfig: refineSinatraEntrypoint
2566
+ };
2567
+
1927
2568
  // src/detection/frameworks/slim.ts
1928
2569
  var slim = {
1929
2570
  slug: "slim",
@@ -2044,17 +2685,33 @@ var FRAMEWORK_DEFINITIONS = [
2044
2685
  mezzio,
2045
2686
  yii,
2046
2687
  slim,
2688
+ ...railsPresets,
2689
+ hanami,
2690
+ ...jekyllPresets,
2691
+ bridgetown,
2692
+ sinatra,
2693
+ roda,
2047
2694
  hono,
2048
2695
  elysia,
2049
2696
  fastify,
2050
2697
  express,
2698
+ rack,
2051
2699
  ...phpComposerProjects,
2052
2700
  ...phpSites,
2053
2701
  vite
2054
- ].sort((a, b) => b.priority - a.priority);
2702
+ ].map((framework) => {
2703
+ switch (framework.language) {
2704
+ case "php":
2705
+ return withComposerPhpRuntime(framework);
2706
+ case "ruby":
2707
+ return withRubyRuntime(framework);
2708
+ case "node":
2709
+ return framework;
2710
+ }
2711
+ }).sort((a, b) => b.priority - a.priority);
2055
2712
 
2056
2713
  // src/detection/generate-config.ts
2057
- import { Effect as Effect11 } from "effect";
2714
+ import { Effect as Effect19 } from "effect";
2058
2715
  var getInstallCommand = (pm) => {
2059
2716
  switch (pm) {
2060
2717
  case "bun":
@@ -2065,6 +2722,8 @@ var getInstallCommand = (pm) => {
2065
2722
  return "yarn install";
2066
2723
  case "composer":
2067
2724
  return "composer install";
2725
+ case "bundler":
2726
+ return "bundle install";
2068
2727
  case "npm":
2069
2728
  default:
2070
2729
  return "npm install";
@@ -2075,11 +2734,17 @@ var isPrivatePhpProjectFile = (projectPath) => {
2075
2734
  const segments = projectPath.split("/").filter((segment) => segment !== "" && segment !== ".");
2076
2735
  return segments.some((segment) => segment.startsWith(".")) || segments[0] === "vendor" || segments[0] === "node_modules" || segments.length === 1 && COMPOSER_ROOT_FILES.has(segments[0] ?? "");
2077
2736
  };
2078
- var generateConfig = Effect11.fn("generateConfig")(function* (framework, packageManager, projectFolder, refinedDefaults) {
2737
+ var BUNDLER_FILES = /* @__PURE__ */ new Set(["Gemfile", "Gemfile.lock", "gems.rb", "gems.locked"]);
2738
+ var isPrivateRubyProjectFile = (projectPath) => {
2739
+ const segments = projectPath.split("/").filter((segment) => segment !== "" && segment !== ".");
2740
+ const fileName = segments.at(-1) ?? "";
2741
+ return segments.some((segment) => segment.startsWith(".")) || segments[0] === "vendor" || /\.(rb|ru)$/i.test(fileName) || BUNDLER_FILES.has(fileName);
2742
+ };
2743
+ var generateConfig = Effect19.fn("generateConfig")(function* (framework, packageManager, projectFolder, refinedDefaults) {
2079
2744
  const defaults = refinedDefaults ?? framework.getDefaultConfig(packageManager);
2080
2745
  const installCmd = defaults.installCommand ?? getInstallCommand(packageManager);
2081
2746
  const commands = installCmd ? [installCmd, ...defaults.commands] : [...defaults.commands];
2082
- yield* Effect11.logDebug(`Generating config for ${framework.name}`, {
2747
+ yield* Effect19.logDebug(`Generating config for ${framework.name}`, {
2083
2748
  runtime: defaults.runtime,
2084
2749
  entrypoint: defaults.entrypoint,
2085
2750
  commands
@@ -2122,6 +2787,7 @@ var generateConfig = Effect11.fn("generateConfig")(function* (framework, package
2122
2787
  for (const file of yield* collectAssetFiles(projectFolder, assetsDir)) {
2123
2788
  if (framework.language === "php" && /\.(php|phtml|phar)$/i.test(file)) continue;
2124
2789
  if (framework.language === "php" && isPrivatePhpProjectFile(`${assetsDir}/${file}`)) continue;
2790
+ if (framework.language === "ruby" && isPrivateRubyProjectFile(`${assetsDir}/${file}`)) continue;
2125
2791
  paths.push(`${assetsDir}/${file}`);
2126
2792
  if (!servesDirectoryIndexes || file in overrides) continue;
2127
2793
  if (file === "index.html") {
@@ -2144,80 +2810,10 @@ var generateConfig = Effect11.fn("generateConfig")(function* (framework, package
2144
2810
  return config;
2145
2811
  });
2146
2812
 
2147
- // src/detection/read-dependencies.ts
2148
- import { FileSystem as FileSystem11, Path as Path9 } from "@effect/platform";
2149
- import { Effect as Effect13 } from "effect";
2150
-
2151
- // src/detection/types.ts
2152
- import { Schema as Schema5 } from "effect";
2153
- var ManifestNotFoundError = class extends Schema5.TaggedError()("ManifestNotFoundError", {
2154
- message: Schema5.String,
2155
- filePath: Schema5.String
2156
- }) {
2157
- };
2158
- var ManifestReadError = class extends Schema5.TaggedError()("ManifestReadError", {
2159
- message: Schema5.String,
2160
- filePath: Schema5.String
2161
- }) {
2162
- };
2163
- var ManifestParseError = class extends Schema5.TaggedError()("ManifestParseError", {
2164
- message: Schema5.String,
2165
- filePath: Schema5.String
2166
- }) {
2167
- };
2168
- var FrameworkNotDetectedError = class extends Schema5.TaggedError()(
2169
- "FrameworkNotDetectedError",
2170
- {
2171
- message: Schema5.String,
2172
- directory: Schema5.String
2173
- }
2174
- ) {
2175
- };
2176
-
2177
- // src/detection/read-dependencies.ts
2178
- var MANIFEST_CONFIG = {
2179
- node: { file: "package.json", depKeys: ["dependencies", "devDependencies"] },
2180
- php: { file: "composer.json", depKeys: ["require", "require-dev"] }
2181
- };
2182
- var readManifest = Effect13.fn("readManifest")(function* (filePath) {
2183
- const fs = yield* FileSystem11.FileSystem;
2184
- const exists = yield* fs.exists(filePath).pipe(Effect13.catchAll(() => Effect13.succeed(false)));
2185
- if (!exists) {
2186
- return yield* Effect13.fail(new ManifestNotFoundError({ message: "Manifest not found", filePath }));
2187
- }
2188
- const content = yield* fs.readFileString(filePath).pipe(Effect13.mapError(() => new ManifestReadError({ message: "Failed to read manifest", filePath })));
2189
- const parsed = yield* Effect13.try({
2190
- try: () => JSON.parse(content),
2191
- catch: () => new ManifestParseError({ message: "Failed to parse manifest JSON", filePath })
2192
- });
2193
- return parsed;
2194
- });
2195
- var readDependencies = Effect13.fn("readDependencies")(function* (projectFolder, language) {
2196
- const pathService = yield* Path9.Path;
2197
- const config = MANIFEST_CONFIG[language];
2198
- const filePath = pathService.join(projectFolder, config.file);
2199
- const manifest = yield* readManifest(filePath).pipe(
2200
- Effect13.catchTag("ManifestNotFoundError", () => Effect13.succeed(null))
2201
- );
2202
- if (!manifest) {
2203
- return /* @__PURE__ */ new Set();
2204
- }
2205
- const deps = /* @__PURE__ */ new Set();
2206
- for (const key of config.depKeys) {
2207
- const section = manifest[key];
2208
- if (section && typeof section === "object" && !Array.isArray(section)) {
2209
- for (const name of Object.keys(section)) {
2210
- deps.add(name);
2211
- }
2212
- }
2213
- }
2214
- return deps;
2215
- });
2216
-
2217
2813
  // src/detection/detect-framework.ts
2218
- var matchesDetectionItem = Effect14.fn("matchesDetectionItem")(function* (item, projectFolder, framework, cachedReadDeps) {
2219
- const fs = yield* FileSystem12.FileSystem;
2220
- const pathService = yield* Path10.Path;
2814
+ var matchesDetectionItem = Effect20.fn("matchesDetectionItem")(function* (item, projectFolder, framework, cachedReadDeps) {
2815
+ const fs = yield* FileSystem16.FileSystem;
2816
+ const pathService = yield* Path14.Path;
2221
2817
  if (item.matchPackage != null) {
2222
2818
  const deps = yield* cachedReadDeps(`${projectFolder}\0${framework.language}`);
2223
2819
  if (!deps.has(item.matchPackage)) {
@@ -2226,12 +2822,12 @@ var matchesDetectionItem = Effect14.fn("matchesDetectionItem")(function* (item,
2226
2822
  }
2227
2823
  if (item.path != null) {
2228
2824
  const filePath = pathService.join(projectFolder, item.path);
2229
- const exists = yield* fs.exists(filePath).pipe(Effect14.catchAll(() => Effect14.succeed(false)));
2825
+ const exists = yield* fs.exists(filePath).pipe(Effect20.catchAll(() => Effect20.succeed(false)));
2230
2826
  if (!exists) {
2231
2827
  return false;
2232
2828
  }
2233
2829
  if (item.matchContent != null) {
2234
- const content = yield* fs.readFileString(filePath).pipe(Effect14.catchAll(() => Effect14.succeed("")));
2830
+ const content = yield* fs.readFileString(filePath).pipe(Effect20.catchAll(() => Effect20.succeed("")));
2235
2831
  let regexMatch = false;
2236
2832
  try {
2237
2833
  regexMatch = new RegExp(item.matchContent).test(content);
@@ -2244,7 +2840,7 @@ var matchesDetectionItem = Effect14.fn("matchesDetectionItem")(function* (item,
2244
2840
  }
2245
2841
  return true;
2246
2842
  });
2247
- var matchesFramework = Effect14.fn("matchesFramework")(function* (framework, projectFolder, cachedReadDeps) {
2843
+ var matchesFramework = Effect20.fn("matchesFramework")(function* (framework, projectFolder, cachedReadDeps) {
2248
2844
  for (const detector of framework.detectors) {
2249
2845
  const matches = yield* matchesDetectionItem(detector, projectFolder, framework, cachedReadDeps);
2250
2846
  if (!matches) {
@@ -2253,9 +2849,19 @@ var matchesFramework = Effect14.fn("matchesFramework")(function* (framework, pro
2253
2849
  }
2254
2850
  return true;
2255
2851
  });
2256
- var detectFramework = Effect14.fn("detectFramework")(function* (projectFolder) {
2257
- yield* Effect14.logDebug(`Detecting framework in ${projectFolder}`);
2258
- const cachedReadDeps = yield* Effect14.cachedFunction((key) => {
2852
+ var packageManagerForLanguage = (language, detected) => {
2853
+ switch (language) {
2854
+ case "php":
2855
+ return "composer";
2856
+ case "ruby":
2857
+ return "bundler";
2858
+ case "node":
2859
+ return detected === "bundler" ? "npm" : detected;
2860
+ }
2861
+ };
2862
+ var detectFramework = Effect20.fn("detectFramework")(function* (projectFolder) {
2863
+ yield* Effect20.logDebug(`Detecting framework in ${projectFolder}`);
2864
+ const cachedReadDeps = yield* Effect20.cachedFunction((key) => {
2259
2865
  const sepIndex = key.lastIndexOf("\0");
2260
2866
  const folder = key.slice(0, sepIndex);
2261
2867
  const language = key.slice(sepIndex + 1);
@@ -2264,16 +2870,16 @@ var detectFramework = Effect14.fn("detectFramework")(function* (projectFolder) {
2264
2870
  for (const framework of FRAMEWORK_DEFINITIONS) {
2265
2871
  const matches = yield* matchesFramework(framework, projectFolder, cachedReadDeps);
2266
2872
  if (matches) {
2267
- yield* Effect14.log(`Detected framework: ${framework.name}`, { slug: framework.slug });
2873
+ yield* Effect20.log(`Detected framework: ${framework.name}`, { slug: framework.slug });
2268
2874
  const detectedPackageManager = yield* detectPackageManager(projectFolder);
2269
- const packageManager = framework.language === "php" ? "composer" : detectedPackageManager;
2875
+ const packageManager = packageManagerForLanguage(framework.language, detectedPackageManager);
2270
2876
  const defaults = framework.getDefaultConfig(packageManager);
2271
2877
  const refinedDefaults = framework.refineDefaultConfig ? yield* framework.refineDefaultConfig(defaults, projectFolder) : defaults;
2272
2878
  const config = yield* generateConfig(framework, packageManager, projectFolder, refinedDefaults);
2273
2879
  return { framework, packageManager, config };
2274
2880
  }
2275
2881
  }
2276
- return yield* Effect14.fail(
2882
+ return yield* Effect20.fail(
2277
2883
  new FrameworkNotDetectedError({
2278
2884
  message: `No framework detected in project directory`,
2279
2885
  directory: projectFolder
@@ -2282,9 +2888,9 @@ var detectFramework = Effect14.fn("detectFramework")(function* (projectFolder) {
2282
2888
  });
2283
2889
 
2284
2890
  // src/detection/merge-config.ts
2285
- import { Effect as Effect15 } from "effect";
2286
- var mergeWithFrameworkDefaults = Effect15.fn("mergeWithFrameworkDefaults")(function* (userConfig, frameworkConfig) {
2287
- yield* Effect15.logDebug("Merging user config with framework defaults");
2891
+ import { Effect as Effect21 } from "effect";
2892
+ var mergeWithFrameworkDefaults = Effect21.fn("mergeWithFrameworkDefaults")(function* (userConfig, frameworkConfig) {
2893
+ yield* Effect21.logDebug("Merging user config with framework defaults");
2288
2894
  const userHasAssets = (userConfig.assets?.paths?.length ?? 0) > 0 || (userConfig.assets?.prefixes?.length ?? 0) > 0 || (userConfig.assets?.manifests?.length ?? 0) > 0;
2289
2895
  const isContainer = (entrypoint) => entrypoint.runtime === CONTAINER_RUNTIME;
2290
2896
  const userFileFunctions = userConfig.entrypoints.filter((entrypoint) => !isContainer(entrypoint));
@@ -2325,23 +2931,23 @@ var filterFunctionsFromAssets = (config) => {
2325
2931
  };
2326
2932
 
2327
2933
  // src/parse-config.ts
2328
- import { Effect as Effect21 } from "effect";
2934
+ import { Effect as Effect27 } from "effect";
2329
2935
 
2330
2936
  // src/services/raw-config-reader.ts
2331
- import { FileSystem as FileSystem13, Path as Path11 } from "@effect/platform";
2332
- import { Effect as Effect17 } from "effect";
2937
+ import { FileSystem as FileSystem17, Path as Path15 } from "@effect/platform";
2938
+ import { Effect as Effect23 } from "effect";
2333
2939
  import { parse as parseYaml2 } from "yaml";
2334
2940
 
2335
2941
  // src/services/config-module-loader.ts
2336
- import { Effect as Effect16 } from "effect";
2942
+ import { Effect as Effect22 } from "effect";
2337
2943
  import { createJiti } from "jiti";
2338
2944
  var MISSING_DEFAULT_EXPORT = /* @__PURE__ */ Symbol("MissingDefaultExport");
2339
2945
  var STRICT_DEFAULT_EXPORT_EXTENSIONS = [".ts", ".mts", ".mjs"];
2340
- var ConfigModuleLoader = class extends Effect16.Service()("ConfigModuleLoader", {
2341
- effect: Effect16.gen(function* () {
2342
- const loadConfigModule = Effect16.fn("ConfigModuleLoader.loadConfigModule")(function* (filePath) {
2946
+ var ConfigModuleLoader = class extends Effect22.Service()("ConfigModuleLoader", {
2947
+ effect: Effect22.gen(function* () {
2948
+ const loadConfigModule = Effect22.fn("ConfigModuleLoader.loadConfigModule")(function* (filePath) {
2343
2949
  const extension = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
2344
- const mod = yield* Effect16.tryPromise({
2950
+ const mod = yield* Effect22.tryPromise({
2345
2951
  try: async () => {
2346
2952
  const jiti = createJiti(filePath, { fsCache: false, interopDefault: true, moduleCache: false });
2347
2953
  const namespace = await jiti.import(filePath);
@@ -2360,7 +2966,7 @@ var ConfigModuleLoader = class extends Effect16.Service()("ConfigModuleLoader",
2360
2966
  })
2361
2967
  });
2362
2968
  if (mod === MISSING_DEFAULT_EXPORT) {
2363
- return yield* Effect16.fail(
2969
+ return yield* Effect22.fail(
2364
2970
  new ConfigModuleLoadError({
2365
2971
  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.`,
2366
2972
  filePath
@@ -2368,7 +2974,7 @@ var ConfigModuleLoader = class extends Effect16.Service()("ConfigModuleLoader",
2368
2974
  );
2369
2975
  }
2370
2976
  if (typeof mod === "function") {
2371
- return yield* Effect16.fail(
2977
+ return yield* Effect22.fail(
2372
2978
  new ConfigModuleLoadError({
2373
2979
  message: `Config module at ${filePath} default-exports a function; config factories are not supported. Export a config object instead (optionally wrapped in defineConfig).`,
2374
2980
  filePath
@@ -2376,7 +2982,7 @@ var ConfigModuleLoader = class extends Effect16.Service()("ConfigModuleLoader",
2376
2982
  );
2377
2983
  }
2378
2984
  if (typeof mod !== "object" || mod === null || Array.isArray(mod)) {
2379
- return yield* Effect16.fail(
2985
+ return yield* Effect22.fail(
2380
2986
  new ConfigModuleLoadError({
2381
2987
  message: `Config module at ${filePath} must default-export a config object.`,
2382
2988
  filePath
@@ -2406,36 +3012,36 @@ var ALLOWED_CONFIG_NAMES = [
2406
3012
  "nebula.json"
2407
3013
  ];
2408
3014
  var MODULE_EXTENSIONS = [".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"];
2409
- var RawConfigReader = class extends Effect17.Service()("RawConfigReader", {
3015
+ var RawConfigReader = class extends Effect23.Service()("RawConfigReader", {
2410
3016
  dependencies: [ConfigModuleLoader.Default],
2411
- effect: Effect17.gen(function* () {
2412
- const fs = yield* FileSystem13.FileSystem;
2413
- const pathService = yield* Path11.Path;
3017
+ effect: Effect23.gen(function* () {
3018
+ const fs = yield* FileSystem17.FileSystem;
3019
+ const pathService = yield* Path15.Path;
2414
3020
  const moduleLoader = yield* ConfigModuleLoader;
2415
- const findConfig = Effect17.fn("RawConfigReader.findConfig")(function* (projectFolder) {
3021
+ const findConfig = Effect23.fn("RawConfigReader.findConfig")(function* (projectFolder) {
2416
3022
  for (const name of ALLOWED_CONFIG_NAMES) {
2417
3023
  const filePath = pathService.join(projectFolder, name);
2418
- const exists = yield* fs.exists(filePath).pipe(Effect17.catchAll(() => Effect17.succeed(false)));
3024
+ const exists = yield* fs.exists(filePath).pipe(Effect23.catchAll(() => Effect23.succeed(false)));
2419
3025
  if (exists) {
2420
3026
  return filePath;
2421
3027
  }
2422
3028
  }
2423
3029
  return null;
2424
3030
  });
2425
- const readRawConfig = Effect17.fn("RawConfigReader.readRawConfig")(function* (filePath, options) {
2426
- const exists = yield* fs.exists(filePath).pipe(Effect17.catchAll(() => Effect17.succeed(false)));
3031
+ const readRawConfig = Effect23.fn("RawConfigReader.readRawConfig")(function* (filePath, options) {
3032
+ const exists = yield* fs.exists(filePath).pipe(Effect23.catchAll(() => Effect23.succeed(false)));
2427
3033
  if (!exists) {
2428
- return yield* Effect17.fail(
3034
+ return yield* Effect23.fail(
2429
3035
  new ConfigFileNotFoundError({ message: `Config file not found at ${filePath}`, filePath })
2430
3036
  );
2431
3037
  }
2432
3038
  const fileContents = yield* fs.readFileString(filePath).pipe(
2433
- Effect17.mapError(
3039
+ Effect23.mapError(
2434
3040
  () => new ConfigFileParseError({ message: `Failed to read config file at ${filePath}`, filePath })
2435
3041
  )
2436
3042
  );
2437
3043
  if (fileContents.length === 0) {
2438
- return yield* Effect17.fail(
3044
+ return yield* Effect23.fail(
2439
3045
  new ConfigFileEmptyError({ message: `Config file is empty at ${filePath}`, filePath })
2440
3046
  );
2441
3047
  }
@@ -2451,7 +3057,7 @@ var RawConfigReader = class extends Effect17.Service()("RawConfigReader", {
2451
3057
  parsed = parseYaml2(fileContents);
2452
3058
  }
2453
3059
  } catch (error) {
2454
- return yield* Effect17.fail(
3060
+ return yield* Effect23.fail(
2455
3061
  new ConfigFileParseError({
2456
3062
  message: `Failed to parse config file at ${filePath}: ${error instanceof Error ? error.message : "Unknown error"}`,
2457
3063
  filePath,
@@ -2461,21 +3067,21 @@ var RawConfigReader = class extends Effect17.Service()("RawConfigReader", {
2461
3067
  }
2462
3068
  }
2463
3069
  if (parsed == null) {
2464
- return yield* Effect17.fail(
3070
+ return yield* Effect23.fail(
2465
3071
  new ConfigFileParseError({ message: `Config file could not be parsed at ${filePath}`, filePath })
2466
3072
  );
2467
3073
  }
2468
3074
  if (!options?.disableVersionCheck && typeof parsed.version !== "number") {
2469
- return yield* Effect17.fail(
3075
+ return yield* Effect23.fail(
2470
3076
  new ConfigVersionError({ message: `Config file is missing version at ${filePath}`, filePath })
2471
3077
  );
2472
3078
  }
2473
3079
  return parsed;
2474
3080
  });
2475
3081
  const readConfigFile = (configFilePath) => readRawConfig(configFilePath, { disableVersionCheck: true }).pipe(
2476
- Effect17.map((parsed) => parsed),
2477
- Effect17.catchTag("ConfigFileNotFoundError", () => Effect17.succeed(null)),
2478
- Effect17.withSpan("RawConfigReader.readConfigFile")
3082
+ Effect23.map((parsed) => parsed),
3083
+ Effect23.catchTag("ConfigFileNotFoundError", () => Effect23.succeed(null)),
3084
+ Effect23.withSpan("RawConfigReader.readConfigFile")
2479
3085
  );
2480
3086
  return { findConfig, readRawConfig, readConfigFile };
2481
3087
  })
@@ -2485,17 +3091,17 @@ var RawConfigReader = class extends Effect17.Service()("RawConfigReader", {
2485
3091
  // src/services/schema-validator.ts
2486
3092
  import Ajv from "ajv";
2487
3093
  import addFormats from "ajv-formats";
2488
- import { Effect as Effect18 } from "effect";
2489
- var SchemaValidator = class extends Effect18.Service()("SchemaValidator", {
2490
- effect: Effect18.gen(function* () {
3094
+ import { Effect as Effect24 } from "effect";
3095
+ var SchemaValidator = class extends Effect24.Service()("SchemaValidator", {
3096
+ effect: Effect24.gen(function* () {
2491
3097
  const ajv = new Ajv();
2492
3098
  addFormats(ajv);
2493
- const validate = Effect18.fn("SchemaValidator.validate")(function* (config, schema, filePath) {
3099
+ const validate = Effect24.fn("SchemaValidator.validate")(function* (config, schema, filePath) {
2494
3100
  const compiledValidate = ajv.compile(schema);
2495
3101
  const valid = compiledValidate(config);
2496
3102
  if (!valid) {
2497
3103
  const errors = compiledValidate.errors?.map((e) => `${e.instancePath || "/"} ${e.message ?? ""}`.trim()) ?? [];
2498
- return yield* Effect18.fail(
3104
+ return yield* Effect24.fail(
2499
3105
  new ConfigSchemaValidationError({
2500
3106
  message: `Config file at ${filePath} is invalid: ${ajv.errorsText(compiledValidate.errors)}`,
2501
3107
  filePath,
@@ -2551,7 +3157,7 @@ var getFilesForPattern = async (pattern, projectFolder, excludeFiles = []) => {
2551
3157
  };
2552
3158
 
2553
3159
  // src/services/v4-config-parser.ts
2554
- import { Effect as Effect19 } from "effect";
3160
+ import { Effect as Effect25 } from "effect";
2555
3161
  import { minimatch as minimatch2 } from "minimatch";
2556
3162
  import { posix as posix2 } from "path";
2557
3163
  import safeRegex from "safe-regex2";
@@ -2567,7 +3173,7 @@ var toArray = (value) => {
2567
3173
  if (value == null) return void 0;
2568
3174
  return Array.isArray(value) ? value : [value];
2569
3175
  };
2570
- var runtimeStreamsByDefault = (runtime) => runtime == null || runtime.startsWith("node-") || runtime.startsWith("bun-");
3176
+ var runtimeStreamsByDefault = (runtime) => runtime == null || runtime.startsWith("node-") || runtime.startsWith("bun-") || runtime.startsWith("ruby-");
2571
3177
  var normalizeImagePolicy = (images) => {
2572
3178
  if (!images) return void 0;
2573
3179
  return {
@@ -2702,7 +3308,7 @@ var mapRoute = (route, entrypoints) => ({
2702
3308
  negativeRequirements: route.missing,
2703
3309
  status: route.statusCode
2704
3310
  });
2705
- var parseEntrypoints = Effect19.fn("parseEntrypoints")(function* (config, projectFolder) {
3311
+ var parseEntrypoints = Effect25.fn("parseEntrypoints")(function* (config, projectFolder) {
2706
3312
  const entrypoints = [];
2707
3313
  const dockerFunctions = [];
2708
3314
  if (config.functions == null) return { entrypoints, dockerFunctions };
@@ -2713,7 +3319,7 @@ var parseEntrypoints = Effect19.fn("parseEntrypoints")(function* (config, projec
2713
3319
  functionPath: fnPath
2714
3320
  });
2715
3321
  }
2716
- const matchedFiles = yield* Effect19.tryPromise({
3322
+ const matchedFiles = yield* Effect25.tryPromise({
2717
3323
  try: () => getFilesForPattern(fnPath, projectFolder, func.excludeFiles),
2718
3324
  catch: (error) => new FunctionConfigError({
2719
3325
  message: `Failed to resolve files for function pattern '${fnPath}': ${error instanceof Error ? error.message : String(error)}`,
@@ -2788,13 +3394,13 @@ var parseEntrypoints = Effect19.fn("parseEntrypoints")(function* (config, projec
2788
3394
  }
2789
3395
  return { entrypoints, dockerFunctions };
2790
3396
  });
2791
- var collectAssets = Effect19.fn("collectAssets")(function* (config, projectFolder) {
3397
+ var collectAssets = Effect25.fn("collectAssets")(function* (config, projectFolder) {
2792
3398
  if (config.assets == null) return [];
2793
3399
  const assetNames = yield* collectAssetFiles(projectFolder, config.assets);
2794
3400
  return assetNames.filter((assetName) => getFunctionSettings(`${config.assets}/${assetName}`, config) == null).map((assetName) => `${config.assets}/${assetName}`);
2795
3401
  });
2796
3402
  var reservedRuntimePorts = (entrypoint) => entrypoint.runtime === CONTAINER_RUNTIME ? [] : entrypoint.runtime.startsWith("php-") ? [8080, 9e3] : [8080];
2797
- var parseContainers = Effect19.fn("parseContainers")(function* (config, projectFolder, fileEntrypoints, dockerFunctions) {
3403
+ var parseContainers = Effect25.fn("parseContainers")(function* (config, projectFolder, fileEntrypoints, dockerFunctions) {
2798
3404
  const warnings = [];
2799
3405
  let containers = {};
2800
3406
  if (config.compose != null) {
@@ -2827,16 +3433,16 @@ var parseContainers = Effect19.fn("parseContainers")(function* (config, projectF
2827
3433
  }
2828
3434
  return { ...result, warnings };
2829
3435
  });
2830
- var V4ConfigParser = class extends Effect19.Service()("V4ConfigParser", {
3436
+ var V4ConfigParser = class extends Effect25.Service()("V4ConfigParser", {
2831
3437
  accessors: true,
2832
- effect: Effect19.succeed({
3438
+ effect: Effect25.succeed({
2833
3439
  /**
2834
3440
  * Parses a ConfigV4 into a NormalizedConfig.
2835
3441
  *
2836
3442
  * @param config - The raw V4 config object
2837
3443
  * @param projectFolder - Absolute path to the project root
2838
3444
  */
2839
- parse: Effect19.fn("V4ConfigParser.parse")(function* (config, projectFolder) {
3445
+ parse: Effect25.fn("V4ConfigParser.parse")(function* (config, projectFolder) {
2840
3446
  const { entrypoints: fileEntrypoints, dockerFunctions } = yield* parseEntrypoints(config, projectFolder);
2841
3447
  const containers = yield* parseContainers(config, projectFolder, fileEntrypoints, dockerFunctions);
2842
3448
  const entrypoints = [...fileEntrypoints, ...containers.entrypoints];
@@ -2878,7 +3484,7 @@ var V4ConfigParser = class extends Effect19.Service()("V4ConfigParser", {
2878
3484
  };
2879
3485
 
2880
3486
  // src/services/vercel-build-output-parser.ts
2881
- import { Path as Path12 } from "@effect/platform";
3487
+ import { Path as Path16 } from "@effect/platform";
2882
3488
 
2883
3489
  // ../commons/src/deep-merge.ts
2884
3490
  var deepMerge = (target, ...partials) => {
@@ -2907,7 +3513,7 @@ var deepMerge = (target, ...partials) => {
2907
3513
  };
2908
3514
 
2909
3515
  // src/services/vercel-build-output-parser.ts
2910
- import { Effect as Effect20 } from "effect";
3516
+ import { Effect as Effect26 } from "effect";
2911
3517
 
2912
3518
  // src/build-output-v3/determine-repo-root.ts
2913
3519
  import path from "path";
@@ -3003,11 +3609,11 @@ var translateVercelRuntime = (runtime) => {
3003
3609
  var CONFIG_PATH = ".vercel/output/config.json";
3004
3610
  var FUNCTIONS_FOLDER = ".vercel/output/functions";
3005
3611
  var FUNCTION_CONFIGS_PATTERN = `${FUNCTIONS_FOLDER}/**/*.func/.vc-config.json`;
3006
- var VercelBuildOutputParser = class extends Effect20.Service()("VercelBuildOutputParser", {
3007
- effect: Effect20.gen(function* () {
3612
+ var VercelBuildOutputParser = class extends Effect26.Service()("VercelBuildOutputParser", {
3613
+ effect: Effect26.gen(function* () {
3008
3614
  const rawConfigReader = yield* RawConfigReader;
3009
- const pathService = yield* Path12.Path;
3010
- const parse = Effect20.fn("VercelBuildOutputParser.parse")(function* (parseResult, projectFolder) {
3615
+ const pathService = yield* Path16.Path;
3616
+ const parse = Effect26.fn("VercelBuildOutputParser.parse")(function* (parseResult, projectFolder) {
3011
3617
  const config = yield* rawConfigReader.readConfigFile(pathService.join(projectFolder, CONFIG_PATH));
3012
3618
  if (!config || typeof config.version !== "number" || config.version < 3) {
3013
3619
  return parseResult;
@@ -3019,8 +3625,8 @@ var VercelBuildOutputParser = class extends Effect20.Service()("VercelBuildOutpu
3019
3625
  merged.regions = [...new Set(merged.regions)];
3020
3626
  return merged;
3021
3627
  });
3022
- const loadFunctions = Effect20.fn("VercelBuildOutputParser.loadFunctions")(function* (config, parseResult, projectFolder) {
3023
- const functionConfigs = yield* Effect20.tryPromise({
3628
+ const loadFunctions = Effect26.fn("VercelBuildOutputParser.loadFunctions")(function* (config, parseResult, projectFolder) {
3629
+ const functionConfigs = yield* Effect26.tryPromise({
3024
3630
  try: () => getFilesForPattern(FUNCTION_CONFIGS_PATTERN, projectFolder),
3025
3631
  catch: (error) => new ConfigFileParseError({
3026
3632
  message: `Failed to scan for function configs: ${error instanceof Error ? error.message : String(error)}`,
@@ -3317,7 +3923,7 @@ var schema_default = {
3317
3923
  },
3318
3924
  streaming: {
3319
3925
  type: "boolean",
3320
- description: "Enable function response streaming. When omitted, Node and Bun runtimes stream by default."
3926
+ description: "Enable function response streaming. When omitted, Node, Bun and Ruby runtimes stream by default."
3321
3927
  },
3322
3928
  schedule: {
3323
3929
  $ref: "#/$defs/schedule",
@@ -3883,7 +4489,19 @@ var schema_default = {
3883
4489
  },
3884
4490
  runtimes: {
3885
4491
  type: "string",
3886
- enum: ["php-84", "php-83", "php-81", "node-22", "node-20", "node-18", "node-16", "bun-1"]
4492
+ enum: [
4493
+ "php-84",
4494
+ "php-83",
4495
+ "php-81",
4496
+ "ruby-40",
4497
+ "ruby-34",
4498
+ "ruby-33",
4499
+ "node-22",
4500
+ "node-20",
4501
+ "node-18",
4502
+ "node-16",
4503
+ "bun-1"
4504
+ ]
3887
4505
  },
3888
4506
  matchRequirements: {
3889
4507
  description: "An array of requirements that are needed to match",
@@ -3937,7 +4555,7 @@ var schema_default = {
3937
4555
  };
3938
4556
 
3939
4557
  // src/parse-config.ts
3940
- var parseConfigRaw = Effect21.fn("parseConfigRaw")(function* (filePath, projectFolder) {
4558
+ var parseConfigRaw = Effect27.fn("parseConfigRaw")(function* (filePath, projectFolder) {
3941
4559
  const rawReader = yield* RawConfigReader;
3942
4560
  const validator = yield* SchemaValidator;
3943
4561
  const v4Parser = yield* V4ConfigParser;
@@ -3948,7 +4566,7 @@ var parseConfigRaw = Effect21.fn("parseConfigRaw")(function* (filePath, projectF
3948
4566
  };
3949
4567
  const schema = schemaMap[version];
3950
4568
  if (!schema) {
3951
- return yield* Effect21.fail(
4569
+ return yield* Effect27.fail(
3952
4570
  new ConfigVersionError({
3953
4571
  message: `Config file at ${filePath} has an unsupported version: ${version}`,
3954
4572
  filePath,
@@ -3959,11 +4577,11 @@ var parseConfigRaw = Effect21.fn("parseConfigRaw")(function* (filePath, projectF
3959
4577
  yield* validator.validate(parsed, schema, filePath);
3960
4578
  return yield* v4Parser.parse(parsed, projectFolder);
3961
4579
  });
3962
- var parseConfig = Effect21.fn("parseConfig")(function* (filePath, projectFolder) {
4580
+ var parseConfig = Effect27.fn("parseConfig")(function* (filePath, projectFolder) {
3963
4581
  const parseResult = yield* parseConfigRaw(filePath, projectFolder);
3964
4582
  return yield* postProcessConfig(parseResult, projectFolder);
3965
4583
  });
3966
- var postProcessConfig = Effect21.fn("postProcessConfig")(function* (config, projectFolder) {
4584
+ var postProcessConfig = Effect27.fn("postProcessConfig")(function* (config, projectFolder) {
3967
4585
  const vercelParser = yield* VercelBuildOutputParser;
3968
4586
  let result = yield* vercelParser.parse(config, projectFolder);
3969
4587
  const hasAssets = (result.assets?.paths?.length ?? 0) > 0 || (result.assets?.prefixes?.length ?? 0) > 0 || (result.assets?.manifests?.length ?? 0) > 0;
@@ -4011,6 +4629,9 @@ var RUNTIME_DEFINITIONS = [
4011
4629
  "php-84",
4012
4630
  "php-83",
4013
4631
  "php-81",
4632
+ "ruby-40",
4633
+ "ruby-34",
4634
+ "ruby-33",
4014
4635
  "node-22",
4015
4636
  "node-20",
4016
4637
  "node-18",
@@ -4045,6 +4666,7 @@ export {
4045
4666
  ContainerConfigError,
4046
4667
  DEFAULT_CONTAINER_MEMORY_MB,
4047
4668
  DEFAULT_FUNCTION_DURATION_SECONDS,
4669
+ DEFAULT_RUBY_RUNTIME,
4048
4670
  DEFAULT_SIDECAR_MEMORY_MB,
4049
4671
  FRAMEWORK_DEFINITIONS,
4050
4672
  FrameworkNotDetectedError,
@@ -4081,6 +4703,7 @@ export {
4081
4703
  detectContainerProject,
4082
4704
  detectFramework,
4083
4705
  detectPackageManager,
4706
+ detectRubyRuntime,
4084
4707
  dockerFunctionContainerName,
4085
4708
  filterFunctionsFromAssets,
4086
4709
  generateConfig,
@@ -4096,6 +4719,9 @@ export {
4096
4719
  postProcessConfig,
4097
4720
  readComposeContainers,
4098
4721
  readDependencies,
4722
+ rubyRuntimeForRequirement,
4723
+ rubyRuntimeForVersion,
4724
+ rubyRuntimeFromProjectFiles,
4099
4725
  splitCommandWords
4100
4726
  };
4101
4727
  //# sourceMappingURL=index.mjs.map