@gigadrive/network-config 5.4.0 → 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 FileSystem13, Path as Path11 } from "@effect/platform";
909
- import { Effect as Effect15 } 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,12 +2296,12 @@ 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
 
1906
2302
  // src/detection/frameworks/php-runtime.ts
1907
- import { FileSystem as FileSystem11, Path as Path9 } from "@effect/platform";
1908
- import { Effect as Effect11, Option as Option3 } from "effect";
2303
+ import { FileSystem as FileSystem14, Path as Path12 } from "@effect/platform";
2304
+ import { Effect as Effect16, Option as Option3 } from "effect";
1909
2305
 
1910
2306
  // src/detection/frameworks/composer-constraint.ts
1911
2307
  var STABILITY_SUFFIX = /-(?:dev|alpha|beta|a|b|rc|patch|pl|p|stable)\.?\d*$/i;
@@ -2029,31 +2425,86 @@ var PHP_RUNTIME_CANDIDATES = [
2029
2425
  { runtime: "php-83", newestVersion: "8.3.9999" }
2030
2426
  ];
2031
2427
  var phpRuntimeForConstraint = (constraint) => PHP_RUNTIME_CANDIDATES.find(({ newestVersion }) => composerConstraintAllows(constraint, newestVersion) === true)?.runtime;
2032
- var readPhpConstraint = Effect11.fn("readPhpConstraint")(
2428
+ var readPhpConstraint = Effect16.fn("readPhpConstraint")(
2033
2429
  function* (projectFolder) {
2034
- const fs = yield* FileSystem11.FileSystem;
2035
- const pathService = yield* Path9.Path;
2430
+ const fs = yield* FileSystem14.FileSystem;
2431
+ const pathService = yield* Path12.Path;
2036
2432
  const content = yield* fs.readFileString(pathService.join(projectFolder, "composer.json"));
2037
- const manifest = yield* Effect11.try(() => JSON.parse(content));
2433
+ const manifest = yield* Effect16.try(() => JSON.parse(content));
2038
2434
  const requires = manifest && typeof manifest === "object" && "require" in manifest ? manifest.require : void 0;
2039
2435
  const php = requires && typeof requires === "object" && "php" in requires ? requires.php : void 0;
2040
2436
  return typeof php === "string" ? Option3.some(php) : Option3.none();
2041
2437
  },
2042
- Effect11.catchAll(() => Effect11.succeed(Option3.none()))
2438
+ Effect16.catchAll(() => Effect16.succeed(Option3.none()))
2043
2439
  );
2044
- var refineComposerPhpRuntime = Effect11.fn("refineComposerPhpRuntime")(function* (defaults, projectFolder) {
2440
+ var refineComposerPhpRuntime = Effect16.fn("refineComposerPhpRuntime")(function* (defaults, projectFolder) {
2045
2441
  const constraint = yield* readPhpConstraint(projectFolder);
2046
2442
  const runtime = Option3.getOrUndefined(Option3.flatMapNullable(constraint, phpRuntimeForConstraint));
2047
2443
  return runtime ? { ...defaults, runtime } : defaults;
2048
2444
  });
2049
2445
  var withComposerPhpRuntime = (framework) => ({
2050
2446
  ...framework,
2051
- refineDefaultConfig: (defaults, projectFolder) => Effect11.gen(function* () {
2447
+ refineDefaultConfig: (defaults, projectFolder) => Effect16.gen(function* () {
2052
2448
  const refined = framework.refineDefaultConfig ? yield* framework.refineDefaultConfig(defaults, projectFolder) : defaults;
2053
2449
  return yield* refineComposerPhpRuntime(refined, projectFolder);
2054
2450
  })
2055
2451
  });
2056
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
+
2057
2508
  // src/detection/frameworks/remix.ts
2058
2509
  var remix = {
2059
2510
  slug: "remix",
@@ -2075,6 +2526,45 @@ var remix = {
2075
2526
  })
2076
2527
  };
2077
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
+
2078
2568
  // src/detection/frameworks/slim.ts
2079
2569
  var slim = {
2080
2570
  slug: "slim",
@@ -2195,17 +2685,33 @@ var FRAMEWORK_DEFINITIONS = [
2195
2685
  mezzio,
2196
2686
  yii,
2197
2687
  slim,
2688
+ ...railsPresets,
2689
+ hanami,
2690
+ ...jekyllPresets,
2691
+ bridgetown,
2692
+ sinatra,
2693
+ roda,
2198
2694
  hono,
2199
2695
  elysia,
2200
2696
  fastify,
2201
2697
  express,
2698
+ rack,
2202
2699
  ...phpComposerProjects,
2203
2700
  ...phpSites,
2204
2701
  vite
2205
- ].map((framework) => framework.language === "php" ? withComposerPhpRuntime(framework) : framework).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);
2206
2712
 
2207
2713
  // src/detection/generate-config.ts
2208
- import { Effect as Effect12 } from "effect";
2714
+ import { Effect as Effect19 } from "effect";
2209
2715
  var getInstallCommand = (pm) => {
2210
2716
  switch (pm) {
2211
2717
  case "bun":
@@ -2216,6 +2722,8 @@ var getInstallCommand = (pm) => {
2216
2722
  return "yarn install";
2217
2723
  case "composer":
2218
2724
  return "composer install";
2725
+ case "bundler":
2726
+ return "bundle install";
2219
2727
  case "npm":
2220
2728
  default:
2221
2729
  return "npm install";
@@ -2226,11 +2734,17 @@ var isPrivatePhpProjectFile = (projectPath) => {
2226
2734
  const segments = projectPath.split("/").filter((segment) => segment !== "" && segment !== ".");
2227
2735
  return segments.some((segment) => segment.startsWith(".")) || segments[0] === "vendor" || segments[0] === "node_modules" || segments.length === 1 && COMPOSER_ROOT_FILES.has(segments[0] ?? "");
2228
2736
  };
2229
- var generateConfig = Effect12.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) {
2230
2744
  const defaults = refinedDefaults ?? framework.getDefaultConfig(packageManager);
2231
2745
  const installCmd = defaults.installCommand ?? getInstallCommand(packageManager);
2232
2746
  const commands = installCmd ? [installCmd, ...defaults.commands] : [...defaults.commands];
2233
- yield* Effect12.logDebug(`Generating config for ${framework.name}`, {
2747
+ yield* Effect19.logDebug(`Generating config for ${framework.name}`, {
2234
2748
  runtime: defaults.runtime,
2235
2749
  entrypoint: defaults.entrypoint,
2236
2750
  commands
@@ -2273,6 +2787,7 @@ var generateConfig = Effect12.fn("generateConfig")(function* (framework, package
2273
2787
  for (const file of yield* collectAssetFiles(projectFolder, assetsDir)) {
2274
2788
  if (framework.language === "php" && /\.(php|phtml|phar)$/i.test(file)) continue;
2275
2789
  if (framework.language === "php" && isPrivatePhpProjectFile(`${assetsDir}/${file}`)) continue;
2790
+ if (framework.language === "ruby" && isPrivateRubyProjectFile(`${assetsDir}/${file}`)) continue;
2276
2791
  paths.push(`${assetsDir}/${file}`);
2277
2792
  if (!servesDirectoryIndexes || file in overrides) continue;
2278
2793
  if (file === "index.html") {
@@ -2295,80 +2810,10 @@ var generateConfig = Effect12.fn("generateConfig")(function* (framework, package
2295
2810
  return config;
2296
2811
  });
2297
2812
 
2298
- // src/detection/read-dependencies.ts
2299
- import { FileSystem as FileSystem12, Path as Path10 } from "@effect/platform";
2300
- import { Effect as Effect14 } from "effect";
2301
-
2302
- // src/detection/types.ts
2303
- import { Schema as Schema5 } from "effect";
2304
- var ManifestNotFoundError = class extends Schema5.TaggedError()("ManifestNotFoundError", {
2305
- message: Schema5.String,
2306
- filePath: Schema5.String
2307
- }) {
2308
- };
2309
- var ManifestReadError = class extends Schema5.TaggedError()("ManifestReadError", {
2310
- message: Schema5.String,
2311
- filePath: Schema5.String
2312
- }) {
2313
- };
2314
- var ManifestParseError = class extends Schema5.TaggedError()("ManifestParseError", {
2315
- message: Schema5.String,
2316
- filePath: Schema5.String
2317
- }) {
2318
- };
2319
- var FrameworkNotDetectedError = class extends Schema5.TaggedError()(
2320
- "FrameworkNotDetectedError",
2321
- {
2322
- message: Schema5.String,
2323
- directory: Schema5.String
2324
- }
2325
- ) {
2326
- };
2327
-
2328
- // src/detection/read-dependencies.ts
2329
- var MANIFEST_CONFIG = {
2330
- node: { file: "package.json", depKeys: ["dependencies", "devDependencies"] },
2331
- php: { file: "composer.json", depKeys: ["require", "require-dev"] }
2332
- };
2333
- var readManifest = Effect14.fn("readManifest")(function* (filePath) {
2334
- const fs = yield* FileSystem12.FileSystem;
2335
- const exists = yield* fs.exists(filePath).pipe(Effect14.catchAll(() => Effect14.succeed(false)));
2336
- if (!exists) {
2337
- return yield* Effect14.fail(new ManifestNotFoundError({ message: "Manifest not found", filePath }));
2338
- }
2339
- const content = yield* fs.readFileString(filePath).pipe(Effect14.mapError(() => new ManifestReadError({ message: "Failed to read manifest", filePath })));
2340
- const parsed = yield* Effect14.try({
2341
- try: () => JSON.parse(content),
2342
- catch: () => new ManifestParseError({ message: "Failed to parse manifest JSON", filePath })
2343
- });
2344
- return parsed;
2345
- });
2346
- var readDependencies = Effect14.fn("readDependencies")(function* (projectFolder, language) {
2347
- const pathService = yield* Path10.Path;
2348
- const config = MANIFEST_CONFIG[language];
2349
- const filePath = pathService.join(projectFolder, config.file);
2350
- const manifest = yield* readManifest(filePath).pipe(
2351
- Effect14.catchTag("ManifestNotFoundError", () => Effect14.succeed(null))
2352
- );
2353
- if (!manifest) {
2354
- return /* @__PURE__ */ new Set();
2355
- }
2356
- const deps = /* @__PURE__ */ new Set();
2357
- for (const key of config.depKeys) {
2358
- const section = manifest[key];
2359
- if (section && typeof section === "object" && !Array.isArray(section)) {
2360
- for (const name of Object.keys(section)) {
2361
- deps.add(name);
2362
- }
2363
- }
2364
- }
2365
- return deps;
2366
- });
2367
-
2368
2813
  // src/detection/detect-framework.ts
2369
- var matchesDetectionItem = Effect15.fn("matchesDetectionItem")(function* (item, projectFolder, framework, cachedReadDeps) {
2370
- const fs = yield* FileSystem13.FileSystem;
2371
- const pathService = yield* Path11.Path;
2814
+ var matchesDetectionItem = Effect20.fn("matchesDetectionItem")(function* (item, projectFolder, framework, cachedReadDeps) {
2815
+ const fs = yield* FileSystem16.FileSystem;
2816
+ const pathService = yield* Path14.Path;
2372
2817
  if (item.matchPackage != null) {
2373
2818
  const deps = yield* cachedReadDeps(`${projectFolder}\0${framework.language}`);
2374
2819
  if (!deps.has(item.matchPackage)) {
@@ -2377,12 +2822,12 @@ var matchesDetectionItem = Effect15.fn("matchesDetectionItem")(function* (item,
2377
2822
  }
2378
2823
  if (item.path != null) {
2379
2824
  const filePath = pathService.join(projectFolder, item.path);
2380
- const exists = yield* fs.exists(filePath).pipe(Effect15.catchAll(() => Effect15.succeed(false)));
2825
+ const exists = yield* fs.exists(filePath).pipe(Effect20.catchAll(() => Effect20.succeed(false)));
2381
2826
  if (!exists) {
2382
2827
  return false;
2383
2828
  }
2384
2829
  if (item.matchContent != null) {
2385
- const content = yield* fs.readFileString(filePath).pipe(Effect15.catchAll(() => Effect15.succeed("")));
2830
+ const content = yield* fs.readFileString(filePath).pipe(Effect20.catchAll(() => Effect20.succeed("")));
2386
2831
  let regexMatch = false;
2387
2832
  try {
2388
2833
  regexMatch = new RegExp(item.matchContent).test(content);
@@ -2395,7 +2840,7 @@ var matchesDetectionItem = Effect15.fn("matchesDetectionItem")(function* (item,
2395
2840
  }
2396
2841
  return true;
2397
2842
  });
2398
- var matchesFramework = Effect15.fn("matchesFramework")(function* (framework, projectFolder, cachedReadDeps) {
2843
+ var matchesFramework = Effect20.fn("matchesFramework")(function* (framework, projectFolder, cachedReadDeps) {
2399
2844
  for (const detector of framework.detectors) {
2400
2845
  const matches = yield* matchesDetectionItem(detector, projectFolder, framework, cachedReadDeps);
2401
2846
  if (!matches) {
@@ -2404,9 +2849,19 @@ var matchesFramework = Effect15.fn("matchesFramework")(function* (framework, pro
2404
2849
  }
2405
2850
  return true;
2406
2851
  });
2407
- var detectFramework = Effect15.fn("detectFramework")(function* (projectFolder) {
2408
- yield* Effect15.logDebug(`Detecting framework in ${projectFolder}`);
2409
- const cachedReadDeps = yield* Effect15.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) => {
2410
2865
  const sepIndex = key.lastIndexOf("\0");
2411
2866
  const folder = key.slice(0, sepIndex);
2412
2867
  const language = key.slice(sepIndex + 1);
@@ -2415,16 +2870,16 @@ var detectFramework = Effect15.fn("detectFramework")(function* (projectFolder) {
2415
2870
  for (const framework of FRAMEWORK_DEFINITIONS) {
2416
2871
  const matches = yield* matchesFramework(framework, projectFolder, cachedReadDeps);
2417
2872
  if (matches) {
2418
- yield* Effect15.log(`Detected framework: ${framework.name}`, { slug: framework.slug });
2873
+ yield* Effect20.log(`Detected framework: ${framework.name}`, { slug: framework.slug });
2419
2874
  const detectedPackageManager = yield* detectPackageManager(projectFolder);
2420
- const packageManager = framework.language === "php" ? "composer" : detectedPackageManager;
2875
+ const packageManager = packageManagerForLanguage(framework.language, detectedPackageManager);
2421
2876
  const defaults = framework.getDefaultConfig(packageManager);
2422
2877
  const refinedDefaults = framework.refineDefaultConfig ? yield* framework.refineDefaultConfig(defaults, projectFolder) : defaults;
2423
2878
  const config = yield* generateConfig(framework, packageManager, projectFolder, refinedDefaults);
2424
2879
  return { framework, packageManager, config };
2425
2880
  }
2426
2881
  }
2427
- return yield* Effect15.fail(
2882
+ return yield* Effect20.fail(
2428
2883
  new FrameworkNotDetectedError({
2429
2884
  message: `No framework detected in project directory`,
2430
2885
  directory: projectFolder
@@ -2433,9 +2888,9 @@ var detectFramework = Effect15.fn("detectFramework")(function* (projectFolder) {
2433
2888
  });
2434
2889
 
2435
2890
  // src/detection/merge-config.ts
2436
- import { Effect as Effect16 } from "effect";
2437
- var mergeWithFrameworkDefaults = Effect16.fn("mergeWithFrameworkDefaults")(function* (userConfig, frameworkConfig) {
2438
- yield* Effect16.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");
2439
2894
  const userHasAssets = (userConfig.assets?.paths?.length ?? 0) > 0 || (userConfig.assets?.prefixes?.length ?? 0) > 0 || (userConfig.assets?.manifests?.length ?? 0) > 0;
2440
2895
  const isContainer = (entrypoint) => entrypoint.runtime === CONTAINER_RUNTIME;
2441
2896
  const userFileFunctions = userConfig.entrypoints.filter((entrypoint) => !isContainer(entrypoint));
@@ -2476,23 +2931,23 @@ var filterFunctionsFromAssets = (config) => {
2476
2931
  };
2477
2932
 
2478
2933
  // src/parse-config.ts
2479
- import { Effect as Effect22 } from "effect";
2934
+ import { Effect as Effect27 } from "effect";
2480
2935
 
2481
2936
  // src/services/raw-config-reader.ts
2482
- import { FileSystem as FileSystem14, Path as Path12 } from "@effect/platform";
2483
- import { Effect as Effect18 } from "effect";
2937
+ import { FileSystem as FileSystem17, Path as Path15 } from "@effect/platform";
2938
+ import { Effect as Effect23 } from "effect";
2484
2939
  import { parse as parseYaml2 } from "yaml";
2485
2940
 
2486
2941
  // src/services/config-module-loader.ts
2487
- import { Effect as Effect17 } from "effect";
2942
+ import { Effect as Effect22 } from "effect";
2488
2943
  import { createJiti } from "jiti";
2489
2944
  var MISSING_DEFAULT_EXPORT = /* @__PURE__ */ Symbol("MissingDefaultExport");
2490
2945
  var STRICT_DEFAULT_EXPORT_EXTENSIONS = [".ts", ".mts", ".mjs"];
2491
- var ConfigModuleLoader = class extends Effect17.Service()("ConfigModuleLoader", {
2492
- effect: Effect17.gen(function* () {
2493
- const loadConfigModule = Effect17.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) {
2494
2949
  const extension = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
2495
- const mod = yield* Effect17.tryPromise({
2950
+ const mod = yield* Effect22.tryPromise({
2496
2951
  try: async () => {
2497
2952
  const jiti = createJiti(filePath, { fsCache: false, interopDefault: true, moduleCache: false });
2498
2953
  const namespace = await jiti.import(filePath);
@@ -2511,7 +2966,7 @@ var ConfigModuleLoader = class extends Effect17.Service()("ConfigModuleLoader",
2511
2966
  })
2512
2967
  });
2513
2968
  if (mod === MISSING_DEFAULT_EXPORT) {
2514
- return yield* Effect17.fail(
2969
+ return yield* Effect22.fail(
2515
2970
  new ConfigModuleLoadError({
2516
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.`,
2517
2972
  filePath
@@ -2519,7 +2974,7 @@ var ConfigModuleLoader = class extends Effect17.Service()("ConfigModuleLoader",
2519
2974
  );
2520
2975
  }
2521
2976
  if (typeof mod === "function") {
2522
- return yield* Effect17.fail(
2977
+ return yield* Effect22.fail(
2523
2978
  new ConfigModuleLoadError({
2524
2979
  message: `Config module at ${filePath} default-exports a function; config factories are not supported. Export a config object instead (optionally wrapped in defineConfig).`,
2525
2980
  filePath
@@ -2527,7 +2982,7 @@ var ConfigModuleLoader = class extends Effect17.Service()("ConfigModuleLoader",
2527
2982
  );
2528
2983
  }
2529
2984
  if (typeof mod !== "object" || mod === null || Array.isArray(mod)) {
2530
- return yield* Effect17.fail(
2985
+ return yield* Effect22.fail(
2531
2986
  new ConfigModuleLoadError({
2532
2987
  message: `Config module at ${filePath} must default-export a config object.`,
2533
2988
  filePath
@@ -2557,36 +3012,36 @@ var ALLOWED_CONFIG_NAMES = [
2557
3012
  "nebula.json"
2558
3013
  ];
2559
3014
  var MODULE_EXTENSIONS = [".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"];
2560
- var RawConfigReader = class extends Effect18.Service()("RawConfigReader", {
3015
+ var RawConfigReader = class extends Effect23.Service()("RawConfigReader", {
2561
3016
  dependencies: [ConfigModuleLoader.Default],
2562
- effect: Effect18.gen(function* () {
2563
- const fs = yield* FileSystem14.FileSystem;
2564
- const pathService = yield* Path12.Path;
3017
+ effect: Effect23.gen(function* () {
3018
+ const fs = yield* FileSystem17.FileSystem;
3019
+ const pathService = yield* Path15.Path;
2565
3020
  const moduleLoader = yield* ConfigModuleLoader;
2566
- const findConfig = Effect18.fn("RawConfigReader.findConfig")(function* (projectFolder) {
3021
+ const findConfig = Effect23.fn("RawConfigReader.findConfig")(function* (projectFolder) {
2567
3022
  for (const name of ALLOWED_CONFIG_NAMES) {
2568
3023
  const filePath = pathService.join(projectFolder, name);
2569
- const exists = yield* fs.exists(filePath).pipe(Effect18.catchAll(() => Effect18.succeed(false)));
3024
+ const exists = yield* fs.exists(filePath).pipe(Effect23.catchAll(() => Effect23.succeed(false)));
2570
3025
  if (exists) {
2571
3026
  return filePath;
2572
3027
  }
2573
3028
  }
2574
3029
  return null;
2575
3030
  });
2576
- const readRawConfig = Effect18.fn("RawConfigReader.readRawConfig")(function* (filePath, options) {
2577
- const exists = yield* fs.exists(filePath).pipe(Effect18.catchAll(() => Effect18.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)));
2578
3033
  if (!exists) {
2579
- return yield* Effect18.fail(
3034
+ return yield* Effect23.fail(
2580
3035
  new ConfigFileNotFoundError({ message: `Config file not found at ${filePath}`, filePath })
2581
3036
  );
2582
3037
  }
2583
3038
  const fileContents = yield* fs.readFileString(filePath).pipe(
2584
- Effect18.mapError(
3039
+ Effect23.mapError(
2585
3040
  () => new ConfigFileParseError({ message: `Failed to read config file at ${filePath}`, filePath })
2586
3041
  )
2587
3042
  );
2588
3043
  if (fileContents.length === 0) {
2589
- return yield* Effect18.fail(
3044
+ return yield* Effect23.fail(
2590
3045
  new ConfigFileEmptyError({ message: `Config file is empty at ${filePath}`, filePath })
2591
3046
  );
2592
3047
  }
@@ -2602,7 +3057,7 @@ var RawConfigReader = class extends Effect18.Service()("RawConfigReader", {
2602
3057
  parsed = parseYaml2(fileContents);
2603
3058
  }
2604
3059
  } catch (error) {
2605
- return yield* Effect18.fail(
3060
+ return yield* Effect23.fail(
2606
3061
  new ConfigFileParseError({
2607
3062
  message: `Failed to parse config file at ${filePath}: ${error instanceof Error ? error.message : "Unknown error"}`,
2608
3063
  filePath,
@@ -2612,21 +3067,21 @@ var RawConfigReader = class extends Effect18.Service()("RawConfigReader", {
2612
3067
  }
2613
3068
  }
2614
3069
  if (parsed == null) {
2615
- return yield* Effect18.fail(
3070
+ return yield* Effect23.fail(
2616
3071
  new ConfigFileParseError({ message: `Config file could not be parsed at ${filePath}`, filePath })
2617
3072
  );
2618
3073
  }
2619
3074
  if (!options?.disableVersionCheck && typeof parsed.version !== "number") {
2620
- return yield* Effect18.fail(
3075
+ return yield* Effect23.fail(
2621
3076
  new ConfigVersionError({ message: `Config file is missing version at ${filePath}`, filePath })
2622
3077
  );
2623
3078
  }
2624
3079
  return parsed;
2625
3080
  });
2626
3081
  const readConfigFile = (configFilePath) => readRawConfig(configFilePath, { disableVersionCheck: true }).pipe(
2627
- Effect18.map((parsed) => parsed),
2628
- Effect18.catchTag("ConfigFileNotFoundError", () => Effect18.succeed(null)),
2629
- Effect18.withSpan("RawConfigReader.readConfigFile")
3082
+ Effect23.map((parsed) => parsed),
3083
+ Effect23.catchTag("ConfigFileNotFoundError", () => Effect23.succeed(null)),
3084
+ Effect23.withSpan("RawConfigReader.readConfigFile")
2630
3085
  );
2631
3086
  return { findConfig, readRawConfig, readConfigFile };
2632
3087
  })
@@ -2636,17 +3091,17 @@ var RawConfigReader = class extends Effect18.Service()("RawConfigReader", {
2636
3091
  // src/services/schema-validator.ts
2637
3092
  import Ajv from "ajv";
2638
3093
  import addFormats from "ajv-formats";
2639
- import { Effect as Effect19 } from "effect";
2640
- var SchemaValidator = class extends Effect19.Service()("SchemaValidator", {
2641
- effect: Effect19.gen(function* () {
3094
+ import { Effect as Effect24 } from "effect";
3095
+ var SchemaValidator = class extends Effect24.Service()("SchemaValidator", {
3096
+ effect: Effect24.gen(function* () {
2642
3097
  const ajv = new Ajv();
2643
3098
  addFormats(ajv);
2644
- const validate = Effect19.fn("SchemaValidator.validate")(function* (config, schema, filePath) {
3099
+ const validate = Effect24.fn("SchemaValidator.validate")(function* (config, schema, filePath) {
2645
3100
  const compiledValidate = ajv.compile(schema);
2646
3101
  const valid = compiledValidate(config);
2647
3102
  if (!valid) {
2648
3103
  const errors = compiledValidate.errors?.map((e) => `${e.instancePath || "/"} ${e.message ?? ""}`.trim()) ?? [];
2649
- return yield* Effect19.fail(
3104
+ return yield* Effect24.fail(
2650
3105
  new ConfigSchemaValidationError({
2651
3106
  message: `Config file at ${filePath} is invalid: ${ajv.errorsText(compiledValidate.errors)}`,
2652
3107
  filePath,
@@ -2702,7 +3157,7 @@ var getFilesForPattern = async (pattern, projectFolder, excludeFiles = []) => {
2702
3157
  };
2703
3158
 
2704
3159
  // src/services/v4-config-parser.ts
2705
- import { Effect as Effect20 } from "effect";
3160
+ import { Effect as Effect25 } from "effect";
2706
3161
  import { minimatch as minimatch2 } from "minimatch";
2707
3162
  import { posix as posix2 } from "path";
2708
3163
  import safeRegex from "safe-regex2";
@@ -2718,7 +3173,7 @@ var toArray = (value) => {
2718
3173
  if (value == null) return void 0;
2719
3174
  return Array.isArray(value) ? value : [value];
2720
3175
  };
2721
- 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-");
2722
3177
  var normalizeImagePolicy = (images) => {
2723
3178
  if (!images) return void 0;
2724
3179
  return {
@@ -2853,7 +3308,7 @@ var mapRoute = (route, entrypoints) => ({
2853
3308
  negativeRequirements: route.missing,
2854
3309
  status: route.statusCode
2855
3310
  });
2856
- var parseEntrypoints = Effect20.fn("parseEntrypoints")(function* (config, projectFolder) {
3311
+ var parseEntrypoints = Effect25.fn("parseEntrypoints")(function* (config, projectFolder) {
2857
3312
  const entrypoints = [];
2858
3313
  const dockerFunctions = [];
2859
3314
  if (config.functions == null) return { entrypoints, dockerFunctions };
@@ -2864,7 +3319,7 @@ var parseEntrypoints = Effect20.fn("parseEntrypoints")(function* (config, projec
2864
3319
  functionPath: fnPath
2865
3320
  });
2866
3321
  }
2867
- const matchedFiles = yield* Effect20.tryPromise({
3322
+ const matchedFiles = yield* Effect25.tryPromise({
2868
3323
  try: () => getFilesForPattern(fnPath, projectFolder, func.excludeFiles),
2869
3324
  catch: (error) => new FunctionConfigError({
2870
3325
  message: `Failed to resolve files for function pattern '${fnPath}': ${error instanceof Error ? error.message : String(error)}`,
@@ -2939,13 +3394,13 @@ var parseEntrypoints = Effect20.fn("parseEntrypoints")(function* (config, projec
2939
3394
  }
2940
3395
  return { entrypoints, dockerFunctions };
2941
3396
  });
2942
- var collectAssets = Effect20.fn("collectAssets")(function* (config, projectFolder) {
3397
+ var collectAssets = Effect25.fn("collectAssets")(function* (config, projectFolder) {
2943
3398
  if (config.assets == null) return [];
2944
3399
  const assetNames = yield* collectAssetFiles(projectFolder, config.assets);
2945
3400
  return assetNames.filter((assetName) => getFunctionSettings(`${config.assets}/${assetName}`, config) == null).map((assetName) => `${config.assets}/${assetName}`);
2946
3401
  });
2947
3402
  var reservedRuntimePorts = (entrypoint) => entrypoint.runtime === CONTAINER_RUNTIME ? [] : entrypoint.runtime.startsWith("php-") ? [8080, 9e3] : [8080];
2948
- var parseContainers = Effect20.fn("parseContainers")(function* (config, projectFolder, fileEntrypoints, dockerFunctions) {
3403
+ var parseContainers = Effect25.fn("parseContainers")(function* (config, projectFolder, fileEntrypoints, dockerFunctions) {
2949
3404
  const warnings = [];
2950
3405
  let containers = {};
2951
3406
  if (config.compose != null) {
@@ -2978,16 +3433,16 @@ var parseContainers = Effect20.fn("parseContainers")(function* (config, projectF
2978
3433
  }
2979
3434
  return { ...result, warnings };
2980
3435
  });
2981
- var V4ConfigParser = class extends Effect20.Service()("V4ConfigParser", {
3436
+ var V4ConfigParser = class extends Effect25.Service()("V4ConfigParser", {
2982
3437
  accessors: true,
2983
- effect: Effect20.succeed({
3438
+ effect: Effect25.succeed({
2984
3439
  /**
2985
3440
  * Parses a ConfigV4 into a NormalizedConfig.
2986
3441
  *
2987
3442
  * @param config - The raw V4 config object
2988
3443
  * @param projectFolder - Absolute path to the project root
2989
3444
  */
2990
- parse: Effect20.fn("V4ConfigParser.parse")(function* (config, projectFolder) {
3445
+ parse: Effect25.fn("V4ConfigParser.parse")(function* (config, projectFolder) {
2991
3446
  const { entrypoints: fileEntrypoints, dockerFunctions } = yield* parseEntrypoints(config, projectFolder);
2992
3447
  const containers = yield* parseContainers(config, projectFolder, fileEntrypoints, dockerFunctions);
2993
3448
  const entrypoints = [...fileEntrypoints, ...containers.entrypoints];
@@ -3029,7 +3484,7 @@ var V4ConfigParser = class extends Effect20.Service()("V4ConfigParser", {
3029
3484
  };
3030
3485
 
3031
3486
  // src/services/vercel-build-output-parser.ts
3032
- import { Path as Path13 } from "@effect/platform";
3487
+ import { Path as Path16 } from "@effect/platform";
3033
3488
 
3034
3489
  // ../commons/src/deep-merge.ts
3035
3490
  var deepMerge = (target, ...partials) => {
@@ -3058,7 +3513,7 @@ var deepMerge = (target, ...partials) => {
3058
3513
  };
3059
3514
 
3060
3515
  // src/services/vercel-build-output-parser.ts
3061
- import { Effect as Effect21 } from "effect";
3516
+ import { Effect as Effect26 } from "effect";
3062
3517
 
3063
3518
  // src/build-output-v3/determine-repo-root.ts
3064
3519
  import path from "path";
@@ -3154,11 +3609,11 @@ var translateVercelRuntime = (runtime) => {
3154
3609
  var CONFIG_PATH = ".vercel/output/config.json";
3155
3610
  var FUNCTIONS_FOLDER = ".vercel/output/functions";
3156
3611
  var FUNCTION_CONFIGS_PATTERN = `${FUNCTIONS_FOLDER}/**/*.func/.vc-config.json`;
3157
- var VercelBuildOutputParser = class extends Effect21.Service()("VercelBuildOutputParser", {
3158
- effect: Effect21.gen(function* () {
3612
+ var VercelBuildOutputParser = class extends Effect26.Service()("VercelBuildOutputParser", {
3613
+ effect: Effect26.gen(function* () {
3159
3614
  const rawConfigReader = yield* RawConfigReader;
3160
- const pathService = yield* Path13.Path;
3161
- const parse = Effect21.fn("VercelBuildOutputParser.parse")(function* (parseResult, projectFolder) {
3615
+ const pathService = yield* Path16.Path;
3616
+ const parse = Effect26.fn("VercelBuildOutputParser.parse")(function* (parseResult, projectFolder) {
3162
3617
  const config = yield* rawConfigReader.readConfigFile(pathService.join(projectFolder, CONFIG_PATH));
3163
3618
  if (!config || typeof config.version !== "number" || config.version < 3) {
3164
3619
  return parseResult;
@@ -3170,8 +3625,8 @@ var VercelBuildOutputParser = class extends Effect21.Service()("VercelBuildOutpu
3170
3625
  merged.regions = [...new Set(merged.regions)];
3171
3626
  return merged;
3172
3627
  });
3173
- const loadFunctions = Effect21.fn("VercelBuildOutputParser.loadFunctions")(function* (config, parseResult, projectFolder) {
3174
- const functionConfigs = yield* Effect21.tryPromise({
3628
+ const loadFunctions = Effect26.fn("VercelBuildOutputParser.loadFunctions")(function* (config, parseResult, projectFolder) {
3629
+ const functionConfigs = yield* Effect26.tryPromise({
3175
3630
  try: () => getFilesForPattern(FUNCTION_CONFIGS_PATTERN, projectFolder),
3176
3631
  catch: (error) => new ConfigFileParseError({
3177
3632
  message: `Failed to scan for function configs: ${error instanceof Error ? error.message : String(error)}`,
@@ -3468,7 +3923,7 @@ var schema_default = {
3468
3923
  },
3469
3924
  streaming: {
3470
3925
  type: "boolean",
3471
- 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."
3472
3927
  },
3473
3928
  schedule: {
3474
3929
  $ref: "#/$defs/schedule",
@@ -4034,7 +4489,19 @@ var schema_default = {
4034
4489
  },
4035
4490
  runtimes: {
4036
4491
  type: "string",
4037
- 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
+ ]
4038
4505
  },
4039
4506
  matchRequirements: {
4040
4507
  description: "An array of requirements that are needed to match",
@@ -4088,7 +4555,7 @@ var schema_default = {
4088
4555
  };
4089
4556
 
4090
4557
  // src/parse-config.ts
4091
- var parseConfigRaw = Effect22.fn("parseConfigRaw")(function* (filePath, projectFolder) {
4558
+ var parseConfigRaw = Effect27.fn("parseConfigRaw")(function* (filePath, projectFolder) {
4092
4559
  const rawReader = yield* RawConfigReader;
4093
4560
  const validator = yield* SchemaValidator;
4094
4561
  const v4Parser = yield* V4ConfigParser;
@@ -4099,7 +4566,7 @@ var parseConfigRaw = Effect22.fn("parseConfigRaw")(function* (filePath, projectF
4099
4566
  };
4100
4567
  const schema = schemaMap[version];
4101
4568
  if (!schema) {
4102
- return yield* Effect22.fail(
4569
+ return yield* Effect27.fail(
4103
4570
  new ConfigVersionError({
4104
4571
  message: `Config file at ${filePath} has an unsupported version: ${version}`,
4105
4572
  filePath,
@@ -4110,11 +4577,11 @@ var parseConfigRaw = Effect22.fn("parseConfigRaw")(function* (filePath, projectF
4110
4577
  yield* validator.validate(parsed, schema, filePath);
4111
4578
  return yield* v4Parser.parse(parsed, projectFolder);
4112
4579
  });
4113
- var parseConfig = Effect22.fn("parseConfig")(function* (filePath, projectFolder) {
4580
+ var parseConfig = Effect27.fn("parseConfig")(function* (filePath, projectFolder) {
4114
4581
  const parseResult = yield* parseConfigRaw(filePath, projectFolder);
4115
4582
  return yield* postProcessConfig(parseResult, projectFolder);
4116
4583
  });
4117
- var postProcessConfig = Effect22.fn("postProcessConfig")(function* (config, projectFolder) {
4584
+ var postProcessConfig = Effect27.fn("postProcessConfig")(function* (config, projectFolder) {
4118
4585
  const vercelParser = yield* VercelBuildOutputParser;
4119
4586
  let result = yield* vercelParser.parse(config, projectFolder);
4120
4587
  const hasAssets = (result.assets?.paths?.length ?? 0) > 0 || (result.assets?.prefixes?.length ?? 0) > 0 || (result.assets?.manifests?.length ?? 0) > 0;
@@ -4162,6 +4629,9 @@ var RUNTIME_DEFINITIONS = [
4162
4629
  "php-84",
4163
4630
  "php-83",
4164
4631
  "php-81",
4632
+ "ruby-40",
4633
+ "ruby-34",
4634
+ "ruby-33",
4165
4635
  "node-22",
4166
4636
  "node-20",
4167
4637
  "node-18",
@@ -4196,6 +4666,7 @@ export {
4196
4666
  ContainerConfigError,
4197
4667
  DEFAULT_CONTAINER_MEMORY_MB,
4198
4668
  DEFAULT_FUNCTION_DURATION_SECONDS,
4669
+ DEFAULT_RUBY_RUNTIME,
4199
4670
  DEFAULT_SIDECAR_MEMORY_MB,
4200
4671
  FRAMEWORK_DEFINITIONS,
4201
4672
  FrameworkNotDetectedError,
@@ -4232,6 +4703,7 @@ export {
4232
4703
  detectContainerProject,
4233
4704
  detectFramework,
4234
4705
  detectPackageManager,
4706
+ detectRubyRuntime,
4235
4707
  dockerFunctionContainerName,
4236
4708
  filterFunctionsFromAssets,
4237
4709
  generateConfig,
@@ -4247,6 +4719,9 @@ export {
4247
4719
  postProcessConfig,
4248
4720
  readComposeContainers,
4249
4721
  readDependencies,
4722
+ rubyRuntimeForRequirement,
4723
+ rubyRuntimeForVersion,
4724
+ rubyRuntimeFromProjectFiles,
4250
4725
  splitCommandWords
4251
4726
  };
4252
4727
  //# sourceMappingURL=index.mjs.map