@gigadrive/network-config 5.4.0 → 5.5.1

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,246 @@ 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
+ /** Next's key for the page's runtime cache entry, when its build metadata records one. */
1827
+ cacheKey: Schema5.optional(Schema5.String),
1828
+ pprChain: Schema5.optional(Schema5.mutable(Schema5.Struct({ headers: HttpSingleValueHeadersSchema }))),
1829
+ parentFallbackMode: Schema5.optional(JsonValueSchema),
1830
+ fallback: Schema5.optional(
1831
+ Schema5.mutable(
1832
+ Schema5.Struct({
1833
+ filePath: Schema5.optional(PortableRelativePathSchema),
1834
+ initialStatus: Schema5.optional(Schema5.Int.pipe(Schema5.between(100, 599))),
1835
+ initialHeaders: Schema5.optional(HttpHeadersSchema),
1836
+ initialExpiration: Schema5.optional(Schema5.Number),
1837
+ initialRevalidate: Schema5.optional(Schema5.Union(Schema5.Number, Schema5.Literal(false))),
1838
+ postponedState: Schema5.optional(Schema5.String)
1441
1839
  })
1442
1840
  )
1443
1841
  ),
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)
1842
+ config: Schema5.mutable(
1843
+ Schema5.Struct({
1844
+ allowQuery: Schema5.optional(StringArraySchema),
1845
+ allowHeader: Schema5.optional(StringArraySchema),
1846
+ bypassFor: Schema5.optional(Schema5.mutable(Schema5.Array(JsonValueSchema))),
1847
+ renderingMode: Schema5.optional(Schema5.String),
1848
+ partialFallback: Schema5.optional(Schema5.Boolean),
1849
+ bypassToken: Schema5.optional(Schema5.String)
1452
1850
  })
1453
1851
  )
1454
1852
  };
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)
1853
+ var GigadriveNextPrerenderClassificationSchema = Schema5.Struct({
1854
+ routeType: Schema5.Literal("route", "fallback", "shell", "page"),
1855
+ response: Schema5.Literal("empty", "initial", "complete"),
1856
+ compute: Schema5.Literal("blocking", "resuming", "static"),
1857
+ htmlSize: Schema5.optional(Schema5.Number)
1460
1858
  });
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)
1859
+ var GigadriveNextPrerenderWithoutClassificationSchema = Schema5.Struct({
1860
+ routeType: Schema5.optional(Schema5.Never),
1861
+ response: Schema5.optional(Schema5.Never),
1862
+ compute: Schema5.optional(Schema5.Never),
1863
+ htmlSize: Schema5.optional(Schema5.Never)
1466
1864
  });
1467
- var GigadriveNextPrerenderOutputSchema = Schema4.Union(
1468
- Schema4.mutable(
1469
- Schema4.Struct({ ...GigadriveNextPrerenderOutputFields, ...GigadriveNextPrerenderClassificationSchema.fields })
1865
+ var GigadriveNextPrerenderOutputSchema = Schema5.Union(
1866
+ Schema5.mutable(
1867
+ Schema5.Struct({ ...GigadriveNextPrerenderOutputFields, ...GigadriveNextPrerenderClassificationSchema.fields })
1470
1868
  ),
1471
- Schema4.mutable(
1472
- Schema4.Struct({
1869
+ Schema5.mutable(
1870
+ Schema5.Struct({
1473
1871
  ...GigadriveNextPrerenderOutputFields,
1474
1872
  ...GigadriveNextPrerenderWithoutClassificationSchema.fields
1475
1873
  })
1476
1874
  )
1477
1875
  );
1478
- var GigadriveNextStaticAssetPrefixSchema = Schema4.mutable(
1479
- Schema4.Struct({
1876
+ var GigadriveNextStaticAssetPrefixSchema = Schema5.mutable(
1877
+ Schema5.Struct({
1480
1878
  sourceDir: PortableRelativePathSchema,
1481
1879
  urlPrefix: PortableRelativePathSchema,
1482
- immutable: Schema4.Boolean
1880
+ immutable: Schema5.Boolean
1483
1881
  })
1484
1882
  );
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)
1883
+ var GigadriveNextRouteConditionSchema = Schema5.Union(
1884
+ Schema5.mutable(
1885
+ Schema5.Struct({
1886
+ type: Schema5.Literal("header", "cookie", "query"),
1887
+ key: Schema5.String,
1888
+ value: Schema5.optional(Schema5.String)
1491
1889
  })
1492
1890
  ),
1493
- Schema4.mutable(
1494
- Schema4.Struct({
1495
- type: Schema4.Literal("host"),
1496
- value: Schema4.String
1891
+ Schema5.mutable(
1892
+ Schema5.Struct({
1893
+ type: Schema5.Literal("host"),
1894
+ value: Schema5.String
1497
1895
  })
1498
1896
  )
1499
1897
  );
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)))
1898
+ var GigadriveNextMiddlewareMatcherSchema = Schema5.mutable(
1899
+ Schema5.Struct({
1900
+ source: Schema5.String,
1901
+ sourceRegex: Schema5.String,
1902
+ has: Schema5.optional(Schema5.mutable(Schema5.Array(GigadriveNextRouteConditionSchema))),
1903
+ missing: Schema5.optional(Schema5.mutable(Schema5.Array(GigadriveNextRouteConditionSchema)))
1506
1904
  })
1507
1905
  );
1508
- var GigadriveNextMiddlewareDescriptorSchema = Schema4.Union(
1509
- Schema4.mutable(
1510
- Schema4.Struct({
1511
- present: Schema4.Literal(true),
1512
- matchers: Schema4.mutable(Schema4.Array(GigadriveNextMiddlewareMatcherSchema))
1906
+ var GigadriveNextMiddlewareDescriptorSchema = Schema5.Union(
1907
+ Schema5.mutable(
1908
+ Schema5.Struct({
1909
+ present: Schema5.Literal(true),
1910
+ matchers: Schema5.mutable(Schema5.Array(GigadriveNextMiddlewareMatcherSchema))
1513
1911
  })
1514
1912
  ),
1515
- Schema4.mutable(
1516
- Schema4.Struct({
1517
- present: Schema4.Literal(false),
1518
- matchers: Schema4.mutable(Schema4.Tuple())
1913
+ Schema5.mutable(
1914
+ Schema5.Struct({
1915
+ present: Schema5.Literal(false),
1916
+ matchers: Schema5.mutable(Schema5.Tuple())
1519
1917
  })
1520
1918
  )
1521
1919
  );
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)
1920
+ var GigadriveNextServerDescriptorSchema = Schema5.mutable(
1921
+ Schema5.Struct({
1922
+ maxDuration: Schema5.optional(Schema5.Number),
1923
+ preferredRegion: Schema5.optional(Schema5.Union(Schema5.String, StringArraySchema)),
1924
+ env: Schema5.optional(StringRecordSchema)
1527
1925
  })
1528
1926
  );
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"))
1927
+ var PrerenderArraySchema = Schema5.mutable(Schema5.Array(GigadriveNextPrerenderOutputSchema));
1928
+ var StaticAssetArraySchema = Schema5.mutable(Schema5.Array(GigadriveNextStaticAssetPrefixSchema));
1929
+ var JsonValueArraySchema = Schema5.mutable(Schema5.Array(JsonValueSchema));
1930
+ var GigadriveNextPrerenderSeedMethodsSchema = Schema5.mutable(
1931
+ Schema5.Tuple(Schema5.Literal("GET"), Schema5.Literal("HEAD"))
1534
1932
  );
1535
- var GigadriveNextBuildManifestV1Schema = Schema4.mutable(
1536
- Schema4.Struct({
1537
- version: Schema4.Literal(1),
1538
- output: Schema4.Literal("standalone", "export"),
1933
+ var GigadriveNextBuildManifestV1Schema = Schema5.mutable(
1934
+ Schema5.Struct({
1935
+ version: Schema5.Literal(1),
1936
+ output: Schema5.Literal("standalone", "export"),
1539
1937
  distDir: PortableRelativePathSchema,
1540
1938
  repoRootToProject: RepositoryRelativePathSchema,
1541
- nextVersion: Schema4.String,
1542
- buildId: Schema4.String
1939
+ nextVersion: Schema5.String,
1940
+ buildId: Schema5.String
1543
1941
  })
1544
1942
  );
1545
- var GigadriveNextBuildManifestV2ExportSchema = Schema4.mutable(
1546
- Schema4.Struct({
1547
- version: Schema4.Literal(2),
1548
- mode: Schema4.Literal("export"),
1943
+ var GigadriveNextBuildManifestV2ExportSchema = Schema5.mutable(
1944
+ Schema5.Struct({
1945
+ version: Schema5.Literal(2),
1946
+ mode: Schema5.Literal("export"),
1549
1947
  distDir: PortableRelativePathSchema,
1550
1948
  repoRootToProject: RepositoryRelativePathSchema,
1551
- nextVersion: Schema4.String,
1552
- buildId: Schema4.String
1949
+ nextVersion: Schema5.String,
1950
+ buildId: Schema5.String
1553
1951
  })
1554
1952
  );
1555
- var GigadriveNextBuildManifestV2StandaloneSchema = Schema4.mutable(
1556
- Schema4.Struct({
1557
- version: Schema4.Literal(2),
1558
- mode: Schema4.Literal("standalone-v2"),
1953
+ var GigadriveNextBuildManifestV2StandaloneSchema = Schema5.mutable(
1954
+ Schema5.Struct({
1955
+ version: Schema5.Literal(2),
1956
+ mode: Schema5.Literal("standalone-v2"),
1559
1957
  distDir: PortableRelativePathSchema,
1560
1958
  repoRootToProject: RepositoryRelativePathSchema,
1561
- nextVersion: Schema4.String,
1562
- buildId: Schema4.String,
1959
+ nextVersion: Schema5.String,
1960
+ buildId: Schema5.String,
1563
1961
  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)
1962
+ config: Schema5.mutable(
1963
+ Schema5.Struct({
1964
+ basePath: Schema5.String,
1965
+ trailingSlash: Schema5.Boolean,
1966
+ cacheComponents: Schema5.Boolean,
1967
+ i18n: Schema5.optional(JsonValueSchema),
1968
+ images: Schema5.optional(ImagePolicySchema)
1571
1969
  })
1572
1970
  ),
1573
- routing: Schema4.mutable(
1574
- Schema4.Struct({
1971
+ routing: Schema5.mutable(
1972
+ Schema5.Struct({
1575
1973
  beforeMiddleware: JsonValueArraySchema,
1576
1974
  beforeFiles: JsonValueArraySchema,
1577
1975
  afterFiles: JsonValueArraySchema,
1578
1976
  dynamicRoutes: JsonValueArraySchema,
1579
1977
  onMatch: JsonValueArraySchema,
1580
1978
  fallback: JsonValueArraySchema,
1581
- shouldNormalizeNextData: Schema4.Boolean,
1979
+ shouldNormalizeNextData: Schema5.Boolean,
1582
1980
  rsc: JsonValueSchema
1583
1981
  })
1584
1982
  ),
1585
- outputs: Schema4.mutable(
1586
- Schema4.Struct({
1983
+ outputs: Schema5.mutable(
1984
+ Schema5.Struct({
1587
1985
  prerenders: PrerenderArraySchema,
1588
- prerenderManifest: Schema4.optional(PortableRelativePathSchema),
1589
- assetManifest: Schema4.optional(PortableRelativePathSchema),
1590
- entryPagePaths: Schema4.optional(Schema4.mutable(Schema4.Array(UrlPathnameSchema))),
1986
+ prerenderManifest: Schema5.optional(PortableRelativePathSchema),
1987
+ assetManifest: Schema5.optional(PortableRelativePathSchema),
1988
+ entryPagePaths: Schema5.optional(Schema5.mutable(Schema5.Array(UrlPathnameSchema))),
1591
1989
  staticAssets: StaticAssetArraySchema,
1592
- middleware: Schema4.optional(GigadriveNextMiddlewareDescriptorSchema)
1990
+ middleware: Schema5.optional(GigadriveNextMiddlewareDescriptorSchema)
1593
1991
  })
1594
1992
  )
1595
1993
  })
1596
1994
  );
1597
- var GigadriveNextBuildManifestSchema = Schema4.Union(
1995
+ var GigadriveNextBuildManifestSchema = Schema5.Union(
1598
1996
  GigadriveNextBuildManifestV1Schema,
1599
1997
  GigadriveNextBuildManifestV2ExportSchema,
1600
1998
  GigadriveNextBuildManifestV2StandaloneSchema
1601
1999
  );
1602
- var GigadriveNextPrerenderManifestV1Schema = Schema4.mutable(
1603
- Schema4.Struct({
1604
- version: Schema4.Literal(1),
1605
- seedMethods: Schema4.optional(GigadriveNextPrerenderSeedMethodsSchema),
2000
+ var GigadriveNextPrerenderManifestV1Schema = Schema5.mutable(
2001
+ Schema5.Struct({
2002
+ version: Schema5.Literal(1),
2003
+ seedMethods: Schema5.optional(GigadriveNextPrerenderSeedMethodsSchema),
1606
2004
  prerenders: PrerenderArraySchema
1607
2005
  })
1608
2006
  );
@@ -1612,22 +2010,22 @@ var parseGigadriveNextPrerenderManifest = (content) => decodeJson(GigadriveNextP
1612
2010
  // src/detection/frameworks/nextjs.ts
1613
2011
  var toPortablePath = (value) => value.replaceAll("\\", "/");
1614
2012
  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;
2013
+ var resolveStandaloneServer = Effect13.fn("nextjs.resolveStandaloneServer")(function* (projectFolder, distDir, repoRootToProject) {
2014
+ const fs = yield* FileSystem11.FileSystem;
2015
+ const pathService = yield* Path10.Path;
1618
2016
  const standaloneRoot = pathService.join(projectFolder, distDir, "standalone");
1619
2017
  const monorepoServer = pathService.join(standaloneRoot, repoRootToProject, "server.js");
1620
2018
  const rootServer = pathService.join(standaloneRoot, "server.js");
1621
- const monorepoServerExists = yield* fs.exists(monorepoServer).pipe(Effect8.catchAll(() => Effect8.succeed(false)));
2019
+ const monorepoServerExists = yield* fs.exists(monorepoServer).pipe(Effect13.catchAll(() => Effect13.succeed(false)));
1622
2020
  const serverPath = monorepoServerExists ? monorepoServer : rootServer;
1623
- const serverExists = yield* fs.exists(serverPath).pipe(Effect8.catchAll(() => Effect8.succeed(false)));
2021
+ const serverExists = yield* fs.exists(serverPath).pipe(Effect13.catchAll(() => Effect13.succeed(false)));
1624
2022
  if (!serverExists) return void 0;
1625
2023
  const serverDirectory = pathService.dirname(serverPath);
1626
2024
  const entrypoint = toPortablePath(pathService.relative(standaloneRoot, serverPath));
1627
2025
  return { standaloneRoot, serverDirectory, entrypoint };
1628
2026
  });
1629
- var buildStandalonePublicAssets = Effect8.fn("nextjs.buildStandalonePublicAssets")(function* (projectFolder, standaloneRoot, serverDirectory) {
1630
- const pathService = yield* Path7.Path;
2027
+ var buildStandalonePublicAssets = Effect13.fn("nextjs.buildStandalonePublicAssets")(function* (projectFolder, standaloneRoot, serverDirectory) {
2028
+ const pathService = yield* Path10.Path;
1631
2029
  const publicFiles = yield* getDefaultPathMap(pathService.join(projectFolder, "public"));
1632
2030
  const assetPaths = [];
1633
2031
  const assetOverrides = {};
@@ -1643,8 +2041,8 @@ var buildStandalonePublicAssets = Effect8.fn("nextjs.buildStandalonePublicAssets
1643
2041
  }
1644
2042
  return { assetPaths, assetOverrides, filePathMap };
1645
2043
  });
1646
- var createStaticExportConfig = Effect8.fn("nextjs.createStaticExportConfig")(function* (defaults, projectFolder) {
1647
- const pathService = yield* Path7.Path;
2044
+ var createStaticExportConfig = Effect13.fn("nextjs.createStaticExportConfig")(function* (defaults, projectFolder) {
2045
+ const pathService = yield* Path10.Path;
1648
2046
  const outputDirectory = pathService.join(projectFolder, "out");
1649
2047
  const files = yield* getDefaultPathMap(outputDirectory);
1650
2048
  const assetPaths = [];
@@ -1667,8 +2065,8 @@ var createStaticExportConfig = Effect8.fn("nextjs.createStaticExportConfig")(fun
1667
2065
  package: void 0
1668
2066
  };
1669
2067
  });
1670
- var createStandaloneConfig = Effect8.fn("nextjs.createStandaloneConfig")(function* (defaults, projectFolder, manifest) {
1671
- const pathService = yield* Path7.Path;
2068
+ var createStandaloneConfig = Effect13.fn("nextjs.createStandaloneConfig")(function* (defaults, projectFolder, manifest) {
2069
+ const pathService = yield* Path10.Path;
1672
2070
  const resolved = yield* resolveStandaloneServer(projectFolder, manifest.distDir, manifest.repoRootToProject);
1673
2071
  if (!resolved) return defaults;
1674
2072
  const { standaloneRoot, serverDirectory, entrypoint } = resolved;
@@ -1701,7 +2099,7 @@ var createStandaloneConfig = Effect8.fn("nextjs.createStandaloneConfig")(functio
1701
2099
  }
1702
2100
  };
1703
2101
  });
1704
- var createStandaloneV2Config = Effect8.fn("nextjs.createStandaloneV2Config")(function* (defaults, projectFolder, manifest) {
2102
+ var createStandaloneV2Config = Effect13.fn("nextjs.createStandaloneV2Config")(function* (defaults, projectFolder, manifest) {
1705
2103
  const resolved = yield* resolveStandaloneServer(projectFolder, manifest.distDir, manifest.repoRootToProject);
1706
2104
  if (!resolved) return defaults;
1707
2105
  const { standaloneRoot, serverDirectory, entrypoint } = resolved;
@@ -1809,9 +2207,9 @@ var nextjs = {
1809
2207
  routes: [{ source: "/*", destination: ".next/standalone/server.js" }],
1810
2208
  environmentVariables: { NODE_ENV: "production" }
1811
2209
  }),
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)));
2210
+ refineDefaultConfig: (defaults, projectFolder) => Effect13.gen(function* () {
2211
+ const fs = yield* FileSystem11.FileSystem;
2212
+ const manifestContent = yield* fs.readFileString(`${projectFolder}/.gigadrive/nextjs.json`).pipe(Effect13.catchAll(() => Effect13.succeed(void 0)));
1815
2213
  const manifest = manifestContent ? parseGigadriveNextBuildManifest(manifestContent) : void 0;
1816
2214
  if (!manifest) return defaults;
1817
2215
  if (manifest.version === 2) {
@@ -1822,8 +2220,8 @@ var nextjs = {
1822
2220
  };
1823
2221
 
1824
2222
  // src/detection/frameworks/nuxt.ts
1825
- import { FileSystem as FileSystem9 } from "@effect/platform";
1826
- import { Effect as Effect9 } from "effect";
2223
+ import { FileSystem as FileSystem12 } from "@effect/platform";
2224
+ import { Effect as Effect14 } from "effect";
1827
2225
  var isVercelBuildOutputV3 = (content) => {
1828
2226
  try {
1829
2227
  const config = JSON.parse(content);
@@ -1850,9 +2248,9 @@ var nuxt = {
1850
2248
  routes: [{ source: "/*", destination: ".output/server/index.mjs" }],
1851
2249
  environmentVariables: { NODE_ENV: "production", NITRO_PRESET: "node-server" }
1852
2250
  }),
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)));
2251
+ refineDefaultConfig: (defaults, projectFolder) => Effect14.gen(function* () {
2252
+ const fs = yield* FileSystem12.FileSystem;
2253
+ const buildOutputConfig = yield* fs.readFileString(`${projectFolder}/.vercel/output/config.json`).pipe(Effect14.catchAll(() => Effect14.succeed(void 0)));
1856
2254
  if (!buildOutputConfig || !isVercelBuildOutputV3(buildOutputConfig)) {
1857
2255
  return defaults;
1858
2256
  }
@@ -1867,16 +2265,16 @@ var nuxt = {
1867
2265
  };
1868
2266
 
1869
2267
  // src/detection/frameworks/php.ts
1870
- import { FileSystem as FileSystem10, Path as Path8 } from "@effect/platform";
1871
- import { Effect as Effect10 } from "effect";
2268
+ import { FileSystem as FileSystem13, Path as Path11 } from "@effect/platform";
2269
+ import { Effect as Effect15 } from "effect";
1872
2270
  var COMPOSER_FILES = ["composer.json", "composer.lock"];
1873
2271
  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;
2272
+ var refinePhpDocumentRoot = (defaults, projectFolder) => Effect15.gen(function* () {
2273
+ const fs = yield* FileSystem13.FileSystem;
2274
+ const pathService = yield* Path11.Path;
1877
2275
  for (const documentRoot of DOCUMENT_ROOTS) {
1878
2276
  const frontController = pathService.join(projectFolder, documentRoot, "index.php");
1879
- if (yield* fs.exists(frontController).pipe(Effect10.catchAll(() => Effect10.succeed(false)))) {
2277
+ if (yield* fs.exists(frontController).pipe(Effect15.catchAll(() => Effect15.succeed(false)))) {
1880
2278
  return phpFrontControllerDefaults({ documentRoot, excludeFiles: COMPOSER_FILES });
1881
2279
  }
1882
2280
  }
@@ -1900,12 +2298,12 @@ var phpSites = DOCUMENT_ROOTS.map((documentRoot) => ({
1900
2298
  detectors: [{ path: frontControllerPath(documentRoot) }],
1901
2299
  priority: 6,
1902
2300
  getDefaultConfig: () => ({ ...getDefaultConfig(), installCommand: "" }),
1903
- refineDefaultConfig: (defaults, projectFolder) => refinePhpDocumentRoot(defaults, projectFolder).pipe(Effect10.map((refined) => ({ ...refined, installCommand: "" })))
2301
+ refineDefaultConfig: (defaults, projectFolder) => refinePhpDocumentRoot(defaults, projectFolder).pipe(Effect15.map((refined) => ({ ...refined, installCommand: "" })))
1904
2302
  }));
1905
2303
 
1906
2304
  // 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";
2305
+ import { FileSystem as FileSystem14, Path as Path12 } from "@effect/platform";
2306
+ import { Effect as Effect16, Option as Option3 } from "effect";
1909
2307
 
1910
2308
  // src/detection/frameworks/composer-constraint.ts
1911
2309
  var STABILITY_SUFFIX = /-(?:dev|alpha|beta|a|b|rc|patch|pl|p|stable)\.?\d*$/i;
@@ -2029,31 +2427,86 @@ var PHP_RUNTIME_CANDIDATES = [
2029
2427
  { runtime: "php-83", newestVersion: "8.3.9999" }
2030
2428
  ];
2031
2429
  var phpRuntimeForConstraint = (constraint) => PHP_RUNTIME_CANDIDATES.find(({ newestVersion }) => composerConstraintAllows(constraint, newestVersion) === true)?.runtime;
2032
- var readPhpConstraint = Effect11.fn("readPhpConstraint")(
2430
+ var readPhpConstraint = Effect16.fn("readPhpConstraint")(
2033
2431
  function* (projectFolder) {
2034
- const fs = yield* FileSystem11.FileSystem;
2035
- const pathService = yield* Path9.Path;
2432
+ const fs = yield* FileSystem14.FileSystem;
2433
+ const pathService = yield* Path12.Path;
2036
2434
  const content = yield* fs.readFileString(pathService.join(projectFolder, "composer.json"));
2037
- const manifest = yield* Effect11.try(() => JSON.parse(content));
2435
+ const manifest = yield* Effect16.try(() => JSON.parse(content));
2038
2436
  const requires = manifest && typeof manifest === "object" && "require" in manifest ? manifest.require : void 0;
2039
2437
  const php = requires && typeof requires === "object" && "php" in requires ? requires.php : void 0;
2040
2438
  return typeof php === "string" ? Option3.some(php) : Option3.none();
2041
2439
  },
2042
- Effect11.catchAll(() => Effect11.succeed(Option3.none()))
2440
+ Effect16.catchAll(() => Effect16.succeed(Option3.none()))
2043
2441
  );
2044
- var refineComposerPhpRuntime = Effect11.fn("refineComposerPhpRuntime")(function* (defaults, projectFolder) {
2442
+ var refineComposerPhpRuntime = Effect16.fn("refineComposerPhpRuntime")(function* (defaults, projectFolder) {
2045
2443
  const constraint = yield* readPhpConstraint(projectFolder);
2046
2444
  const runtime = Option3.getOrUndefined(Option3.flatMapNullable(constraint, phpRuntimeForConstraint));
2047
2445
  return runtime ? { ...defaults, runtime } : defaults;
2048
2446
  });
2049
2447
  var withComposerPhpRuntime = (framework) => ({
2050
2448
  ...framework,
2051
- refineDefaultConfig: (defaults, projectFolder) => Effect11.gen(function* () {
2449
+ refineDefaultConfig: (defaults, projectFolder) => Effect16.gen(function* () {
2052
2450
  const refined = framework.refineDefaultConfig ? yield* framework.refineDefaultConfig(defaults, projectFolder) : defaults;
2053
2451
  return yield* refineComposerPhpRuntime(refined, projectFolder);
2054
2452
  })
2055
2453
  });
2056
2454
 
2455
+ // src/detection/frameworks/rack.ts
2456
+ var rack = {
2457
+ slug: "rack",
2458
+ name: "Rack",
2459
+ language: "ruby",
2460
+ detectors: [{ path: "config.ru" }, { path: "Gemfile" }],
2461
+ priority: 10,
2462
+ getDefaultConfig: () => rubyServerDefaults({ environmentVariables: { RACK_ENV: "production" } }),
2463
+ refineDefaultConfig: refineRubyPublicDirectory
2464
+ };
2465
+
2466
+ // src/detection/frameworks/rails.ts
2467
+ import { Effect as Effect17 } from "effect";
2468
+ var ASSET_PIPELINE_GEMS = ["propshaft", "sprockets", "sprockets-rails"];
2469
+ var refineRailsAssets = Effect17.fn("refineRailsAssets")(function* (defaults, projectFolder) {
2470
+ const gems = yield* readDependencies(projectFolder, "ruby").pipe(
2471
+ Effect17.catchAll(() => Effect17.succeed(/* @__PURE__ */ new Set()))
2472
+ );
2473
+ const withPublicDirectory = yield* refineRubyPublicDirectory(defaults, projectFolder);
2474
+ return ASSET_PIPELINE_GEMS.some((gem) => gems.has(gem)) ? {
2475
+ ...withPublicDirectory,
2476
+ commands: [...withPublicDirectory.commands, "SECRET_KEY_BASE_DUMMY=1 bundle exec rails assets:precompile"]
2477
+ } : withPublicDirectory;
2478
+ });
2479
+ var rails = {
2480
+ slug: "rails",
2481
+ name: "Ruby on Rails",
2482
+ language: "ruby",
2483
+ // `railties` is in every Rails application's Gemfile.lock, including ones
2484
+ // that require individual Rails gems instead of `rails`.
2485
+ detectors: [{ matchPackage: "railties" }, { path: "config/application.rb" }],
2486
+ priority: 80,
2487
+ getDefaultConfig: () => rubyServerDefaults({
2488
+ memory: 512,
2489
+ excludeFiles: ["tmp/", "log/", "storage/", "test/", "spec/", "node_modules/", ".git/"],
2490
+ // tmp/, log/ and storage/ are excluded, so the directories Rails writes
2491
+ // caches, pids, sockets, logs and Active Storage files to are created empty.
2492
+ writablePaths: ["tmp/cache", "tmp/pids", "tmp/sockets", "tmp/storage", "log", "storage"],
2493
+ environmentVariables: {
2494
+ RAILS_ENV: "production",
2495
+ RACK_ENV: "production",
2496
+ // Signs and encrypts cookies and sessions; Rails refuses to boot in production without it.
2497
+ SECRET_KEY_BASE: generatedSecret("hex"),
2498
+ RAILS_LOG_TO_STDOUT: "1",
2499
+ RAILS_SERVE_STATIC_FILES: "1",
2500
+ RAILS_MAX_THREADS: "5"
2501
+ }
2502
+ }),
2503
+ refineDefaultConfig: refineRailsAssets
2504
+ };
2505
+ var railsPresets = [
2506
+ rails,
2507
+ { ...rails, detectors: [{ matchPackage: "rails" }, { path: "config/application.rb" }] }
2508
+ ];
2509
+
2057
2510
  // src/detection/frameworks/remix.ts
2058
2511
  var remix = {
2059
2512
  slug: "remix",
@@ -2075,6 +2528,45 @@ var remix = {
2075
2528
  })
2076
2529
  };
2077
2530
 
2531
+ // src/detection/frameworks/roda.ts
2532
+ var roda = {
2533
+ slug: "roda",
2534
+ name: "Roda",
2535
+ language: "ruby",
2536
+ detectors: [{ matchPackage: "roda" }, { path: "config.ru" }],
2537
+ priority: 60,
2538
+ getDefaultConfig: () => rubyServerDefaults({ environmentVariables: { RACK_ENV: "production" } }),
2539
+ refineDefaultConfig: refineRubyPublicDirectory
2540
+ };
2541
+
2542
+ // src/detection/frameworks/sinatra.ts
2543
+ import { FileSystem as FileSystem15, Path as Path13 } from "@effect/platform";
2544
+ import { Effect as Effect18 } from "effect";
2545
+ var SINATRA_ENTRYPOINTS = ["config.ru", "app.rb", "main.rb", "server.rb", "application.rb"];
2546
+ var refineSinatraEntrypoint = Effect18.fn("refineSinatraEntrypoint")(function* (defaults, projectFolder) {
2547
+ const fs = yield* FileSystem15.FileSystem;
2548
+ const pathService = yield* Path13.Path;
2549
+ const entrypoint = yield* Effect18.findFirst(
2550
+ SINATRA_ENTRYPOINTS,
2551
+ (file) => fs.exists(pathService.join(projectFolder, file)).pipe(Effect18.catchAll(() => Effect18.succeed(false)))
2552
+ );
2553
+ const withPublicDirectory = yield* refineRubyPublicDirectory(defaults, projectFolder);
2554
+ return entrypoint._tag === "Some" ? {
2555
+ ...withPublicDirectory,
2556
+ entrypoint: entrypoint.value,
2557
+ routes: [{ source: "/*", destination: entrypoint.value }]
2558
+ } : withPublicDirectory;
2559
+ });
2560
+ var sinatra = {
2561
+ slug: "sinatra",
2562
+ name: "Sinatra",
2563
+ language: "ruby",
2564
+ detectors: [{ matchPackage: "sinatra" }],
2565
+ priority: 60,
2566
+ getDefaultConfig: () => rubyServerDefaults({ environmentVariables: { APP_ENV: "production", RACK_ENV: "production" } }),
2567
+ refineDefaultConfig: refineSinatraEntrypoint
2568
+ };
2569
+
2078
2570
  // src/detection/frameworks/slim.ts
2079
2571
  var slim = {
2080
2572
  slug: "slim",
@@ -2195,17 +2687,33 @@ var FRAMEWORK_DEFINITIONS = [
2195
2687
  mezzio,
2196
2688
  yii,
2197
2689
  slim,
2690
+ ...railsPresets,
2691
+ hanami,
2692
+ ...jekyllPresets,
2693
+ bridgetown,
2694
+ sinatra,
2695
+ roda,
2198
2696
  hono,
2199
2697
  elysia,
2200
2698
  fastify,
2201
2699
  express,
2700
+ rack,
2202
2701
  ...phpComposerProjects,
2203
2702
  ...phpSites,
2204
2703
  vite
2205
- ].map((framework) => framework.language === "php" ? withComposerPhpRuntime(framework) : framework).sort((a, b) => b.priority - a.priority);
2704
+ ].map((framework) => {
2705
+ switch (framework.language) {
2706
+ case "php":
2707
+ return withComposerPhpRuntime(framework);
2708
+ case "ruby":
2709
+ return withRubyRuntime(framework);
2710
+ case "node":
2711
+ return framework;
2712
+ }
2713
+ }).sort((a, b) => b.priority - a.priority);
2206
2714
 
2207
2715
  // src/detection/generate-config.ts
2208
- import { Effect as Effect12 } from "effect";
2716
+ import { Effect as Effect19 } from "effect";
2209
2717
  var getInstallCommand = (pm) => {
2210
2718
  switch (pm) {
2211
2719
  case "bun":
@@ -2216,6 +2724,8 @@ var getInstallCommand = (pm) => {
2216
2724
  return "yarn install";
2217
2725
  case "composer":
2218
2726
  return "composer install";
2727
+ case "bundler":
2728
+ return "bundle install";
2219
2729
  case "npm":
2220
2730
  default:
2221
2731
  return "npm install";
@@ -2226,11 +2736,17 @@ var isPrivatePhpProjectFile = (projectPath) => {
2226
2736
  const segments = projectPath.split("/").filter((segment) => segment !== "" && segment !== ".");
2227
2737
  return segments.some((segment) => segment.startsWith(".")) || segments[0] === "vendor" || segments[0] === "node_modules" || segments.length === 1 && COMPOSER_ROOT_FILES.has(segments[0] ?? "");
2228
2738
  };
2229
- var generateConfig = Effect12.fn("generateConfig")(function* (framework, packageManager, projectFolder, refinedDefaults) {
2739
+ var BUNDLER_FILES = /* @__PURE__ */ new Set(["Gemfile", "Gemfile.lock", "gems.rb", "gems.locked"]);
2740
+ var isPrivateRubyProjectFile = (projectPath) => {
2741
+ const segments = projectPath.split("/").filter((segment) => segment !== "" && segment !== ".");
2742
+ const fileName = segments.at(-1) ?? "";
2743
+ return segments.some((segment) => segment.startsWith(".")) || segments[0] === "vendor" || /\.(rb|ru)$/i.test(fileName) || BUNDLER_FILES.has(fileName);
2744
+ };
2745
+ var generateConfig = Effect19.fn("generateConfig")(function* (framework, packageManager, projectFolder, refinedDefaults) {
2230
2746
  const defaults = refinedDefaults ?? framework.getDefaultConfig(packageManager);
2231
2747
  const installCmd = defaults.installCommand ?? getInstallCommand(packageManager);
2232
2748
  const commands = installCmd ? [installCmd, ...defaults.commands] : [...defaults.commands];
2233
- yield* Effect12.logDebug(`Generating config for ${framework.name}`, {
2749
+ yield* Effect19.logDebug(`Generating config for ${framework.name}`, {
2234
2750
  runtime: defaults.runtime,
2235
2751
  entrypoint: defaults.entrypoint,
2236
2752
  commands
@@ -2273,6 +2789,7 @@ var generateConfig = Effect12.fn("generateConfig")(function* (framework, package
2273
2789
  for (const file of yield* collectAssetFiles(projectFolder, assetsDir)) {
2274
2790
  if (framework.language === "php" && /\.(php|phtml|phar)$/i.test(file)) continue;
2275
2791
  if (framework.language === "php" && isPrivatePhpProjectFile(`${assetsDir}/${file}`)) continue;
2792
+ if (framework.language === "ruby" && isPrivateRubyProjectFile(`${assetsDir}/${file}`)) continue;
2276
2793
  paths.push(`${assetsDir}/${file}`);
2277
2794
  if (!servesDirectoryIndexes || file in overrides) continue;
2278
2795
  if (file === "index.html") {
@@ -2295,80 +2812,10 @@ var generateConfig = Effect12.fn("generateConfig")(function* (framework, package
2295
2812
  return config;
2296
2813
  });
2297
2814
 
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
2815
  // 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;
2816
+ var matchesDetectionItem = Effect20.fn("matchesDetectionItem")(function* (item, projectFolder, framework, cachedReadDeps) {
2817
+ const fs = yield* FileSystem16.FileSystem;
2818
+ const pathService = yield* Path14.Path;
2372
2819
  if (item.matchPackage != null) {
2373
2820
  const deps = yield* cachedReadDeps(`${projectFolder}\0${framework.language}`);
2374
2821
  if (!deps.has(item.matchPackage)) {
@@ -2377,12 +2824,12 @@ var matchesDetectionItem = Effect15.fn("matchesDetectionItem")(function* (item,
2377
2824
  }
2378
2825
  if (item.path != null) {
2379
2826
  const filePath = pathService.join(projectFolder, item.path);
2380
- const exists = yield* fs.exists(filePath).pipe(Effect15.catchAll(() => Effect15.succeed(false)));
2827
+ const exists = yield* fs.exists(filePath).pipe(Effect20.catchAll(() => Effect20.succeed(false)));
2381
2828
  if (!exists) {
2382
2829
  return false;
2383
2830
  }
2384
2831
  if (item.matchContent != null) {
2385
- const content = yield* fs.readFileString(filePath).pipe(Effect15.catchAll(() => Effect15.succeed("")));
2832
+ const content = yield* fs.readFileString(filePath).pipe(Effect20.catchAll(() => Effect20.succeed("")));
2386
2833
  let regexMatch = false;
2387
2834
  try {
2388
2835
  regexMatch = new RegExp(item.matchContent).test(content);
@@ -2395,7 +2842,7 @@ var matchesDetectionItem = Effect15.fn("matchesDetectionItem")(function* (item,
2395
2842
  }
2396
2843
  return true;
2397
2844
  });
2398
- var matchesFramework = Effect15.fn("matchesFramework")(function* (framework, projectFolder, cachedReadDeps) {
2845
+ var matchesFramework = Effect20.fn("matchesFramework")(function* (framework, projectFolder, cachedReadDeps) {
2399
2846
  for (const detector of framework.detectors) {
2400
2847
  const matches = yield* matchesDetectionItem(detector, projectFolder, framework, cachedReadDeps);
2401
2848
  if (!matches) {
@@ -2404,9 +2851,19 @@ var matchesFramework = Effect15.fn("matchesFramework")(function* (framework, pro
2404
2851
  }
2405
2852
  return true;
2406
2853
  });
2407
- var detectFramework = Effect15.fn("detectFramework")(function* (projectFolder) {
2408
- yield* Effect15.logDebug(`Detecting framework in ${projectFolder}`);
2409
- const cachedReadDeps = yield* Effect15.cachedFunction((key) => {
2854
+ var packageManagerForLanguage = (language, detected) => {
2855
+ switch (language) {
2856
+ case "php":
2857
+ return "composer";
2858
+ case "ruby":
2859
+ return "bundler";
2860
+ case "node":
2861
+ return detected === "bundler" ? "npm" : detected;
2862
+ }
2863
+ };
2864
+ var detectFramework = Effect20.fn("detectFramework")(function* (projectFolder) {
2865
+ yield* Effect20.logDebug(`Detecting framework in ${projectFolder}`);
2866
+ const cachedReadDeps = yield* Effect20.cachedFunction((key) => {
2410
2867
  const sepIndex = key.lastIndexOf("\0");
2411
2868
  const folder = key.slice(0, sepIndex);
2412
2869
  const language = key.slice(sepIndex + 1);
@@ -2415,16 +2872,16 @@ var detectFramework = Effect15.fn("detectFramework")(function* (projectFolder) {
2415
2872
  for (const framework of FRAMEWORK_DEFINITIONS) {
2416
2873
  const matches = yield* matchesFramework(framework, projectFolder, cachedReadDeps);
2417
2874
  if (matches) {
2418
- yield* Effect15.log(`Detected framework: ${framework.name}`, { slug: framework.slug });
2875
+ yield* Effect20.log(`Detected framework: ${framework.name}`, { slug: framework.slug });
2419
2876
  const detectedPackageManager = yield* detectPackageManager(projectFolder);
2420
- const packageManager = framework.language === "php" ? "composer" : detectedPackageManager;
2877
+ const packageManager = packageManagerForLanguage(framework.language, detectedPackageManager);
2421
2878
  const defaults = framework.getDefaultConfig(packageManager);
2422
2879
  const refinedDefaults = framework.refineDefaultConfig ? yield* framework.refineDefaultConfig(defaults, projectFolder) : defaults;
2423
2880
  const config = yield* generateConfig(framework, packageManager, projectFolder, refinedDefaults);
2424
2881
  return { framework, packageManager, config };
2425
2882
  }
2426
2883
  }
2427
- return yield* Effect15.fail(
2884
+ return yield* Effect20.fail(
2428
2885
  new FrameworkNotDetectedError({
2429
2886
  message: `No framework detected in project directory`,
2430
2887
  directory: projectFolder
@@ -2433,9 +2890,9 @@ var detectFramework = Effect15.fn("detectFramework")(function* (projectFolder) {
2433
2890
  });
2434
2891
 
2435
2892
  // 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");
2893
+ import { Effect as Effect21 } from "effect";
2894
+ var mergeWithFrameworkDefaults = Effect21.fn("mergeWithFrameworkDefaults")(function* (userConfig, frameworkConfig) {
2895
+ yield* Effect21.logDebug("Merging user config with framework defaults");
2439
2896
  const userHasAssets = (userConfig.assets?.paths?.length ?? 0) > 0 || (userConfig.assets?.prefixes?.length ?? 0) > 0 || (userConfig.assets?.manifests?.length ?? 0) > 0;
2440
2897
  const isContainer = (entrypoint) => entrypoint.runtime === CONTAINER_RUNTIME;
2441
2898
  const userFileFunctions = userConfig.entrypoints.filter((entrypoint) => !isContainer(entrypoint));
@@ -2476,23 +2933,23 @@ var filterFunctionsFromAssets = (config) => {
2476
2933
  };
2477
2934
 
2478
2935
  // src/parse-config.ts
2479
- import { Effect as Effect22 } from "effect";
2936
+ import { Effect as Effect27 } from "effect";
2480
2937
 
2481
2938
  // src/services/raw-config-reader.ts
2482
- import { FileSystem as FileSystem14, Path as Path12 } from "@effect/platform";
2483
- import { Effect as Effect18 } from "effect";
2939
+ import { FileSystem as FileSystem17, Path as Path15 } from "@effect/platform";
2940
+ import { Effect as Effect23 } from "effect";
2484
2941
  import { parse as parseYaml2 } from "yaml";
2485
2942
 
2486
2943
  // src/services/config-module-loader.ts
2487
- import { Effect as Effect17 } from "effect";
2944
+ import { Effect as Effect22 } from "effect";
2488
2945
  import { createJiti } from "jiti";
2489
2946
  var MISSING_DEFAULT_EXPORT = /* @__PURE__ */ Symbol("MissingDefaultExport");
2490
2947
  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) {
2948
+ var ConfigModuleLoader = class extends Effect22.Service()("ConfigModuleLoader", {
2949
+ effect: Effect22.gen(function* () {
2950
+ const loadConfigModule = Effect22.fn("ConfigModuleLoader.loadConfigModule")(function* (filePath) {
2494
2951
  const extension = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
2495
- const mod = yield* Effect17.tryPromise({
2952
+ const mod = yield* Effect22.tryPromise({
2496
2953
  try: async () => {
2497
2954
  const jiti = createJiti(filePath, { fsCache: false, interopDefault: true, moduleCache: false });
2498
2955
  const namespace = await jiti.import(filePath);
@@ -2511,7 +2968,7 @@ var ConfigModuleLoader = class extends Effect17.Service()("ConfigModuleLoader",
2511
2968
  })
2512
2969
  });
2513
2970
  if (mod === MISSING_DEFAULT_EXPORT) {
2514
- return yield* Effect17.fail(
2971
+ return yield* Effect22.fail(
2515
2972
  new ConfigModuleLoadError({
2516
2973
  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
2974
  filePath
@@ -2519,7 +2976,7 @@ var ConfigModuleLoader = class extends Effect17.Service()("ConfigModuleLoader",
2519
2976
  );
2520
2977
  }
2521
2978
  if (typeof mod === "function") {
2522
- return yield* Effect17.fail(
2979
+ return yield* Effect22.fail(
2523
2980
  new ConfigModuleLoadError({
2524
2981
  message: `Config module at ${filePath} default-exports a function; config factories are not supported. Export a config object instead (optionally wrapped in defineConfig).`,
2525
2982
  filePath
@@ -2527,7 +2984,7 @@ var ConfigModuleLoader = class extends Effect17.Service()("ConfigModuleLoader",
2527
2984
  );
2528
2985
  }
2529
2986
  if (typeof mod !== "object" || mod === null || Array.isArray(mod)) {
2530
- return yield* Effect17.fail(
2987
+ return yield* Effect22.fail(
2531
2988
  new ConfigModuleLoadError({
2532
2989
  message: `Config module at ${filePath} must default-export a config object.`,
2533
2990
  filePath
@@ -2557,36 +3014,36 @@ var ALLOWED_CONFIG_NAMES = [
2557
3014
  "nebula.json"
2558
3015
  ];
2559
3016
  var MODULE_EXTENSIONS = [".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"];
2560
- var RawConfigReader = class extends Effect18.Service()("RawConfigReader", {
3017
+ var RawConfigReader = class extends Effect23.Service()("RawConfigReader", {
2561
3018
  dependencies: [ConfigModuleLoader.Default],
2562
- effect: Effect18.gen(function* () {
2563
- const fs = yield* FileSystem14.FileSystem;
2564
- const pathService = yield* Path12.Path;
3019
+ effect: Effect23.gen(function* () {
3020
+ const fs = yield* FileSystem17.FileSystem;
3021
+ const pathService = yield* Path15.Path;
2565
3022
  const moduleLoader = yield* ConfigModuleLoader;
2566
- const findConfig = Effect18.fn("RawConfigReader.findConfig")(function* (projectFolder) {
3023
+ const findConfig = Effect23.fn("RawConfigReader.findConfig")(function* (projectFolder) {
2567
3024
  for (const name of ALLOWED_CONFIG_NAMES) {
2568
3025
  const filePath = pathService.join(projectFolder, name);
2569
- const exists = yield* fs.exists(filePath).pipe(Effect18.catchAll(() => Effect18.succeed(false)));
3026
+ const exists = yield* fs.exists(filePath).pipe(Effect23.catchAll(() => Effect23.succeed(false)));
2570
3027
  if (exists) {
2571
3028
  return filePath;
2572
3029
  }
2573
3030
  }
2574
3031
  return null;
2575
3032
  });
2576
- const readRawConfig = Effect18.fn("RawConfigReader.readRawConfig")(function* (filePath, options) {
2577
- const exists = yield* fs.exists(filePath).pipe(Effect18.catchAll(() => Effect18.succeed(false)));
3033
+ const readRawConfig = Effect23.fn("RawConfigReader.readRawConfig")(function* (filePath, options) {
3034
+ const exists = yield* fs.exists(filePath).pipe(Effect23.catchAll(() => Effect23.succeed(false)));
2578
3035
  if (!exists) {
2579
- return yield* Effect18.fail(
3036
+ return yield* Effect23.fail(
2580
3037
  new ConfigFileNotFoundError({ message: `Config file not found at ${filePath}`, filePath })
2581
3038
  );
2582
3039
  }
2583
3040
  const fileContents = yield* fs.readFileString(filePath).pipe(
2584
- Effect18.mapError(
3041
+ Effect23.mapError(
2585
3042
  () => new ConfigFileParseError({ message: `Failed to read config file at ${filePath}`, filePath })
2586
3043
  )
2587
3044
  );
2588
3045
  if (fileContents.length === 0) {
2589
- return yield* Effect18.fail(
3046
+ return yield* Effect23.fail(
2590
3047
  new ConfigFileEmptyError({ message: `Config file is empty at ${filePath}`, filePath })
2591
3048
  );
2592
3049
  }
@@ -2602,7 +3059,7 @@ var RawConfigReader = class extends Effect18.Service()("RawConfigReader", {
2602
3059
  parsed = parseYaml2(fileContents);
2603
3060
  }
2604
3061
  } catch (error) {
2605
- return yield* Effect18.fail(
3062
+ return yield* Effect23.fail(
2606
3063
  new ConfigFileParseError({
2607
3064
  message: `Failed to parse config file at ${filePath}: ${error instanceof Error ? error.message : "Unknown error"}`,
2608
3065
  filePath,
@@ -2612,21 +3069,21 @@ var RawConfigReader = class extends Effect18.Service()("RawConfigReader", {
2612
3069
  }
2613
3070
  }
2614
3071
  if (parsed == null) {
2615
- return yield* Effect18.fail(
3072
+ return yield* Effect23.fail(
2616
3073
  new ConfigFileParseError({ message: `Config file could not be parsed at ${filePath}`, filePath })
2617
3074
  );
2618
3075
  }
2619
3076
  if (!options?.disableVersionCheck && typeof parsed.version !== "number") {
2620
- return yield* Effect18.fail(
3077
+ return yield* Effect23.fail(
2621
3078
  new ConfigVersionError({ message: `Config file is missing version at ${filePath}`, filePath })
2622
3079
  );
2623
3080
  }
2624
3081
  return parsed;
2625
3082
  });
2626
3083
  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")
3084
+ Effect23.map((parsed) => parsed),
3085
+ Effect23.catchTag("ConfigFileNotFoundError", () => Effect23.succeed(null)),
3086
+ Effect23.withSpan("RawConfigReader.readConfigFile")
2630
3087
  );
2631
3088
  return { findConfig, readRawConfig, readConfigFile };
2632
3089
  })
@@ -2636,17 +3093,17 @@ var RawConfigReader = class extends Effect18.Service()("RawConfigReader", {
2636
3093
  // src/services/schema-validator.ts
2637
3094
  import Ajv from "ajv";
2638
3095
  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* () {
3096
+ import { Effect as Effect24 } from "effect";
3097
+ var SchemaValidator = class extends Effect24.Service()("SchemaValidator", {
3098
+ effect: Effect24.gen(function* () {
2642
3099
  const ajv = new Ajv();
2643
3100
  addFormats(ajv);
2644
- const validate = Effect19.fn("SchemaValidator.validate")(function* (config, schema, filePath) {
3101
+ const validate = Effect24.fn("SchemaValidator.validate")(function* (config, schema, filePath) {
2645
3102
  const compiledValidate = ajv.compile(schema);
2646
3103
  const valid = compiledValidate(config);
2647
3104
  if (!valid) {
2648
3105
  const errors = compiledValidate.errors?.map((e) => `${e.instancePath || "/"} ${e.message ?? ""}`.trim()) ?? [];
2649
- return yield* Effect19.fail(
3106
+ return yield* Effect24.fail(
2650
3107
  new ConfigSchemaValidationError({
2651
3108
  message: `Config file at ${filePath} is invalid: ${ajv.errorsText(compiledValidate.errors)}`,
2652
3109
  filePath,
@@ -2702,7 +3159,7 @@ var getFilesForPattern = async (pattern, projectFolder, excludeFiles = []) => {
2702
3159
  };
2703
3160
 
2704
3161
  // src/services/v4-config-parser.ts
2705
- import { Effect as Effect20 } from "effect";
3162
+ import { Effect as Effect25 } from "effect";
2706
3163
  import { minimatch as minimatch2 } from "minimatch";
2707
3164
  import { posix as posix2 } from "path";
2708
3165
  import safeRegex from "safe-regex2";
@@ -2718,7 +3175,7 @@ var toArray = (value) => {
2718
3175
  if (value == null) return void 0;
2719
3176
  return Array.isArray(value) ? value : [value];
2720
3177
  };
2721
- var runtimeStreamsByDefault = (runtime) => runtime == null || runtime.startsWith("node-") || runtime.startsWith("bun-");
3178
+ var runtimeStreamsByDefault = (runtime) => runtime == null || runtime.startsWith("node-") || runtime.startsWith("bun-") || runtime.startsWith("ruby-");
2722
3179
  var normalizeImagePolicy = (images) => {
2723
3180
  if (!images) return void 0;
2724
3181
  return {
@@ -2853,7 +3310,7 @@ var mapRoute = (route, entrypoints) => ({
2853
3310
  negativeRequirements: route.missing,
2854
3311
  status: route.statusCode
2855
3312
  });
2856
- var parseEntrypoints = Effect20.fn("parseEntrypoints")(function* (config, projectFolder) {
3313
+ var parseEntrypoints = Effect25.fn("parseEntrypoints")(function* (config, projectFolder) {
2857
3314
  const entrypoints = [];
2858
3315
  const dockerFunctions = [];
2859
3316
  if (config.functions == null) return { entrypoints, dockerFunctions };
@@ -2864,7 +3321,7 @@ var parseEntrypoints = Effect20.fn("parseEntrypoints")(function* (config, projec
2864
3321
  functionPath: fnPath
2865
3322
  });
2866
3323
  }
2867
- const matchedFiles = yield* Effect20.tryPromise({
3324
+ const matchedFiles = yield* Effect25.tryPromise({
2868
3325
  try: () => getFilesForPattern(fnPath, projectFolder, func.excludeFiles),
2869
3326
  catch: (error) => new FunctionConfigError({
2870
3327
  message: `Failed to resolve files for function pattern '${fnPath}': ${error instanceof Error ? error.message : String(error)}`,
@@ -2939,13 +3396,13 @@ var parseEntrypoints = Effect20.fn("parseEntrypoints")(function* (config, projec
2939
3396
  }
2940
3397
  return { entrypoints, dockerFunctions };
2941
3398
  });
2942
- var collectAssets = Effect20.fn("collectAssets")(function* (config, projectFolder) {
3399
+ var collectAssets = Effect25.fn("collectAssets")(function* (config, projectFolder) {
2943
3400
  if (config.assets == null) return [];
2944
3401
  const assetNames = yield* collectAssetFiles(projectFolder, config.assets);
2945
3402
  return assetNames.filter((assetName) => getFunctionSettings(`${config.assets}/${assetName}`, config) == null).map((assetName) => `${config.assets}/${assetName}`);
2946
3403
  });
2947
3404
  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) {
3405
+ var parseContainers = Effect25.fn("parseContainers")(function* (config, projectFolder, fileEntrypoints, dockerFunctions) {
2949
3406
  const warnings = [];
2950
3407
  let containers = {};
2951
3408
  if (config.compose != null) {
@@ -2978,16 +3435,16 @@ var parseContainers = Effect20.fn("parseContainers")(function* (config, projectF
2978
3435
  }
2979
3436
  return { ...result, warnings };
2980
3437
  });
2981
- var V4ConfigParser = class extends Effect20.Service()("V4ConfigParser", {
3438
+ var V4ConfigParser = class extends Effect25.Service()("V4ConfigParser", {
2982
3439
  accessors: true,
2983
- effect: Effect20.succeed({
3440
+ effect: Effect25.succeed({
2984
3441
  /**
2985
3442
  * Parses a ConfigV4 into a NormalizedConfig.
2986
3443
  *
2987
3444
  * @param config - The raw V4 config object
2988
3445
  * @param projectFolder - Absolute path to the project root
2989
3446
  */
2990
- parse: Effect20.fn("V4ConfigParser.parse")(function* (config, projectFolder) {
3447
+ parse: Effect25.fn("V4ConfigParser.parse")(function* (config, projectFolder) {
2991
3448
  const { entrypoints: fileEntrypoints, dockerFunctions } = yield* parseEntrypoints(config, projectFolder);
2992
3449
  const containers = yield* parseContainers(config, projectFolder, fileEntrypoints, dockerFunctions);
2993
3450
  const entrypoints = [...fileEntrypoints, ...containers.entrypoints];
@@ -3029,7 +3486,7 @@ var V4ConfigParser = class extends Effect20.Service()("V4ConfigParser", {
3029
3486
  };
3030
3487
 
3031
3488
  // src/services/vercel-build-output-parser.ts
3032
- import { Path as Path13 } from "@effect/platform";
3489
+ import { Path as Path16 } from "@effect/platform";
3033
3490
 
3034
3491
  // ../commons/src/deep-merge.ts
3035
3492
  var deepMerge = (target, ...partials) => {
@@ -3058,7 +3515,7 @@ var deepMerge = (target, ...partials) => {
3058
3515
  };
3059
3516
 
3060
3517
  // src/services/vercel-build-output-parser.ts
3061
- import { Effect as Effect21 } from "effect";
3518
+ import { Effect as Effect26 } from "effect";
3062
3519
 
3063
3520
  // src/build-output-v3/determine-repo-root.ts
3064
3521
  import path from "path";
@@ -3154,11 +3611,11 @@ var translateVercelRuntime = (runtime) => {
3154
3611
  var CONFIG_PATH = ".vercel/output/config.json";
3155
3612
  var FUNCTIONS_FOLDER = ".vercel/output/functions";
3156
3613
  var FUNCTION_CONFIGS_PATTERN = `${FUNCTIONS_FOLDER}/**/*.func/.vc-config.json`;
3157
- var VercelBuildOutputParser = class extends Effect21.Service()("VercelBuildOutputParser", {
3158
- effect: Effect21.gen(function* () {
3614
+ var VercelBuildOutputParser = class extends Effect26.Service()("VercelBuildOutputParser", {
3615
+ effect: Effect26.gen(function* () {
3159
3616
  const rawConfigReader = yield* RawConfigReader;
3160
- const pathService = yield* Path13.Path;
3161
- const parse = Effect21.fn("VercelBuildOutputParser.parse")(function* (parseResult, projectFolder) {
3617
+ const pathService = yield* Path16.Path;
3618
+ const parse = Effect26.fn("VercelBuildOutputParser.parse")(function* (parseResult, projectFolder) {
3162
3619
  const config = yield* rawConfigReader.readConfigFile(pathService.join(projectFolder, CONFIG_PATH));
3163
3620
  if (!config || typeof config.version !== "number" || config.version < 3) {
3164
3621
  return parseResult;
@@ -3170,8 +3627,8 @@ var VercelBuildOutputParser = class extends Effect21.Service()("VercelBuildOutpu
3170
3627
  merged.regions = [...new Set(merged.regions)];
3171
3628
  return merged;
3172
3629
  });
3173
- const loadFunctions = Effect21.fn("VercelBuildOutputParser.loadFunctions")(function* (config, parseResult, projectFolder) {
3174
- const functionConfigs = yield* Effect21.tryPromise({
3630
+ const loadFunctions = Effect26.fn("VercelBuildOutputParser.loadFunctions")(function* (config, parseResult, projectFolder) {
3631
+ const functionConfigs = yield* Effect26.tryPromise({
3175
3632
  try: () => getFilesForPattern(FUNCTION_CONFIGS_PATTERN, projectFolder),
3176
3633
  catch: (error) => new ConfigFileParseError({
3177
3634
  message: `Failed to scan for function configs: ${error instanceof Error ? error.message : String(error)}`,
@@ -3468,7 +3925,7 @@ var schema_default = {
3468
3925
  },
3469
3926
  streaming: {
3470
3927
  type: "boolean",
3471
- description: "Enable function response streaming. When omitted, Node and Bun runtimes stream by default."
3928
+ description: "Enable function response streaming. When omitted, Node, Bun and Ruby runtimes stream by default."
3472
3929
  },
3473
3930
  schedule: {
3474
3931
  $ref: "#/$defs/schedule",
@@ -4034,7 +4491,19 @@ var schema_default = {
4034
4491
  },
4035
4492
  runtimes: {
4036
4493
  type: "string",
4037
- enum: ["php-84", "php-83", "php-81", "node-22", "node-20", "node-18", "node-16", "bun-1"]
4494
+ enum: [
4495
+ "php-84",
4496
+ "php-83",
4497
+ "php-81",
4498
+ "ruby-40",
4499
+ "ruby-34",
4500
+ "ruby-33",
4501
+ "node-22",
4502
+ "node-20",
4503
+ "node-18",
4504
+ "node-16",
4505
+ "bun-1"
4506
+ ]
4038
4507
  },
4039
4508
  matchRequirements: {
4040
4509
  description: "An array of requirements that are needed to match",
@@ -4088,7 +4557,7 @@ var schema_default = {
4088
4557
  };
4089
4558
 
4090
4559
  // src/parse-config.ts
4091
- var parseConfigRaw = Effect22.fn("parseConfigRaw")(function* (filePath, projectFolder) {
4560
+ var parseConfigRaw = Effect27.fn("parseConfigRaw")(function* (filePath, projectFolder) {
4092
4561
  const rawReader = yield* RawConfigReader;
4093
4562
  const validator = yield* SchemaValidator;
4094
4563
  const v4Parser = yield* V4ConfigParser;
@@ -4099,7 +4568,7 @@ var parseConfigRaw = Effect22.fn("parseConfigRaw")(function* (filePath, projectF
4099
4568
  };
4100
4569
  const schema = schemaMap[version];
4101
4570
  if (!schema) {
4102
- return yield* Effect22.fail(
4571
+ return yield* Effect27.fail(
4103
4572
  new ConfigVersionError({
4104
4573
  message: `Config file at ${filePath} has an unsupported version: ${version}`,
4105
4574
  filePath,
@@ -4110,11 +4579,11 @@ var parseConfigRaw = Effect22.fn("parseConfigRaw")(function* (filePath, projectF
4110
4579
  yield* validator.validate(parsed, schema, filePath);
4111
4580
  return yield* v4Parser.parse(parsed, projectFolder);
4112
4581
  });
4113
- var parseConfig = Effect22.fn("parseConfig")(function* (filePath, projectFolder) {
4582
+ var parseConfig = Effect27.fn("parseConfig")(function* (filePath, projectFolder) {
4114
4583
  const parseResult = yield* parseConfigRaw(filePath, projectFolder);
4115
4584
  return yield* postProcessConfig(parseResult, projectFolder);
4116
4585
  });
4117
- var postProcessConfig = Effect22.fn("postProcessConfig")(function* (config, projectFolder) {
4586
+ var postProcessConfig = Effect27.fn("postProcessConfig")(function* (config, projectFolder) {
4118
4587
  const vercelParser = yield* VercelBuildOutputParser;
4119
4588
  let result = yield* vercelParser.parse(config, projectFolder);
4120
4589
  const hasAssets = (result.assets?.paths?.length ?? 0) > 0 || (result.assets?.prefixes?.length ?? 0) > 0 || (result.assets?.manifests?.length ?? 0) > 0;
@@ -4162,6 +4631,9 @@ var RUNTIME_DEFINITIONS = [
4162
4631
  "php-84",
4163
4632
  "php-83",
4164
4633
  "php-81",
4634
+ "ruby-40",
4635
+ "ruby-34",
4636
+ "ruby-33",
4165
4637
  "node-22",
4166
4638
  "node-20",
4167
4639
  "node-18",
@@ -4196,6 +4668,7 @@ export {
4196
4668
  ContainerConfigError,
4197
4669
  DEFAULT_CONTAINER_MEMORY_MB,
4198
4670
  DEFAULT_FUNCTION_DURATION_SECONDS,
4671
+ DEFAULT_RUBY_RUNTIME,
4199
4672
  DEFAULT_SIDECAR_MEMORY_MB,
4200
4673
  FRAMEWORK_DEFINITIONS,
4201
4674
  FrameworkNotDetectedError,
@@ -4232,6 +4705,7 @@ export {
4232
4705
  detectContainerProject,
4233
4706
  detectFramework,
4234
4707
  detectPackageManager,
4708
+ detectRubyRuntime,
4235
4709
  dockerFunctionContainerName,
4236
4710
  filterFunctionsFromAssets,
4237
4711
  generateConfig,
@@ -4247,6 +4721,9 @@ export {
4247
4721
  postProcessConfig,
4248
4722
  readComposeContainers,
4249
4723
  readDependencies,
4724
+ rubyRuntimeForRequirement,
4725
+ rubyRuntimeForVersion,
4726
+ rubyRuntimeFromProjectFiles,
4250
4727
  splitCommandWords
4251
4728
  };
4252
4729
  //# sourceMappingURL=index.mjs.map