@gigadrive/network-config 5.3.1 → 5.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -46,6 +46,7 @@ __export(src_exports, {
46
46
  ContainerConfigError: () => ContainerConfigError,
47
47
  DEFAULT_CONTAINER_MEMORY_MB: () => DEFAULT_CONTAINER_MEMORY_MB,
48
48
  DEFAULT_FUNCTION_DURATION_SECONDS: () => DEFAULT_FUNCTION_DURATION_SECONDS,
49
+ DEFAULT_RUBY_RUNTIME: () => DEFAULT_RUBY_RUNTIME,
49
50
  DEFAULT_SIDECAR_MEMORY_MB: () => DEFAULT_SIDECAR_MEMORY_MB,
50
51
  FRAMEWORK_DEFINITIONS: () => FRAMEWORK_DEFINITIONS,
51
52
  FrameworkNotDetectedError: () => FrameworkNotDetectedError,
@@ -82,6 +83,7 @@ __export(src_exports, {
82
83
  detectContainerProject: () => detectContainerProject,
83
84
  detectFramework: () => detectFramework,
84
85
  detectPackageManager: () => detectPackageManager,
86
+ detectRubyRuntime: () => detectRubyRuntime,
85
87
  dockerFunctionContainerName: () => dockerFunctionContainerName,
86
88
  filterFunctionsFromAssets: () => filterFunctionsFromAssets,
87
89
  generateConfig: () => generateConfig,
@@ -97,6 +99,9 @@ __export(src_exports, {
97
99
  postProcessConfig: () => postProcessConfig,
98
100
  readComposeContainers: () => readComposeContainers,
99
101
  readDependencies: () => readDependencies,
102
+ rubyRuntimeForRequirement: () => rubyRuntimeForRequirement,
103
+ rubyRuntimeForVersion: () => rubyRuntimeForVersion,
104
+ rubyRuntimeFromProjectFiles: () => rubyRuntimeFromProjectFiles,
100
105
  splitCommandWords: () => splitCommandWords
101
106
  });
102
107
  module.exports = __toCommonJS(src_exports);
@@ -1008,8 +1013,8 @@ var detectContainerProject = import_effect6.Effect.fn("detectContainerProject")(
1008
1013
  });
1009
1014
 
1010
1015
  // src/detection/detect-framework.ts
1011
- var import_platform12 = require("@effect/platform");
1012
- var import_effect18 = require("effect");
1016
+ var import_platform16 = require("@effect/platform");
1017
+ var import_effect24 = require("effect");
1013
1018
 
1014
1019
  // src/detection/detect-package-manager.ts
1015
1020
  var import_platform4 = require("@effect/platform");
@@ -1019,7 +1024,10 @@ var LOCKFILE_MAP = [
1019
1024
  { files: ["pnpm-lock.yaml"], pm: "pnpm" },
1020
1025
  { files: ["yarn.lock"], pm: "yarn" },
1021
1026
  { files: ["package-lock.json"], pm: "npm" },
1022
- { files: ["composer.lock"], pm: "composer" }
1027
+ { files: ["composer.lock"], pm: "composer" },
1028
+ // A Gemfile is checked last and counts even without its lockfile: Bundler
1029
+ // resolves and writes Gemfile.lock on the first install.
1030
+ { files: ["Gemfile.lock", "Gemfile"], pm: "bundler" }
1023
1031
  ];
1024
1032
  var detectPackageManager = import_effect7.Effect.fn("detectPackageManager")(function* (projectFolder) {
1025
1033
  const fs = yield* import_platform4.FileSystem.FileSystem;
@@ -1058,6 +1066,192 @@ var astro = {
1058
1066
  })
1059
1067
  };
1060
1068
 
1069
+ // src/detection/frameworks/ruby-runtime.ts
1070
+ var import_platform5 = require("@effect/platform");
1071
+ var import_effect8 = require("effect");
1072
+
1073
+ // src/detection/frameworks/ruby-requirement.ts
1074
+ var RUBY_VERSION = /^(?:ruby-)?(\d+(?:\.\d+)*)(?:p\d+)?(?:[-.]?(?:preview|rc|dev|alpha|beta|pre)\d*)?$/i;
1075
+ var REQUIREMENT_ATOM = /^(~>|>=|<=|!=|=|>|<)?\s*(\S+)$/;
1076
+ var parseRubyVersion = (text) => {
1077
+ const match = RUBY_VERSION.exec(text);
1078
+ return match ? match[1].split(".").map(Number) : void 0;
1079
+ };
1080
+ var compareRubyVersions = (a, b) => {
1081
+ for (let index = 0; index < Math.max(a.length, b.length); index++) {
1082
+ const difference = (a[index] ?? 0) - (b[index] ?? 0);
1083
+ if (difference !== 0) {
1084
+ return difference;
1085
+ }
1086
+ }
1087
+ return 0;
1088
+ };
1089
+ var pessimisticUpperBound = (segments) => {
1090
+ const kept = segments.length > 1 ? segments.slice(0, -1) : [...segments];
1091
+ kept[kept.length - 1] += 1;
1092
+ return kept;
1093
+ };
1094
+ var parseRubyRequirement = (requirement) => {
1095
+ const parts = requirement.split(",").map((part) => part.trim());
1096
+ const atoms = [];
1097
+ for (const part of parts) {
1098
+ const match = REQUIREMENT_ATOM.exec(part);
1099
+ const segments = match ? parseRubyVersion(match[2]) : void 0;
1100
+ if (!match || !segments) {
1101
+ return void 0;
1102
+ }
1103
+ atoms.push({ operator: match[1] ?? "=", segments });
1104
+ }
1105
+ return atoms;
1106
+ };
1107
+ var atomAllows = ({ operator, segments }, version) => {
1108
+ const comparison = compareRubyVersions(version, segments);
1109
+ switch (operator) {
1110
+ case "=":
1111
+ return comparison === 0;
1112
+ case "!=":
1113
+ return comparison !== 0;
1114
+ case ">":
1115
+ return comparison > 0;
1116
+ case "<":
1117
+ return comparison < 0;
1118
+ case ">=":
1119
+ return comparison >= 0;
1120
+ case "<=":
1121
+ return comparison <= 0;
1122
+ case "~>":
1123
+ return comparison >= 0 && compareRubyVersions(version, pessimisticUpperBound(segments)) < 0;
1124
+ }
1125
+ };
1126
+ var rubyRequirementAllows = (requirement, version) => {
1127
+ const atoms = parseRubyRequirement(requirement);
1128
+ const segments = parseRubyVersion(version);
1129
+ if (!atoms || !segments) {
1130
+ return void 0;
1131
+ }
1132
+ return atoms.every((atom) => atomAllows(atom, segments));
1133
+ };
1134
+
1135
+ // src/detection/frameworks/ruby-runtime.ts
1136
+ var DEFAULT_RUBY_RUNTIME = "ruby-34";
1137
+ var RUBY_RUNTIME_CANDIDATES = [
1138
+ { runtime: "ruby-40", series: [4, 0], newestVersion: "4.0.9999" },
1139
+ { runtime: "ruby-34", series: [3, 4], newestVersion: "3.4.9999" },
1140
+ { runtime: "ruby-33", series: [3, 3], newestVersion: "3.3.9999" }
1141
+ ];
1142
+ var rubyRuntimeForVersion = (version) => {
1143
+ const segments = parseRubyVersion(version);
1144
+ if (!segments) {
1145
+ return void 0;
1146
+ }
1147
+ const series = [segments[0], segments[1] ?? 0];
1148
+ const candidate = RUBY_RUNTIME_CANDIDATES.find((candidate2) => compareRubyVersions(candidate2.series, series) <= 0);
1149
+ return (candidate ?? RUBY_RUNTIME_CANDIDATES[RUBY_RUNTIME_CANDIDATES.length - 1]).runtime;
1150
+ };
1151
+ var rubyRuntimeForRequirement = (requirement) => {
1152
+ const atoms = parseRubyRequirement(requirement);
1153
+ if (!atoms) {
1154
+ return void 0;
1155
+ }
1156
+ if (atoms.length === 1 && atoms[0].operator === "=") {
1157
+ return rubyRuntimeForVersion(atoms[0].segments.join("."));
1158
+ }
1159
+ return RUBY_RUNTIME_CANDIDATES.find(({ newestVersion }) => rubyRequirementAllows(requirement, newestVersion) === true)?.runtime;
1160
+ };
1161
+ var versionFromRubyVersionFile = (content) => content.split(/\r?\n/).map((line) => line.trim()).find((line) => line !== "" && !line.startsWith("#"))?.split(/\s/)[0]?.split("@")[0];
1162
+ var versionFromToolVersionsFile = (content) => /^\s*ruby\s+(\S+)/m.exec(content)?.[1];
1163
+ var versionFromGemfileLock = (content) => /^RUBY VERSION\r?\n\s+ruby\s+(\S+)/m.exec(content)?.[1];
1164
+ var GEMFILE_RUBY_DIRECTIVE = /^\s*ruby[\s(]+(.+)$/m;
1165
+ var GEMFILE_RUBY_FILE = /^(?:file:|:file\s*=>|File\.read\s*\(?)\s*(['"])([^'"]+)\1/;
1166
+ var LEADING_STRINGS = /^\s*(['"])([^'"]*)\1\s*(?:,|\)|#|$)/;
1167
+ var RUBY_VERSION_FILES = [".ruby-version", ".tool-versions", "Gemfile", "Gemfile.lock"];
1168
+ var gemfileRubyDirective = (gemfile) => GEMFILE_RUBY_DIRECTIVE.exec(gemfile)?.[1]?.trim();
1169
+ var gemfileRubyVersionFile = (gemfile) => {
1170
+ const directive = gemfileRubyDirective(gemfile);
1171
+ return directive === void 0 ? void 0 : GEMFILE_RUBY_FILE.exec(directive)?.[2];
1172
+ };
1173
+ var runtimeFromVersionFile = (file, content) => {
1174
+ if (content === void 0) {
1175
+ return void 0;
1176
+ }
1177
+ const parse = file.split("/").at(-1) === ".tool-versions" ? versionFromToolVersionsFile : versionFromRubyVersionFile;
1178
+ const version = parse(content);
1179
+ return version === void 0 ? void 0 : rubyRuntimeForVersion(version);
1180
+ };
1181
+ var runtimeFromGemfile = (gemfile, readFile) => {
1182
+ const directive = gemfile === void 0 ? void 0 : gemfileRubyDirective(gemfile);
1183
+ if (directive === void 0) {
1184
+ return void 0;
1185
+ }
1186
+ const versionFile = GEMFILE_RUBY_FILE.exec(directive)?.[2];
1187
+ if (versionFile !== void 0) {
1188
+ return runtimeFromVersionFile(versionFile, readFile(versionFile));
1189
+ }
1190
+ const requirements = [];
1191
+ let rest = directive;
1192
+ for (let match = LEADING_STRINGS.exec(rest); match; match = LEADING_STRINGS.exec(rest)) {
1193
+ requirements.push(match[2]);
1194
+ rest = rest.slice(match[0].length);
1195
+ }
1196
+ return requirements.length === 0 ? void 0 : rubyRuntimeForRequirement(requirements.join(","));
1197
+ };
1198
+ var runtimeFromGemfileLock = (lockfile) => {
1199
+ const version = lockfile === void 0 ? void 0 : versionFromGemfileLock(lockfile);
1200
+ return version === void 0 ? void 0 : rubyRuntimeForVersion(version);
1201
+ };
1202
+ var rubyRuntimeFromProjectFiles = (readFile) => runtimeFromVersionFile(".ruby-version", readFile(".ruby-version")) ?? runtimeFromVersionFile(".tool-versions", readFile(".tool-versions")) ?? runtimeFromGemfile(readFile("Gemfile"), readFile) ?? runtimeFromGemfileLock(readFile("Gemfile.lock"));
1203
+ var readProjectFile = import_effect8.Effect.fn("readProjectFile")(
1204
+ function* (projectFolder, file) {
1205
+ const fs = yield* import_platform5.FileSystem.FileSystem;
1206
+ const pathService = yield* import_platform5.Path.Path;
1207
+ return yield* fs.readFileString(pathService.join(projectFolder, file));
1208
+ },
1209
+ import_effect8.Effect.catchAll(() => import_effect8.Effect.succeed(void 0))
1210
+ );
1211
+ var detectRubyRuntime = import_effect8.Effect.fn("detectRubyRuntime")(function* (projectFolder) {
1212
+ const files = /* @__PURE__ */ new Map();
1213
+ for (const file of RUBY_VERSION_FILES) {
1214
+ files.set(file, yield* readProjectFile(projectFolder, file));
1215
+ }
1216
+ const gemfile = files.get("Gemfile");
1217
+ const versionFile = gemfile === void 0 ? void 0 : gemfileRubyVersionFile(gemfile);
1218
+ if (versionFile !== void 0 && !files.has(versionFile)) {
1219
+ files.set(versionFile, yield* readProjectFile(projectFolder, versionFile));
1220
+ }
1221
+ return rubyRuntimeFromProjectFiles((file) => files.get(file));
1222
+ });
1223
+ var refineRubyRuntime = import_effect8.Effect.fn("refineRubyRuntime")(function* (defaults, projectFolder) {
1224
+ const runtime = yield* detectRubyRuntime(projectFolder);
1225
+ return runtime ? { ...defaults, runtime } : defaults;
1226
+ });
1227
+ var withRubyRuntime = (framework) => ({
1228
+ ...framework,
1229
+ refineDefaultConfig: (defaults, projectFolder) => import_effect8.Effect.gen(function* () {
1230
+ const refined = framework.refineDefaultConfig ? yield* framework.refineDefaultConfig(defaults, projectFolder) : defaults;
1231
+ return yield* refineRubyRuntime(refined, projectFolder);
1232
+ })
1233
+ });
1234
+
1235
+ // src/detection/frameworks/bridgetown.ts
1236
+ var bridgetown = {
1237
+ slug: "bridgetown",
1238
+ name: "Bridgetown",
1239
+ language: "ruby",
1240
+ detectors: [{ matchPackage: "bridgetown" }],
1241
+ priority: 70,
1242
+ getDefaultConfig: () => ({
1243
+ runtime: DEFAULT_RUBY_RUNTIME,
1244
+ memory: 128,
1245
+ maxDuration: 30,
1246
+ streaming: false,
1247
+ commands: ["bin/bridgetown deploy"],
1248
+ assetsDir: "output",
1249
+ populateAssetCache: true,
1250
+ routes: [],
1251
+ environmentVariables: { BRIDGETOWN_ENV: "production" }
1252
+ })
1253
+ };
1254
+
1061
1255
  // src/detection/generated-secret.ts
1062
1256
  var generatedSecret = (format) => `{{gigadrive.secret:${format}}}`;
1063
1257
 
@@ -1132,8 +1326,8 @@ var codeigniter = {
1132
1326
  };
1133
1327
 
1134
1328
  // src/detection/frameworks/resolve-node-entrypoint.ts
1135
- var import_platform5 = require("@effect/platform");
1136
- var import_effect8 = require("effect");
1329
+ var import_platform6 = require("@effect/platform");
1330
+ var import_effect9 = require("effect");
1137
1331
  var SCRIPT_RUNNERS = /* @__PURE__ */ new Set(["node", "bun", "tsx", "ts-node"]);
1138
1332
  var COMMON_ENTRYPOINT_CANDIDATES = [
1139
1333
  "index.js",
@@ -1181,14 +1375,14 @@ var applyEntrypoint = (defaults, entrypoint) => ({
1181
1375
  (route) => route.destination === defaults.entrypoint ? { ...route, destination: entrypoint } : route
1182
1376
  )
1183
1377
  });
1184
- var resolveNodeServerEntrypoint = (defaults, projectFolder) => import_effect8.Effect.gen(function* () {
1185
- const fs = yield* import_platform5.FileSystem.FileSystem;
1186
- const pathService = yield* import_platform5.Path.Path;
1378
+ var resolveNodeServerEntrypoint = (defaults, projectFolder) => import_effect9.Effect.gen(function* () {
1379
+ const fs = yield* import_platform6.FileSystem.FileSystem;
1380
+ const pathService = yield* import_platform6.Path.Path;
1187
1381
  const isFile = (relativePath) => fs.stat(pathService.join(projectFolder, relativePath)).pipe(
1188
- import_effect8.Effect.map((info) => info.type === "File"),
1189
- import_effect8.Effect.catchAll(() => import_effect8.Effect.succeed(false))
1382
+ import_effect9.Effect.map((info) => info.type === "File"),
1383
+ import_effect9.Effect.catchAll(() => import_effect9.Effect.succeed(false))
1190
1384
  );
1191
- const content = yield* fs.readFileString(pathService.join(projectFolder, "package.json")).pipe(import_effect8.Effect.catchAll(() => import_effect8.Effect.succeed(void 0)));
1385
+ const content = yield* fs.readFileString(pathService.join(projectFolder, "package.json")).pipe(import_effect9.Effect.catchAll(() => import_effect9.Effect.succeed(void 0)));
1192
1386
  const manifest = content ? parsePackageJson(content) : void 0;
1193
1387
  const startScript = typeof manifest?.scripts?.start === "string" ? manifest.scripts.start : void 0;
1194
1388
  const candidates = [
@@ -1268,6 +1462,189 @@ var fastify = {
1268
1462
  refineDefaultConfig: resolveNodeServerEntrypoint
1269
1463
  };
1270
1464
 
1465
+ // src/detection/frameworks/hanami.ts
1466
+ var import_effect13 = require("effect");
1467
+
1468
+ // src/detection/read-dependencies.ts
1469
+ var import_platform7 = require("@effect/platform");
1470
+ var import_effect11 = require("effect");
1471
+
1472
+ // src/detection/types.ts
1473
+ var import_effect10 = require("effect");
1474
+ var ManifestNotFoundError = class extends import_effect10.Schema.TaggedError()("ManifestNotFoundError", {
1475
+ message: import_effect10.Schema.String,
1476
+ filePath: import_effect10.Schema.String
1477
+ }) {
1478
+ };
1479
+ var ManifestReadError = class extends import_effect10.Schema.TaggedError()("ManifestReadError", {
1480
+ message: import_effect10.Schema.String,
1481
+ filePath: import_effect10.Schema.String
1482
+ }) {
1483
+ };
1484
+ var ManifestParseError = class extends import_effect10.Schema.TaggedError()("ManifestParseError", {
1485
+ message: import_effect10.Schema.String,
1486
+ filePath: import_effect10.Schema.String
1487
+ }) {
1488
+ };
1489
+ var FrameworkNotDetectedError = class extends import_effect10.Schema.TaggedError()(
1490
+ "FrameworkNotDetectedError",
1491
+ {
1492
+ message: import_effect10.Schema.String,
1493
+ directory: import_effect10.Schema.String
1494
+ }
1495
+ ) {
1496
+ };
1497
+
1498
+ // src/detection/read-dependencies.ts
1499
+ var MANIFEST_CONFIG = {
1500
+ node: { file: "package.json", depKeys: ["dependencies", "devDependencies"] },
1501
+ php: { file: "composer.json", depKeys: ["require", "require-dev"] }
1502
+ };
1503
+ var GEMFILE_LOCK_SOURCE_SECTIONS = /* @__PURE__ */ new Set(["GEM", "GIT", "PATH"]);
1504
+ var GEMFILE_LOCK_SPEC = /^ {4}([A-Za-z0-9_.-]+) \(/;
1505
+ var GEMFILE_GEM = /^\s*gem[\s(]+['"]([^'"]+)['"]/;
1506
+ var parseGemfileLock = (content) => {
1507
+ const gems = /* @__PURE__ */ new Set();
1508
+ let inSourceSection = false;
1509
+ for (const line of content.split(/\r?\n/)) {
1510
+ if (/^\S/.test(line)) {
1511
+ inSourceSection = GEMFILE_LOCK_SOURCE_SECTIONS.has(line.trim());
1512
+ continue;
1513
+ }
1514
+ const match = inSourceSection ? GEMFILE_LOCK_SPEC.exec(line) : null;
1515
+ if (match) {
1516
+ gems.add(match[1]);
1517
+ }
1518
+ }
1519
+ return gems;
1520
+ };
1521
+ var parseGemfile = (content) => {
1522
+ const gems = /* @__PURE__ */ new Set();
1523
+ for (const line of content.split(/\r?\n/)) {
1524
+ const match = GEMFILE_GEM.exec(line);
1525
+ if (match) {
1526
+ gems.add(match[1]);
1527
+ }
1528
+ }
1529
+ return gems;
1530
+ };
1531
+ var readOptionalText = import_effect11.Effect.fn("readOptionalText")(function* (filePath) {
1532
+ const fs = yield* import_platform7.FileSystem.FileSystem;
1533
+ const exists = yield* fs.exists(filePath).pipe(import_effect11.Effect.catchAll(() => import_effect11.Effect.succeed(false)));
1534
+ if (!exists) {
1535
+ return void 0;
1536
+ }
1537
+ return yield* fs.readFileString(filePath).pipe(import_effect11.Effect.mapError(() => new ManifestReadError({ message: "Failed to read manifest", filePath })));
1538
+ });
1539
+ var readGemNames = import_effect11.Effect.fn("readGemNames")(function* (projectFolder) {
1540
+ const pathService = yield* import_platform7.Path.Path;
1541
+ const lockfile = yield* readOptionalText(pathService.join(projectFolder, "Gemfile.lock"));
1542
+ if (lockfile !== void 0) {
1543
+ return parseGemfileLock(lockfile);
1544
+ }
1545
+ const gemfile = yield* readOptionalText(pathService.join(projectFolder, "Gemfile"));
1546
+ return gemfile === void 0 ? /* @__PURE__ */ new Set() : parseGemfile(gemfile);
1547
+ });
1548
+ var readManifest = import_effect11.Effect.fn("readManifest")(function* (filePath) {
1549
+ const fs = yield* import_platform7.FileSystem.FileSystem;
1550
+ const exists = yield* fs.exists(filePath).pipe(import_effect11.Effect.catchAll(() => import_effect11.Effect.succeed(false)));
1551
+ if (!exists) {
1552
+ return yield* import_effect11.Effect.fail(new ManifestNotFoundError({ message: "Manifest not found", filePath }));
1553
+ }
1554
+ const content = yield* fs.readFileString(filePath).pipe(import_effect11.Effect.mapError(() => new ManifestReadError({ message: "Failed to read manifest", filePath })));
1555
+ const parsed = yield* import_effect11.Effect.try({
1556
+ try: () => JSON.parse(content),
1557
+ catch: () => new ManifestParseError({ message: "Failed to parse manifest JSON", filePath })
1558
+ });
1559
+ return parsed;
1560
+ });
1561
+ var readDependencies = import_effect11.Effect.fn("readDependencies")(function* (projectFolder, language) {
1562
+ if (language === "ruby") {
1563
+ return yield* readGemNames(projectFolder);
1564
+ }
1565
+ const pathService = yield* import_platform7.Path.Path;
1566
+ const config = MANIFEST_CONFIG[language];
1567
+ const filePath = pathService.join(projectFolder, config.file);
1568
+ const manifest = yield* readManifest(filePath).pipe(
1569
+ import_effect11.Effect.catchTag("ManifestNotFoundError", () => import_effect11.Effect.succeed(null))
1570
+ );
1571
+ if (!manifest) {
1572
+ return /* @__PURE__ */ new Set();
1573
+ }
1574
+ const deps = /* @__PURE__ */ new Set();
1575
+ for (const key of config.depKeys) {
1576
+ const section = manifest[key];
1577
+ if (section && typeof section === "object" && !Array.isArray(section)) {
1578
+ for (const name of Object.keys(section)) {
1579
+ deps.add(name);
1580
+ }
1581
+ }
1582
+ }
1583
+ return deps;
1584
+ });
1585
+
1586
+ // src/detection/frameworks/ruby-server.ts
1587
+ var import_platform8 = require("@effect/platform");
1588
+ var import_effect12 = require("effect");
1589
+ var rubyServerDefaults = ({
1590
+ entrypoint = "config.ru",
1591
+ memory = 256,
1592
+ commands = [],
1593
+ environmentVariables,
1594
+ excludeFiles,
1595
+ writablePaths = []
1596
+ }) => ({
1597
+ runtime: DEFAULT_RUBY_RUNTIME,
1598
+ memory,
1599
+ maxDuration: 30,
1600
+ streaming: true,
1601
+ commands,
1602
+ entrypoint,
1603
+ assetsDir: "public",
1604
+ populateAssetCache: true,
1605
+ routes: [{ source: "/*", destination: entrypoint }],
1606
+ environmentVariables,
1607
+ ...excludeFiles ? { excludeFiles } : {},
1608
+ ...writablePaths.length > 0 ? { package: { writablePaths } } : {}
1609
+ });
1610
+ var refineRubyPublicDirectory = import_effect12.Effect.fn("refineRubyPublicDirectory")(function* (defaults, projectFolder) {
1611
+ if (!defaults.assetsDir) {
1612
+ return defaults;
1613
+ }
1614
+ const fs = yield* import_platform8.FileSystem.FileSystem;
1615
+ const pathService = yield* import_platform8.Path.Path;
1616
+ const exists = yield* fs.exists(pathService.join(projectFolder, defaults.assetsDir)).pipe(import_effect12.Effect.catchAll(() => import_effect12.Effect.succeed(false)));
1617
+ if (exists) {
1618
+ return defaults;
1619
+ }
1620
+ const withoutAssets = { ...defaults };
1621
+ delete withoutAssets.assetsDir;
1622
+ delete withoutAssets.populateAssetCache;
1623
+ return withoutAssets;
1624
+ });
1625
+
1626
+ // src/detection/frameworks/hanami.ts
1627
+ var refineHanamiAssets = import_effect13.Effect.fn("refineHanamiAssets")(function* (defaults, projectFolder) {
1628
+ const gems = yield* readDependencies(projectFolder, "ruby").pipe(
1629
+ import_effect13.Effect.catchAll(() => import_effect13.Effect.succeed(/* @__PURE__ */ new Set()))
1630
+ );
1631
+ const withPublicDirectory = yield* refineRubyPublicDirectory(defaults, projectFolder);
1632
+ return gems.has("hanami-assets") ? { ...withPublicDirectory, commands: [...withPublicDirectory.commands, "bundle exec hanami assets compile"] } : withPublicDirectory;
1633
+ });
1634
+ var hanami = {
1635
+ slug: "hanami",
1636
+ name: "Hanami",
1637
+ language: "ruby",
1638
+ detectors: [{ matchPackage: "hanami" }, { path: "config.ru" }],
1639
+ priority: 75,
1640
+ getDefaultConfig: () => rubyServerDefaults({
1641
+ excludeFiles: ["tmp/", "log/", "spec/", "node_modules/", ".git/"],
1642
+ writablePaths: ["tmp", "log"],
1643
+ environmentVariables: { HANAMI_ENV: "production", RACK_ENV: "production" }
1644
+ }),
1645
+ refineDefaultConfig: refineHanamiAssets
1646
+ };
1647
+
1271
1648
  // src/detection/frameworks/hono.ts
1272
1649
  var hono = {
1273
1650
  slug: "hono",
@@ -1288,6 +1665,30 @@ var hono = {
1288
1665
  refineDefaultConfig: resolveNodeServerEntrypoint
1289
1666
  };
1290
1667
 
1668
+ // src/detection/frameworks/jekyll.ts
1669
+ var jekyll = {
1670
+ slug: "jekyll",
1671
+ name: "Jekyll",
1672
+ language: "ruby",
1673
+ detectors: [{ matchPackage: "jekyll" }],
1674
+ priority: 70,
1675
+ getDefaultConfig: () => ({
1676
+ runtime: DEFAULT_RUBY_RUNTIME,
1677
+ memory: 128,
1678
+ maxDuration: 30,
1679
+ streaming: false,
1680
+ commands: ["bundle exec jekyll build"],
1681
+ assetsDir: "_site",
1682
+ populateAssetCache: true,
1683
+ routes: [],
1684
+ environmentVariables: { JEKYLL_ENV: "production" }
1685
+ })
1686
+ };
1687
+ var jekyllPresets = [
1688
+ jekyll,
1689
+ { ...jekyll, detectors: [{ matchPackage: "github-pages" }] }
1690
+ ];
1691
+
1291
1692
  // src/detection/frameworks/laminas.ts
1292
1693
  var laminas = {
1293
1694
  slug: "laminas",
@@ -1367,8 +1768,8 @@ var mezzio = {
1367
1768
  };
1368
1769
 
1369
1770
  // src/detection/frameworks/nestjs.ts
1370
- var import_platform6 = require("@effect/platform");
1371
- var import_effect9 = require("effect");
1771
+ var import_platform9 = require("@effect/platform");
1772
+ var import_effect14 = require("effect");
1372
1773
  var isRecord3 = (value) => typeof value === "object" && value !== null;
1373
1774
  var parseNestCliJson = (content) => {
1374
1775
  try {
@@ -1419,9 +1820,9 @@ var nestjs = {
1419
1820
  detectors: [{ matchPackage: "@nestjs/core" }],
1420
1821
  priority: 90,
1421
1822
  getDefaultConfig: () => createNestConfig("dist"),
1422
- refineDefaultConfig: (defaults, projectFolder) => import_effect9.Effect.gen(function* () {
1423
- const fs = yield* import_platform6.FileSystem.FileSystem;
1424
- const content = yield* fs.readFileString(`${projectFolder}/nest-cli.json`).pipe(import_effect9.Effect.catchAll(() => import_effect9.Effect.succeed(void 0)));
1823
+ refineDefaultConfig: (defaults, projectFolder) => import_effect14.Effect.gen(function* () {
1824
+ const fs = yield* import_platform9.FileSystem.FileSystem;
1825
+ const content = yield* fs.readFileString(`${projectFolder}/nest-cli.json`).pipe(import_effect14.Effect.catchAll(() => import_effect14.Effect.succeed(void 0)));
1425
1826
  if (!content) return defaults;
1426
1827
  const nestConfig = parseNestCliJson(content);
1427
1828
  const outputPath = nestConfig ? getProjectOutputPath(nestConfig) : void 0;
@@ -1430,28 +1831,28 @@ var nestjs = {
1430
1831
  };
1431
1832
 
1432
1833
  // src/detection/frameworks/nextjs.ts
1433
- var import_platform8 = require("@effect/platform");
1434
- var import_effect12 = require("effect");
1834
+ var import_platform11 = require("@effect/platform");
1835
+ var import_effect17 = require("effect");
1435
1836
 
1436
1837
  // src/build-output-v3/get-default-path-map.ts
1437
- var import_platform7 = require("@effect/platform");
1438
- var import_effect10 = require("effect");
1439
- var getDefaultPathMap = import_effect10.Effect.fn("getDefaultPathMap")(function* (directory) {
1440
- const fs = yield* import_platform7.FileSystem.FileSystem;
1441
- const pathService = yield* import_platform7.Path.Path;
1838
+ var import_platform10 = require("@effect/platform");
1839
+ var import_effect15 = require("effect");
1840
+ var getDefaultPathMap = import_effect15.Effect.fn("getDefaultPathMap")(function* (directory) {
1841
+ const fs = yield* import_platform10.FileSystem.FileSystem;
1842
+ const pathService = yield* import_platform10.Path.Path;
1442
1843
  const result = {};
1443
- const exists = yield* fs.exists(directory).pipe(import_effect10.Effect.catchAll(() => import_effect10.Effect.succeed(false)));
1844
+ const exists = yield* fs.exists(directory).pipe(import_effect15.Effect.catchAll(() => import_effect15.Effect.succeed(false)));
1444
1845
  if (!exists) {
1445
1846
  return result;
1446
1847
  }
1447
1848
  const MAX_DEPTH = 100;
1448
- const processDirectory = (currentPath, basePath = "", depth = 0) => import_effect10.Effect.gen(function* () {
1849
+ const processDirectory = (currentPath, basePath = "", depth = 0) => import_effect15.Effect.gen(function* () {
1449
1850
  if (depth > MAX_DEPTH) return;
1450
- const entries = yield* fs.readDirectory(currentPath).pipe(import_effect10.Effect.catchAll(() => import_effect10.Effect.succeed([])));
1851
+ const entries = yield* fs.readDirectory(currentPath).pipe(import_effect15.Effect.catchAll(() => import_effect15.Effect.succeed([])));
1451
1852
  for (const name of entries) {
1452
1853
  const fullPath = pathService.join(currentPath, name);
1453
1854
  const relativePath = basePath ? pathService.join(basePath, name) : name;
1454
- const stat = yield* fs.stat(fullPath).pipe(import_effect10.Effect.catchAll(() => import_effect10.Effect.succeed(null)));
1855
+ const stat = yield* fs.stat(fullPath).pipe(import_effect15.Effect.catchAll(() => import_effect15.Effect.succeed(null)));
1455
1856
  if (!stat) continue;
1456
1857
  if (stat.type === "Directory") {
1457
1858
  yield* processDirectory(fullPath, relativePath, depth + 1);
@@ -1468,244 +1869,244 @@ var getDefaultPathMap = import_effect10.Effect.fn("getDefaultPathMap")(function*
1468
1869
  var MAXIMUM_ENTRY_PAGE_PATHS = 50;
1469
1870
 
1470
1871
  // src/nextjs-manifest.ts
1471
- var import_effect11 = require("effect");
1472
- var StringArraySchema = import_effect11.Schema.mutable(import_effect11.Schema.Array(import_effect11.Schema.String));
1473
- var StringRecordSchema = import_effect11.Schema.mutable(import_effect11.Schema.Record({ key: import_effect11.Schema.String, value: import_effect11.Schema.String }));
1474
- var JsonValueSchema = import_effect11.Schema.suspend(
1475
- () => import_effect11.Schema.Union(
1476
- import_effect11.Schema.Null,
1477
- import_effect11.Schema.Boolean,
1478
- import_effect11.Schema.Number,
1479
- import_effect11.Schema.String,
1480
- import_effect11.Schema.mutable(import_effect11.Schema.Array(JsonValueSchema)),
1481
- import_effect11.Schema.mutable(import_effect11.Schema.Record({ key: import_effect11.Schema.String, value: JsonValueSchema }))
1872
+ var import_effect16 = require("effect");
1873
+ var StringArraySchema = import_effect16.Schema.mutable(import_effect16.Schema.Array(import_effect16.Schema.String));
1874
+ var StringRecordSchema = import_effect16.Schema.mutable(import_effect16.Schema.Record({ key: import_effect16.Schema.String, value: import_effect16.Schema.String }));
1875
+ var JsonValueSchema = import_effect16.Schema.suspend(
1876
+ () => import_effect16.Schema.Union(
1877
+ import_effect16.Schema.Null,
1878
+ import_effect16.Schema.Boolean,
1879
+ import_effect16.Schema.Number,
1880
+ import_effect16.Schema.String,
1881
+ import_effect16.Schema.mutable(import_effect16.Schema.Array(JsonValueSchema)),
1882
+ import_effect16.Schema.mutable(import_effect16.Schema.Record({ key: import_effect16.Schema.String, value: JsonValueSchema }))
1482
1883
  )
1483
1884
  );
1484
- var ImageLocalPatternSchema = import_effect11.Schema.mutable(
1485
- import_effect11.Schema.Struct({
1486
- pathname: import_effect11.Schema.optional(import_effect11.Schema.String),
1487
- search: import_effect11.Schema.optional(import_effect11.Schema.String)
1885
+ var ImageLocalPatternSchema = import_effect16.Schema.mutable(
1886
+ import_effect16.Schema.Struct({
1887
+ pathname: import_effect16.Schema.optional(import_effect16.Schema.String),
1888
+ search: import_effect16.Schema.optional(import_effect16.Schema.String)
1488
1889
  })
1489
1890
  );
1490
- var ImageRemotePatternSchema = import_effect11.Schema.mutable(
1491
- import_effect11.Schema.Struct({
1492
- protocol: import_effect11.Schema.optional(import_effect11.Schema.Literal("http", "https")),
1493
- hostname: import_effect11.Schema.String,
1494
- port: import_effect11.Schema.optional(import_effect11.Schema.String),
1495
- pathname: import_effect11.Schema.optional(import_effect11.Schema.String),
1496
- search: import_effect11.Schema.optional(import_effect11.Schema.String)
1891
+ var ImageRemotePatternSchema = import_effect16.Schema.mutable(
1892
+ import_effect16.Schema.Struct({
1893
+ protocol: import_effect16.Schema.optional(import_effect16.Schema.Literal("http", "https")),
1894
+ hostname: import_effect16.Schema.String,
1895
+ port: import_effect16.Schema.optional(import_effect16.Schema.String),
1896
+ pathname: import_effect16.Schema.optional(import_effect16.Schema.String),
1897
+ search: import_effect16.Schema.optional(import_effect16.Schema.String)
1497
1898
  })
1498
1899
  );
1499
- var ImageVariantSchema = import_effect11.Schema.mutable(
1500
- import_effect11.Schema.Struct({
1501
- width: import_effect11.Schema.optional(import_effect11.Schema.Number),
1502
- height: import_effect11.Schema.optional(import_effect11.Schema.Number),
1503
- quality: import_effect11.Schema.optional(import_effect11.Schema.Number),
1504
- format: import_effect11.Schema.optional(import_effect11.Schema.Literal("image/avif", "image/webp", "image/jpeg", "image/png")),
1505
- fit: import_effect11.Schema.optional(import_effect11.Schema.Literal("contain", "cover", "fill", "inside", "outside"))
1900
+ var ImageVariantSchema = import_effect16.Schema.mutable(
1901
+ import_effect16.Schema.Struct({
1902
+ width: import_effect16.Schema.optional(import_effect16.Schema.Number),
1903
+ height: import_effect16.Schema.optional(import_effect16.Schema.Number),
1904
+ quality: import_effect16.Schema.optional(import_effect16.Schema.Number),
1905
+ format: import_effect16.Schema.optional(import_effect16.Schema.Literal("image/avif", "image/webp", "image/jpeg", "image/png")),
1906
+ fit: import_effect16.Schema.optional(import_effect16.Schema.Literal("contain", "cover", "fill", "inside", "outside"))
1506
1907
  })
1507
1908
  );
1508
- var PositiveIntSchema = import_effect11.Schema.Int.pipe(import_effect11.Schema.greaterThan(0));
1509
- var ImagePolicySchema = import_effect11.Schema.mutable(
1510
- import_effect11.Schema.Struct({
1511
- localPatterns: import_effect11.Schema.mutable(import_effect11.Schema.Array(ImageLocalPatternSchema)),
1512
- remotePatterns: import_effect11.Schema.mutable(import_effect11.Schema.Array(ImageRemotePatternSchema)),
1513
- widths: import_effect11.Schema.mutable(import_effect11.Schema.Array(PositiveIntSchema)),
1514
- heights: import_effect11.Schema.mutable(import_effect11.Schema.Array(PositiveIntSchema)),
1515
- qualities: import_effect11.Schema.mutable(import_effect11.Schema.Array(import_effect11.Schema.Number.pipe(import_effect11.Schema.between(1, 100)))),
1516
- formats: import_effect11.Schema.mutable(import_effect11.Schema.Array(import_effect11.Schema.Literal("image/avif", "image/webp", "image/jpeg", "image/png"))),
1517
- minimumCacheTTL: import_effect11.Schema.Number,
1518
- dangerouslyAllowSVG: import_effect11.Schema.Boolean,
1519
- contentSecurityPolicy: import_effect11.Schema.String,
1520
- contentDispositionType: import_effect11.Schema.Literal("inline", "attachment"),
1521
- maximumRedirects: import_effect11.Schema.Number,
1522
- maximumResponseBody: import_effect11.Schema.Number,
1523
- variants: import_effect11.Schema.mutable(import_effect11.Schema.Record({ key: import_effect11.Schema.String, value: ImageVariantSchema }))
1909
+ var PositiveIntSchema = import_effect16.Schema.Int.pipe(import_effect16.Schema.greaterThan(0));
1910
+ var ImagePolicySchema = import_effect16.Schema.mutable(
1911
+ import_effect16.Schema.Struct({
1912
+ localPatterns: import_effect16.Schema.mutable(import_effect16.Schema.Array(ImageLocalPatternSchema)),
1913
+ remotePatterns: import_effect16.Schema.mutable(import_effect16.Schema.Array(ImageRemotePatternSchema)),
1914
+ widths: import_effect16.Schema.mutable(import_effect16.Schema.Array(PositiveIntSchema)),
1915
+ heights: import_effect16.Schema.mutable(import_effect16.Schema.Array(PositiveIntSchema)),
1916
+ qualities: import_effect16.Schema.mutable(import_effect16.Schema.Array(import_effect16.Schema.Number.pipe(import_effect16.Schema.between(1, 100)))),
1917
+ formats: import_effect16.Schema.mutable(import_effect16.Schema.Array(import_effect16.Schema.Literal("image/avif", "image/webp", "image/jpeg", "image/png"))),
1918
+ minimumCacheTTL: import_effect16.Schema.Number,
1919
+ dangerouslyAllowSVG: import_effect16.Schema.Boolean,
1920
+ contentSecurityPolicy: import_effect16.Schema.String,
1921
+ contentDispositionType: import_effect16.Schema.Literal("inline", "attachment"),
1922
+ maximumRedirects: import_effect16.Schema.Number,
1923
+ maximumResponseBody: import_effect16.Schema.Number,
1924
+ variants: import_effect16.Schema.mutable(import_effect16.Schema.Record({ key: import_effect16.Schema.String, value: ImageVariantSchema }))
1524
1925
  })
1525
1926
  );
1526
1927
  var GigadriveNextPrerenderOutputFields = {
1527
- id: import_effect11.Schema.String,
1528
- type: import_effect11.Schema.Literal("PRERENDER"),
1928
+ id: import_effect16.Schema.String,
1929
+ type: import_effect16.Schema.Literal("PRERENDER"),
1529
1930
  pathname: UrlPathnameSchema,
1530
- route: import_effect11.Schema.optional(UrlPathnameSchema),
1531
- parentOutputId: import_effect11.Schema.String,
1532
- groupId: import_effect11.Schema.Number,
1533
- pprChain: import_effect11.Schema.optional(import_effect11.Schema.mutable(import_effect11.Schema.Struct({ headers: HttpSingleValueHeadersSchema }))),
1534
- parentFallbackMode: import_effect11.Schema.optional(JsonValueSchema),
1535
- fallback: import_effect11.Schema.optional(
1536
- import_effect11.Schema.mutable(
1537
- import_effect11.Schema.Struct({
1538
- filePath: import_effect11.Schema.optional(PortableRelativePathSchema),
1539
- initialStatus: import_effect11.Schema.optional(import_effect11.Schema.Int.pipe(import_effect11.Schema.between(100, 599))),
1540
- initialHeaders: import_effect11.Schema.optional(HttpHeadersSchema),
1541
- initialExpiration: import_effect11.Schema.optional(import_effect11.Schema.Number),
1542
- initialRevalidate: import_effect11.Schema.optional(import_effect11.Schema.Union(import_effect11.Schema.Number, import_effect11.Schema.Literal(false))),
1543
- postponedState: import_effect11.Schema.optional(import_effect11.Schema.String)
1931
+ route: import_effect16.Schema.optional(UrlPathnameSchema),
1932
+ parentOutputId: import_effect16.Schema.String,
1933
+ groupId: import_effect16.Schema.Number,
1934
+ pprChain: import_effect16.Schema.optional(import_effect16.Schema.mutable(import_effect16.Schema.Struct({ headers: HttpSingleValueHeadersSchema }))),
1935
+ parentFallbackMode: import_effect16.Schema.optional(JsonValueSchema),
1936
+ fallback: import_effect16.Schema.optional(
1937
+ import_effect16.Schema.mutable(
1938
+ import_effect16.Schema.Struct({
1939
+ filePath: import_effect16.Schema.optional(PortableRelativePathSchema),
1940
+ initialStatus: import_effect16.Schema.optional(import_effect16.Schema.Int.pipe(import_effect16.Schema.between(100, 599))),
1941
+ initialHeaders: import_effect16.Schema.optional(HttpHeadersSchema),
1942
+ initialExpiration: import_effect16.Schema.optional(import_effect16.Schema.Number),
1943
+ initialRevalidate: import_effect16.Schema.optional(import_effect16.Schema.Union(import_effect16.Schema.Number, import_effect16.Schema.Literal(false))),
1944
+ postponedState: import_effect16.Schema.optional(import_effect16.Schema.String)
1544
1945
  })
1545
1946
  )
1546
1947
  ),
1547
- config: import_effect11.Schema.mutable(
1548
- import_effect11.Schema.Struct({
1549
- allowQuery: import_effect11.Schema.optional(StringArraySchema),
1550
- allowHeader: import_effect11.Schema.optional(StringArraySchema),
1551
- bypassFor: import_effect11.Schema.optional(import_effect11.Schema.mutable(import_effect11.Schema.Array(JsonValueSchema))),
1552
- renderingMode: import_effect11.Schema.optional(import_effect11.Schema.String),
1553
- partialFallback: import_effect11.Schema.optional(import_effect11.Schema.Boolean),
1554
- bypassToken: import_effect11.Schema.optional(import_effect11.Schema.String)
1948
+ config: import_effect16.Schema.mutable(
1949
+ import_effect16.Schema.Struct({
1950
+ allowQuery: import_effect16.Schema.optional(StringArraySchema),
1951
+ allowHeader: import_effect16.Schema.optional(StringArraySchema),
1952
+ bypassFor: import_effect16.Schema.optional(import_effect16.Schema.mutable(import_effect16.Schema.Array(JsonValueSchema))),
1953
+ renderingMode: import_effect16.Schema.optional(import_effect16.Schema.String),
1954
+ partialFallback: import_effect16.Schema.optional(import_effect16.Schema.Boolean),
1955
+ bypassToken: import_effect16.Schema.optional(import_effect16.Schema.String)
1555
1956
  })
1556
1957
  )
1557
1958
  };
1558
- var GigadriveNextPrerenderClassificationSchema = import_effect11.Schema.Struct({
1559
- routeType: import_effect11.Schema.Literal("route", "fallback", "shell", "page"),
1560
- response: import_effect11.Schema.Literal("empty", "initial", "complete"),
1561
- compute: import_effect11.Schema.Literal("blocking", "resuming", "static"),
1562
- htmlSize: import_effect11.Schema.optional(import_effect11.Schema.Number)
1959
+ var GigadriveNextPrerenderClassificationSchema = import_effect16.Schema.Struct({
1960
+ routeType: import_effect16.Schema.Literal("route", "fallback", "shell", "page"),
1961
+ response: import_effect16.Schema.Literal("empty", "initial", "complete"),
1962
+ compute: import_effect16.Schema.Literal("blocking", "resuming", "static"),
1963
+ htmlSize: import_effect16.Schema.optional(import_effect16.Schema.Number)
1563
1964
  });
1564
- var GigadriveNextPrerenderWithoutClassificationSchema = import_effect11.Schema.Struct({
1565
- routeType: import_effect11.Schema.optional(import_effect11.Schema.Never),
1566
- response: import_effect11.Schema.optional(import_effect11.Schema.Never),
1567
- compute: import_effect11.Schema.optional(import_effect11.Schema.Never),
1568
- htmlSize: import_effect11.Schema.optional(import_effect11.Schema.Never)
1965
+ var GigadriveNextPrerenderWithoutClassificationSchema = import_effect16.Schema.Struct({
1966
+ routeType: import_effect16.Schema.optional(import_effect16.Schema.Never),
1967
+ response: import_effect16.Schema.optional(import_effect16.Schema.Never),
1968
+ compute: import_effect16.Schema.optional(import_effect16.Schema.Never),
1969
+ htmlSize: import_effect16.Schema.optional(import_effect16.Schema.Never)
1569
1970
  });
1570
- var GigadriveNextPrerenderOutputSchema = import_effect11.Schema.Union(
1571
- import_effect11.Schema.mutable(
1572
- import_effect11.Schema.Struct({ ...GigadriveNextPrerenderOutputFields, ...GigadriveNextPrerenderClassificationSchema.fields })
1971
+ var GigadriveNextPrerenderOutputSchema = import_effect16.Schema.Union(
1972
+ import_effect16.Schema.mutable(
1973
+ import_effect16.Schema.Struct({ ...GigadriveNextPrerenderOutputFields, ...GigadriveNextPrerenderClassificationSchema.fields })
1573
1974
  ),
1574
- import_effect11.Schema.mutable(
1575
- import_effect11.Schema.Struct({
1975
+ import_effect16.Schema.mutable(
1976
+ import_effect16.Schema.Struct({
1576
1977
  ...GigadriveNextPrerenderOutputFields,
1577
1978
  ...GigadriveNextPrerenderWithoutClassificationSchema.fields
1578
1979
  })
1579
1980
  )
1580
1981
  );
1581
- var GigadriveNextStaticAssetPrefixSchema = import_effect11.Schema.mutable(
1582
- import_effect11.Schema.Struct({
1982
+ var GigadriveNextStaticAssetPrefixSchema = import_effect16.Schema.mutable(
1983
+ import_effect16.Schema.Struct({
1583
1984
  sourceDir: PortableRelativePathSchema,
1584
1985
  urlPrefix: PortableRelativePathSchema,
1585
- immutable: import_effect11.Schema.Boolean
1986
+ immutable: import_effect16.Schema.Boolean
1586
1987
  })
1587
1988
  );
1588
- var GigadriveNextRouteConditionSchema = import_effect11.Schema.Union(
1589
- import_effect11.Schema.mutable(
1590
- import_effect11.Schema.Struct({
1591
- type: import_effect11.Schema.Literal("header", "cookie", "query"),
1592
- key: import_effect11.Schema.String,
1593
- value: import_effect11.Schema.optional(import_effect11.Schema.String)
1989
+ var GigadriveNextRouteConditionSchema = import_effect16.Schema.Union(
1990
+ import_effect16.Schema.mutable(
1991
+ import_effect16.Schema.Struct({
1992
+ type: import_effect16.Schema.Literal("header", "cookie", "query"),
1993
+ key: import_effect16.Schema.String,
1994
+ value: import_effect16.Schema.optional(import_effect16.Schema.String)
1594
1995
  })
1595
1996
  ),
1596
- import_effect11.Schema.mutable(
1597
- import_effect11.Schema.Struct({
1598
- type: import_effect11.Schema.Literal("host"),
1599
- value: import_effect11.Schema.String
1997
+ import_effect16.Schema.mutable(
1998
+ import_effect16.Schema.Struct({
1999
+ type: import_effect16.Schema.Literal("host"),
2000
+ value: import_effect16.Schema.String
1600
2001
  })
1601
2002
  )
1602
2003
  );
1603
- var GigadriveNextMiddlewareMatcherSchema = import_effect11.Schema.mutable(
1604
- import_effect11.Schema.Struct({
1605
- source: import_effect11.Schema.String,
1606
- sourceRegex: import_effect11.Schema.String,
1607
- has: import_effect11.Schema.optional(import_effect11.Schema.mutable(import_effect11.Schema.Array(GigadriveNextRouteConditionSchema))),
1608
- missing: import_effect11.Schema.optional(import_effect11.Schema.mutable(import_effect11.Schema.Array(GigadriveNextRouteConditionSchema)))
2004
+ var GigadriveNextMiddlewareMatcherSchema = import_effect16.Schema.mutable(
2005
+ import_effect16.Schema.Struct({
2006
+ source: import_effect16.Schema.String,
2007
+ sourceRegex: import_effect16.Schema.String,
2008
+ has: import_effect16.Schema.optional(import_effect16.Schema.mutable(import_effect16.Schema.Array(GigadriveNextRouteConditionSchema))),
2009
+ missing: import_effect16.Schema.optional(import_effect16.Schema.mutable(import_effect16.Schema.Array(GigadriveNextRouteConditionSchema)))
1609
2010
  })
1610
2011
  );
1611
- var GigadriveNextMiddlewareDescriptorSchema = import_effect11.Schema.Union(
1612
- import_effect11.Schema.mutable(
1613
- import_effect11.Schema.Struct({
1614
- present: import_effect11.Schema.Literal(true),
1615
- matchers: import_effect11.Schema.mutable(import_effect11.Schema.Array(GigadriveNextMiddlewareMatcherSchema))
2012
+ var GigadriveNextMiddlewareDescriptorSchema = import_effect16.Schema.Union(
2013
+ import_effect16.Schema.mutable(
2014
+ import_effect16.Schema.Struct({
2015
+ present: import_effect16.Schema.Literal(true),
2016
+ matchers: import_effect16.Schema.mutable(import_effect16.Schema.Array(GigadriveNextMiddlewareMatcherSchema))
1616
2017
  })
1617
2018
  ),
1618
- import_effect11.Schema.mutable(
1619
- import_effect11.Schema.Struct({
1620
- present: import_effect11.Schema.Literal(false),
1621
- matchers: import_effect11.Schema.mutable(import_effect11.Schema.Tuple())
2019
+ import_effect16.Schema.mutable(
2020
+ import_effect16.Schema.Struct({
2021
+ present: import_effect16.Schema.Literal(false),
2022
+ matchers: import_effect16.Schema.mutable(import_effect16.Schema.Tuple())
1622
2023
  })
1623
2024
  )
1624
2025
  );
1625
- var GigadriveNextServerDescriptorSchema = import_effect11.Schema.mutable(
1626
- import_effect11.Schema.Struct({
1627
- maxDuration: import_effect11.Schema.optional(import_effect11.Schema.Number),
1628
- preferredRegion: import_effect11.Schema.optional(import_effect11.Schema.Union(import_effect11.Schema.String, StringArraySchema)),
1629
- env: import_effect11.Schema.optional(StringRecordSchema)
2026
+ var GigadriveNextServerDescriptorSchema = import_effect16.Schema.mutable(
2027
+ import_effect16.Schema.Struct({
2028
+ maxDuration: import_effect16.Schema.optional(import_effect16.Schema.Number),
2029
+ preferredRegion: import_effect16.Schema.optional(import_effect16.Schema.Union(import_effect16.Schema.String, StringArraySchema)),
2030
+ env: import_effect16.Schema.optional(StringRecordSchema)
1630
2031
  })
1631
2032
  );
1632
- var PrerenderArraySchema = import_effect11.Schema.mutable(import_effect11.Schema.Array(GigadriveNextPrerenderOutputSchema));
1633
- var StaticAssetArraySchema = import_effect11.Schema.mutable(import_effect11.Schema.Array(GigadriveNextStaticAssetPrefixSchema));
1634
- var JsonValueArraySchema = import_effect11.Schema.mutable(import_effect11.Schema.Array(JsonValueSchema));
1635
- var GigadriveNextPrerenderSeedMethodsSchema = import_effect11.Schema.mutable(
1636
- import_effect11.Schema.Tuple(import_effect11.Schema.Literal("GET"), import_effect11.Schema.Literal("HEAD"))
2033
+ var PrerenderArraySchema = import_effect16.Schema.mutable(import_effect16.Schema.Array(GigadriveNextPrerenderOutputSchema));
2034
+ var StaticAssetArraySchema = import_effect16.Schema.mutable(import_effect16.Schema.Array(GigadriveNextStaticAssetPrefixSchema));
2035
+ var JsonValueArraySchema = import_effect16.Schema.mutable(import_effect16.Schema.Array(JsonValueSchema));
2036
+ var GigadriveNextPrerenderSeedMethodsSchema = import_effect16.Schema.mutable(
2037
+ import_effect16.Schema.Tuple(import_effect16.Schema.Literal("GET"), import_effect16.Schema.Literal("HEAD"))
1637
2038
  );
1638
- var GigadriveNextBuildManifestV1Schema = import_effect11.Schema.mutable(
1639
- import_effect11.Schema.Struct({
1640
- version: import_effect11.Schema.Literal(1),
1641
- output: import_effect11.Schema.Literal("standalone", "export"),
2039
+ var GigadriveNextBuildManifestV1Schema = import_effect16.Schema.mutable(
2040
+ import_effect16.Schema.Struct({
2041
+ version: import_effect16.Schema.Literal(1),
2042
+ output: import_effect16.Schema.Literal("standalone", "export"),
1642
2043
  distDir: PortableRelativePathSchema,
1643
2044
  repoRootToProject: RepositoryRelativePathSchema,
1644
- nextVersion: import_effect11.Schema.String,
1645
- buildId: import_effect11.Schema.String
2045
+ nextVersion: import_effect16.Schema.String,
2046
+ buildId: import_effect16.Schema.String
1646
2047
  })
1647
2048
  );
1648
- var GigadriveNextBuildManifestV2ExportSchema = import_effect11.Schema.mutable(
1649
- import_effect11.Schema.Struct({
1650
- version: import_effect11.Schema.Literal(2),
1651
- mode: import_effect11.Schema.Literal("export"),
2049
+ var GigadriveNextBuildManifestV2ExportSchema = import_effect16.Schema.mutable(
2050
+ import_effect16.Schema.Struct({
2051
+ version: import_effect16.Schema.Literal(2),
2052
+ mode: import_effect16.Schema.Literal("export"),
1652
2053
  distDir: PortableRelativePathSchema,
1653
2054
  repoRootToProject: RepositoryRelativePathSchema,
1654
- nextVersion: import_effect11.Schema.String,
1655
- buildId: import_effect11.Schema.String
2055
+ nextVersion: import_effect16.Schema.String,
2056
+ buildId: import_effect16.Schema.String
1656
2057
  })
1657
2058
  );
1658
- var GigadriveNextBuildManifestV2StandaloneSchema = import_effect11.Schema.mutable(
1659
- import_effect11.Schema.Struct({
1660
- version: import_effect11.Schema.Literal(2),
1661
- mode: import_effect11.Schema.Literal("standalone-v2"),
2059
+ var GigadriveNextBuildManifestV2StandaloneSchema = import_effect16.Schema.mutable(
2060
+ import_effect16.Schema.Struct({
2061
+ version: import_effect16.Schema.Literal(2),
2062
+ mode: import_effect16.Schema.Literal("standalone-v2"),
1662
2063
  distDir: PortableRelativePathSchema,
1663
2064
  repoRootToProject: RepositoryRelativePathSchema,
1664
- nextVersion: import_effect11.Schema.String,
1665
- buildId: import_effect11.Schema.String,
2065
+ nextVersion: import_effect16.Schema.String,
2066
+ buildId: import_effect16.Schema.String,
1666
2067
  server: GigadriveNextServerDescriptorSchema,
1667
- config: import_effect11.Schema.mutable(
1668
- import_effect11.Schema.Struct({
1669
- basePath: import_effect11.Schema.String,
1670
- trailingSlash: import_effect11.Schema.Boolean,
1671
- cacheComponents: import_effect11.Schema.Boolean,
1672
- i18n: import_effect11.Schema.optional(JsonValueSchema),
1673
- images: import_effect11.Schema.optional(ImagePolicySchema)
2068
+ config: import_effect16.Schema.mutable(
2069
+ import_effect16.Schema.Struct({
2070
+ basePath: import_effect16.Schema.String,
2071
+ trailingSlash: import_effect16.Schema.Boolean,
2072
+ cacheComponents: import_effect16.Schema.Boolean,
2073
+ i18n: import_effect16.Schema.optional(JsonValueSchema),
2074
+ images: import_effect16.Schema.optional(ImagePolicySchema)
1674
2075
  })
1675
2076
  ),
1676
- routing: import_effect11.Schema.mutable(
1677
- import_effect11.Schema.Struct({
2077
+ routing: import_effect16.Schema.mutable(
2078
+ import_effect16.Schema.Struct({
1678
2079
  beforeMiddleware: JsonValueArraySchema,
1679
2080
  beforeFiles: JsonValueArraySchema,
1680
2081
  afterFiles: JsonValueArraySchema,
1681
2082
  dynamicRoutes: JsonValueArraySchema,
1682
2083
  onMatch: JsonValueArraySchema,
1683
2084
  fallback: JsonValueArraySchema,
1684
- shouldNormalizeNextData: import_effect11.Schema.Boolean,
2085
+ shouldNormalizeNextData: import_effect16.Schema.Boolean,
1685
2086
  rsc: JsonValueSchema
1686
2087
  })
1687
2088
  ),
1688
- outputs: import_effect11.Schema.mutable(
1689
- import_effect11.Schema.Struct({
2089
+ outputs: import_effect16.Schema.mutable(
2090
+ import_effect16.Schema.Struct({
1690
2091
  prerenders: PrerenderArraySchema,
1691
- prerenderManifest: import_effect11.Schema.optional(PortableRelativePathSchema),
1692
- assetManifest: import_effect11.Schema.optional(PortableRelativePathSchema),
1693
- entryPagePaths: import_effect11.Schema.optional(import_effect11.Schema.mutable(import_effect11.Schema.Array(UrlPathnameSchema))),
2092
+ prerenderManifest: import_effect16.Schema.optional(PortableRelativePathSchema),
2093
+ assetManifest: import_effect16.Schema.optional(PortableRelativePathSchema),
2094
+ entryPagePaths: import_effect16.Schema.optional(import_effect16.Schema.mutable(import_effect16.Schema.Array(UrlPathnameSchema))),
1694
2095
  staticAssets: StaticAssetArraySchema,
1695
- middleware: import_effect11.Schema.optional(GigadriveNextMiddlewareDescriptorSchema)
2096
+ middleware: import_effect16.Schema.optional(GigadriveNextMiddlewareDescriptorSchema)
1696
2097
  })
1697
2098
  )
1698
2099
  })
1699
2100
  );
1700
- var GigadriveNextBuildManifestSchema = import_effect11.Schema.Union(
2101
+ var GigadriveNextBuildManifestSchema = import_effect16.Schema.Union(
1701
2102
  GigadriveNextBuildManifestV1Schema,
1702
2103
  GigadriveNextBuildManifestV2ExportSchema,
1703
2104
  GigadriveNextBuildManifestV2StandaloneSchema
1704
2105
  );
1705
- var GigadriveNextPrerenderManifestV1Schema = import_effect11.Schema.mutable(
1706
- import_effect11.Schema.Struct({
1707
- version: import_effect11.Schema.Literal(1),
1708
- seedMethods: import_effect11.Schema.optional(GigadriveNextPrerenderSeedMethodsSchema),
2106
+ var GigadriveNextPrerenderManifestV1Schema = import_effect16.Schema.mutable(
2107
+ import_effect16.Schema.Struct({
2108
+ version: import_effect16.Schema.Literal(1),
2109
+ seedMethods: import_effect16.Schema.optional(GigadriveNextPrerenderSeedMethodsSchema),
1709
2110
  prerenders: PrerenderArraySchema
1710
2111
  })
1711
2112
  );
@@ -1715,22 +2116,22 @@ var parseGigadriveNextPrerenderManifest = (content) => decodeJson(GigadriveNextP
1715
2116
  // src/detection/frameworks/nextjs.ts
1716
2117
  var toPortablePath = (value) => value.replaceAll("\\", "/");
1717
2118
  var STANDALONE_SERVER_MEMORY_MB = 1024;
1718
- var resolveStandaloneServer = import_effect12.Effect.fn("nextjs.resolveStandaloneServer")(function* (projectFolder, distDir, repoRootToProject) {
1719
- const fs = yield* import_platform8.FileSystem.FileSystem;
1720
- const pathService = yield* import_platform8.Path.Path;
2119
+ var resolveStandaloneServer = import_effect17.Effect.fn("nextjs.resolveStandaloneServer")(function* (projectFolder, distDir, repoRootToProject) {
2120
+ const fs = yield* import_platform11.FileSystem.FileSystem;
2121
+ const pathService = yield* import_platform11.Path.Path;
1721
2122
  const standaloneRoot = pathService.join(projectFolder, distDir, "standalone");
1722
2123
  const monorepoServer = pathService.join(standaloneRoot, repoRootToProject, "server.js");
1723
2124
  const rootServer = pathService.join(standaloneRoot, "server.js");
1724
- const monorepoServerExists = yield* fs.exists(monorepoServer).pipe(import_effect12.Effect.catchAll(() => import_effect12.Effect.succeed(false)));
2125
+ const monorepoServerExists = yield* fs.exists(monorepoServer).pipe(import_effect17.Effect.catchAll(() => import_effect17.Effect.succeed(false)));
1725
2126
  const serverPath = monorepoServerExists ? monorepoServer : rootServer;
1726
- const serverExists = yield* fs.exists(serverPath).pipe(import_effect12.Effect.catchAll(() => import_effect12.Effect.succeed(false)));
2127
+ const serverExists = yield* fs.exists(serverPath).pipe(import_effect17.Effect.catchAll(() => import_effect17.Effect.succeed(false)));
1727
2128
  if (!serverExists) return void 0;
1728
2129
  const serverDirectory = pathService.dirname(serverPath);
1729
2130
  const entrypoint = toPortablePath(pathService.relative(standaloneRoot, serverPath));
1730
2131
  return { standaloneRoot, serverDirectory, entrypoint };
1731
2132
  });
1732
- var buildStandalonePublicAssets = import_effect12.Effect.fn("nextjs.buildStandalonePublicAssets")(function* (projectFolder, standaloneRoot, serverDirectory) {
1733
- const pathService = yield* import_platform8.Path.Path;
2133
+ var buildStandalonePublicAssets = import_effect17.Effect.fn("nextjs.buildStandalonePublicAssets")(function* (projectFolder, standaloneRoot, serverDirectory) {
2134
+ const pathService = yield* import_platform11.Path.Path;
1734
2135
  const publicFiles = yield* getDefaultPathMap(pathService.join(projectFolder, "public"));
1735
2136
  const assetPaths = [];
1736
2137
  const assetOverrides = {};
@@ -1746,8 +2147,8 @@ var buildStandalonePublicAssets = import_effect12.Effect.fn("nextjs.buildStandal
1746
2147
  }
1747
2148
  return { assetPaths, assetOverrides, filePathMap };
1748
2149
  });
1749
- var createStaticExportConfig = import_effect12.Effect.fn("nextjs.createStaticExportConfig")(function* (defaults, projectFolder) {
1750
- const pathService = yield* import_platform8.Path.Path;
2150
+ var createStaticExportConfig = import_effect17.Effect.fn("nextjs.createStaticExportConfig")(function* (defaults, projectFolder) {
2151
+ const pathService = yield* import_platform11.Path.Path;
1751
2152
  const outputDirectory = pathService.join(projectFolder, "out");
1752
2153
  const files = yield* getDefaultPathMap(outputDirectory);
1753
2154
  const assetPaths = [];
@@ -1770,8 +2171,8 @@ var createStaticExportConfig = import_effect12.Effect.fn("nextjs.createStaticExp
1770
2171
  package: void 0
1771
2172
  };
1772
2173
  });
1773
- var createStandaloneConfig = import_effect12.Effect.fn("nextjs.createStandaloneConfig")(function* (defaults, projectFolder, manifest) {
1774
- const pathService = yield* import_platform8.Path.Path;
2174
+ var createStandaloneConfig = import_effect17.Effect.fn("nextjs.createStandaloneConfig")(function* (defaults, projectFolder, manifest) {
2175
+ const pathService = yield* import_platform11.Path.Path;
1775
2176
  const resolved = yield* resolveStandaloneServer(projectFolder, manifest.distDir, manifest.repoRootToProject);
1776
2177
  if (!resolved) return defaults;
1777
2178
  const { standaloneRoot, serverDirectory, entrypoint } = resolved;
@@ -1804,7 +2205,7 @@ var createStandaloneConfig = import_effect12.Effect.fn("nextjs.createStandaloneC
1804
2205
  }
1805
2206
  };
1806
2207
  });
1807
- var createStandaloneV2Config = import_effect12.Effect.fn("nextjs.createStandaloneV2Config")(function* (defaults, projectFolder, manifest) {
2208
+ var createStandaloneV2Config = import_effect17.Effect.fn("nextjs.createStandaloneV2Config")(function* (defaults, projectFolder, manifest) {
1808
2209
  const resolved = yield* resolveStandaloneServer(projectFolder, manifest.distDir, manifest.repoRootToProject);
1809
2210
  if (!resolved) return defaults;
1810
2211
  const { standaloneRoot, serverDirectory, entrypoint } = resolved;
@@ -1912,9 +2313,9 @@ var nextjs = {
1912
2313
  routes: [{ source: "/*", destination: ".next/standalone/server.js" }],
1913
2314
  environmentVariables: { NODE_ENV: "production" }
1914
2315
  }),
1915
- refineDefaultConfig: (defaults, projectFolder) => import_effect12.Effect.gen(function* () {
1916
- const fs = yield* import_platform8.FileSystem.FileSystem;
1917
- const manifestContent = yield* fs.readFileString(`${projectFolder}/.gigadrive/nextjs.json`).pipe(import_effect12.Effect.catchAll(() => import_effect12.Effect.succeed(void 0)));
2316
+ refineDefaultConfig: (defaults, projectFolder) => import_effect17.Effect.gen(function* () {
2317
+ const fs = yield* import_platform11.FileSystem.FileSystem;
2318
+ const manifestContent = yield* fs.readFileString(`${projectFolder}/.gigadrive/nextjs.json`).pipe(import_effect17.Effect.catchAll(() => import_effect17.Effect.succeed(void 0)));
1918
2319
  const manifest = manifestContent ? parseGigadriveNextBuildManifest(manifestContent) : void 0;
1919
2320
  if (!manifest) return defaults;
1920
2321
  if (manifest.version === 2) {
@@ -1925,8 +2326,8 @@ var nextjs = {
1925
2326
  };
1926
2327
 
1927
2328
  // src/detection/frameworks/nuxt.ts
1928
- var import_platform9 = require("@effect/platform");
1929
- var import_effect13 = require("effect");
2329
+ var import_platform12 = require("@effect/platform");
2330
+ var import_effect18 = require("effect");
1930
2331
  var isVercelBuildOutputV3 = (content) => {
1931
2332
  try {
1932
2333
  const config = JSON.parse(content);
@@ -1953,9 +2354,9 @@ var nuxt = {
1953
2354
  routes: [{ source: "/*", destination: ".output/server/index.mjs" }],
1954
2355
  environmentVariables: { NODE_ENV: "production", NITRO_PRESET: "node-server" }
1955
2356
  }),
1956
- refineDefaultConfig: (defaults, projectFolder) => import_effect13.Effect.gen(function* () {
1957
- const fs = yield* import_platform9.FileSystem.FileSystem;
1958
- const buildOutputConfig = yield* fs.readFileString(`${projectFolder}/.vercel/output/config.json`).pipe(import_effect13.Effect.catchAll(() => import_effect13.Effect.succeed(void 0)));
2357
+ refineDefaultConfig: (defaults, projectFolder) => import_effect18.Effect.gen(function* () {
2358
+ const fs = yield* import_platform12.FileSystem.FileSystem;
2359
+ const buildOutputConfig = yield* fs.readFileString(`${projectFolder}/.vercel/output/config.json`).pipe(import_effect18.Effect.catchAll(() => import_effect18.Effect.succeed(void 0)));
1959
2360
  if (!buildOutputConfig || !isVercelBuildOutputV3(buildOutputConfig)) {
1960
2361
  return defaults;
1961
2362
  }
@@ -1970,16 +2371,16 @@ var nuxt = {
1970
2371
  };
1971
2372
 
1972
2373
  // src/detection/frameworks/php.ts
1973
- var import_platform10 = require("@effect/platform");
1974
- var import_effect14 = require("effect");
2374
+ var import_platform13 = require("@effect/platform");
2375
+ var import_effect19 = require("effect");
1975
2376
  var COMPOSER_FILES = ["composer.json", "composer.lock"];
1976
2377
  var DOCUMENT_ROOTS = ["public", "web", "webroot", "public_html", "htdocs", "."];
1977
- var refinePhpDocumentRoot = (defaults, projectFolder) => import_effect14.Effect.gen(function* () {
1978
- const fs = yield* import_platform10.FileSystem.FileSystem;
1979
- const pathService = yield* import_platform10.Path.Path;
2378
+ var refinePhpDocumentRoot = (defaults, projectFolder) => import_effect19.Effect.gen(function* () {
2379
+ const fs = yield* import_platform13.FileSystem.FileSystem;
2380
+ const pathService = yield* import_platform13.Path.Path;
1980
2381
  for (const documentRoot of DOCUMENT_ROOTS) {
1981
2382
  const frontController = pathService.join(projectFolder, documentRoot, "index.php");
1982
- if (yield* fs.exists(frontController).pipe(import_effect14.Effect.catchAll(() => import_effect14.Effect.succeed(false)))) {
2383
+ if (yield* fs.exists(frontController).pipe(import_effect19.Effect.catchAll(() => import_effect19.Effect.succeed(false)))) {
1983
2384
  return phpFrontControllerDefaults({ documentRoot, excludeFiles: COMPOSER_FILES });
1984
2385
  }
1985
2386
  }
@@ -2003,9 +2404,215 @@ var phpSites = DOCUMENT_ROOTS.map((documentRoot) => ({
2003
2404
  detectors: [{ path: frontControllerPath(documentRoot) }],
2004
2405
  priority: 6,
2005
2406
  getDefaultConfig: () => ({ ...getDefaultConfig(), installCommand: "" }),
2006
- refineDefaultConfig: (defaults, projectFolder) => refinePhpDocumentRoot(defaults, projectFolder).pipe(import_effect14.Effect.map((refined) => ({ ...refined, installCommand: "" })))
2407
+ refineDefaultConfig: (defaults, projectFolder) => refinePhpDocumentRoot(defaults, projectFolder).pipe(import_effect19.Effect.map((refined) => ({ ...refined, installCommand: "" })))
2007
2408
  }));
2008
2409
 
2410
+ // src/detection/frameworks/php-runtime.ts
2411
+ var import_platform14 = require("@effect/platform");
2412
+ var import_effect20 = require("effect");
2413
+
2414
+ // src/detection/frameworks/composer-constraint.ts
2415
+ var STABILITY_SUFFIX = /-(?:dev|alpha|beta|a|b|rc|patch|pl|p|stable)\.?\d*$/i;
2416
+ var parseVersion = (text) => {
2417
+ const parts = text.replace(/^v/i, "").replace(STABILITY_SUFFIX, "").split(".");
2418
+ if (parts.length > 4) {
2419
+ return void 0;
2420
+ }
2421
+ const segments = [];
2422
+ let wildcard = false;
2423
+ for (const part of parts) {
2424
+ if (/^[*x]$/i.test(part)) {
2425
+ wildcard = true;
2426
+ } else if (/^\d+$/.test(part) && !wildcard) {
2427
+ segments.push(Number(part));
2428
+ } else {
2429
+ return void 0;
2430
+ }
2431
+ }
2432
+ return { segments, wildcard };
2433
+ };
2434
+ var pad = (segments) => [segments[0] ?? 0, segments[1] ?? 0, segments[2] ?? 0, segments[3] ?? 0];
2435
+ var bump = (segments, position) => pad(segments.slice(0, position).map((segment, index) => index === position - 1 ? segment + 1 : segment));
2436
+ var compare = (a, b) => {
2437
+ for (let index = 0; index < 4; index++) {
2438
+ if (a[index] !== b[index]) {
2439
+ return a[index] - b[index];
2440
+ }
2441
+ }
2442
+ return 0;
2443
+ };
2444
+ var inRange = (version, lower, upper) => compare(version, lower) >= 0 && compare(version, upper) < 0;
2445
+ var allowsAtom = (atom, version) => {
2446
+ const match = /^(\^|~|>=|<=|<>|!=|==|=|>|<)?(.+)$/.exec(atom);
2447
+ const parsed = match ? parseVersion(match[2]) : void 0;
2448
+ if (!match || !parsed) {
2449
+ return void 0;
2450
+ }
2451
+ const operator = match[1];
2452
+ const { segments } = parsed;
2453
+ if (parsed.wildcard) {
2454
+ if (operator !== void 0) {
2455
+ return void 0;
2456
+ }
2457
+ return segments.length === 0 || inRange(version, pad(segments), bump(segments, segments.length));
2458
+ }
2459
+ const target = pad(segments);
2460
+ switch (operator) {
2461
+ case "^": {
2462
+ const position = segments[0] !== 0 || segments.length < 2 ? 1 : segments[1] !== 0 || segments.length < 3 ? 2 : 3;
2463
+ return inRange(version, target, bump(segments, position));
2464
+ }
2465
+ case "~":
2466
+ return inRange(version, target, bump(segments, Math.max(1, segments.length - 1)));
2467
+ case ">=":
2468
+ return compare(version, target) >= 0;
2469
+ case ">":
2470
+ return compare(version, target) > 0;
2471
+ case "<=":
2472
+ return compare(version, target) <= 0;
2473
+ case "<":
2474
+ return compare(version, target) < 0;
2475
+ case "!=":
2476
+ case "<>":
2477
+ return compare(version, target) !== 0;
2478
+ default:
2479
+ return compare(version, target) === 0;
2480
+ }
2481
+ };
2482
+ var allowsHyphenRange = (from, to, version) => {
2483
+ const lower = parseVersion(from);
2484
+ const upper = parseVersion(to);
2485
+ if (!lower || !upper || lower.wildcard || upper.wildcard) {
2486
+ return void 0;
2487
+ }
2488
+ const withinUpper = upper.segments.length >= 3 ? compare(version, pad(upper.segments)) <= 0 : compare(version, bump(upper.segments, upper.segments.length)) < 0;
2489
+ return compare(version, pad(lower.segments)) >= 0 && withinUpper;
2490
+ };
2491
+ var allowsAll = (branch, version) => {
2492
+ const tokens = branch.trim().replace(/([<>=!~^]+)\s+/g, "$1").split(/\s*,\s*|\s+/).filter((token) => token !== "");
2493
+ if (tokens.length === 0) {
2494
+ return void 0;
2495
+ }
2496
+ let allowed = true;
2497
+ for (let index = 0; index < tokens.length; index++) {
2498
+ let result;
2499
+ if (tokens[index + 1] === "-") {
2500
+ const to = tokens[index + 2];
2501
+ result = to === void 0 ? void 0 : allowsHyphenRange(tokens[index], to, version);
2502
+ index += 2;
2503
+ } else {
2504
+ result = allowsAtom(tokens[index], version);
2505
+ }
2506
+ if (result === void 0) {
2507
+ return void 0;
2508
+ }
2509
+ allowed &&= result;
2510
+ }
2511
+ return allowed;
2512
+ };
2513
+ var composerConstraintAllows = (constraint, version) => {
2514
+ const parsed = parseVersion(version);
2515
+ if (!parsed || parsed.wildcard || parsed.segments.length === 0) {
2516
+ return void 0;
2517
+ }
2518
+ const target = pad(parsed.segments);
2519
+ let allowed = false;
2520
+ for (const branch of constraint.replace(/@[a-z]+/gi, "").split(/\|\|?/)) {
2521
+ const result = allowsAll(branch, target);
2522
+ if (result === void 0) {
2523
+ return void 0;
2524
+ }
2525
+ allowed ||= result;
2526
+ }
2527
+ return allowed;
2528
+ };
2529
+
2530
+ // src/detection/frameworks/php-runtime.ts
2531
+ var PHP_RUNTIME_CANDIDATES = [
2532
+ { runtime: "php-84", newestVersion: "8.4.9999" },
2533
+ { runtime: "php-83", newestVersion: "8.3.9999" }
2534
+ ];
2535
+ var phpRuntimeForConstraint = (constraint) => PHP_RUNTIME_CANDIDATES.find(({ newestVersion }) => composerConstraintAllows(constraint, newestVersion) === true)?.runtime;
2536
+ var readPhpConstraint = import_effect20.Effect.fn("readPhpConstraint")(
2537
+ function* (projectFolder) {
2538
+ const fs = yield* import_platform14.FileSystem.FileSystem;
2539
+ const pathService = yield* import_platform14.Path.Path;
2540
+ const content = yield* fs.readFileString(pathService.join(projectFolder, "composer.json"));
2541
+ const manifest = yield* import_effect20.Effect.try(() => JSON.parse(content));
2542
+ const requires = manifest && typeof manifest === "object" && "require" in manifest ? manifest.require : void 0;
2543
+ const php = requires && typeof requires === "object" && "php" in requires ? requires.php : void 0;
2544
+ return typeof php === "string" ? import_effect20.Option.some(php) : import_effect20.Option.none();
2545
+ },
2546
+ import_effect20.Effect.catchAll(() => import_effect20.Effect.succeed(import_effect20.Option.none()))
2547
+ );
2548
+ var refineComposerPhpRuntime = import_effect20.Effect.fn("refineComposerPhpRuntime")(function* (defaults, projectFolder) {
2549
+ const constraint = yield* readPhpConstraint(projectFolder);
2550
+ const runtime = import_effect20.Option.getOrUndefined(import_effect20.Option.flatMapNullable(constraint, phpRuntimeForConstraint));
2551
+ return runtime ? { ...defaults, runtime } : defaults;
2552
+ });
2553
+ var withComposerPhpRuntime = (framework) => ({
2554
+ ...framework,
2555
+ refineDefaultConfig: (defaults, projectFolder) => import_effect20.Effect.gen(function* () {
2556
+ const refined = framework.refineDefaultConfig ? yield* framework.refineDefaultConfig(defaults, projectFolder) : defaults;
2557
+ return yield* refineComposerPhpRuntime(refined, projectFolder);
2558
+ })
2559
+ });
2560
+
2561
+ // src/detection/frameworks/rack.ts
2562
+ var rack = {
2563
+ slug: "rack",
2564
+ name: "Rack",
2565
+ language: "ruby",
2566
+ detectors: [{ path: "config.ru" }, { path: "Gemfile" }],
2567
+ priority: 10,
2568
+ getDefaultConfig: () => rubyServerDefaults({ environmentVariables: { RACK_ENV: "production" } }),
2569
+ refineDefaultConfig: refineRubyPublicDirectory
2570
+ };
2571
+
2572
+ // src/detection/frameworks/rails.ts
2573
+ var import_effect21 = require("effect");
2574
+ var ASSET_PIPELINE_GEMS = ["propshaft", "sprockets", "sprockets-rails"];
2575
+ var refineRailsAssets = import_effect21.Effect.fn("refineRailsAssets")(function* (defaults, projectFolder) {
2576
+ const gems = yield* readDependencies(projectFolder, "ruby").pipe(
2577
+ import_effect21.Effect.catchAll(() => import_effect21.Effect.succeed(/* @__PURE__ */ new Set()))
2578
+ );
2579
+ const withPublicDirectory = yield* refineRubyPublicDirectory(defaults, projectFolder);
2580
+ return ASSET_PIPELINE_GEMS.some((gem) => gems.has(gem)) ? {
2581
+ ...withPublicDirectory,
2582
+ commands: [...withPublicDirectory.commands, "SECRET_KEY_BASE_DUMMY=1 bundle exec rails assets:precompile"]
2583
+ } : withPublicDirectory;
2584
+ });
2585
+ var rails = {
2586
+ slug: "rails",
2587
+ name: "Ruby on Rails",
2588
+ language: "ruby",
2589
+ // `railties` is in every Rails application's Gemfile.lock, including ones
2590
+ // that require individual Rails gems instead of `rails`.
2591
+ detectors: [{ matchPackage: "railties" }, { path: "config/application.rb" }],
2592
+ priority: 80,
2593
+ getDefaultConfig: () => rubyServerDefaults({
2594
+ memory: 512,
2595
+ excludeFiles: ["tmp/", "log/", "storage/", "test/", "spec/", "node_modules/", ".git/"],
2596
+ // tmp/, log/ and storage/ are excluded, so the directories Rails writes
2597
+ // caches, pids, sockets, logs and Active Storage files to are created empty.
2598
+ writablePaths: ["tmp/cache", "tmp/pids", "tmp/sockets", "tmp/storage", "log", "storage"],
2599
+ environmentVariables: {
2600
+ RAILS_ENV: "production",
2601
+ RACK_ENV: "production",
2602
+ // Signs and encrypts cookies and sessions; Rails refuses to boot in production without it.
2603
+ SECRET_KEY_BASE: generatedSecret("hex"),
2604
+ RAILS_LOG_TO_STDOUT: "1",
2605
+ RAILS_SERVE_STATIC_FILES: "1",
2606
+ RAILS_MAX_THREADS: "5"
2607
+ }
2608
+ }),
2609
+ refineDefaultConfig: refineRailsAssets
2610
+ };
2611
+ var railsPresets = [
2612
+ rails,
2613
+ { ...rails, detectors: [{ matchPackage: "rails" }, { path: "config/application.rb" }] }
2614
+ ];
2615
+
2009
2616
  // src/detection/frameworks/remix.ts
2010
2617
  var remix = {
2011
2618
  slug: "remix",
@@ -2027,6 +2634,45 @@ var remix = {
2027
2634
  })
2028
2635
  };
2029
2636
 
2637
+ // src/detection/frameworks/roda.ts
2638
+ var roda = {
2639
+ slug: "roda",
2640
+ name: "Roda",
2641
+ language: "ruby",
2642
+ detectors: [{ matchPackage: "roda" }, { path: "config.ru" }],
2643
+ priority: 60,
2644
+ getDefaultConfig: () => rubyServerDefaults({ environmentVariables: { RACK_ENV: "production" } }),
2645
+ refineDefaultConfig: refineRubyPublicDirectory
2646
+ };
2647
+
2648
+ // src/detection/frameworks/sinatra.ts
2649
+ var import_platform15 = require("@effect/platform");
2650
+ var import_effect22 = require("effect");
2651
+ var SINATRA_ENTRYPOINTS = ["config.ru", "app.rb", "main.rb", "server.rb", "application.rb"];
2652
+ var refineSinatraEntrypoint = import_effect22.Effect.fn("refineSinatraEntrypoint")(function* (defaults, projectFolder) {
2653
+ const fs = yield* import_platform15.FileSystem.FileSystem;
2654
+ const pathService = yield* import_platform15.Path.Path;
2655
+ const entrypoint = yield* import_effect22.Effect.findFirst(
2656
+ SINATRA_ENTRYPOINTS,
2657
+ (file) => fs.exists(pathService.join(projectFolder, file)).pipe(import_effect22.Effect.catchAll(() => import_effect22.Effect.succeed(false)))
2658
+ );
2659
+ const withPublicDirectory = yield* refineRubyPublicDirectory(defaults, projectFolder);
2660
+ return entrypoint._tag === "Some" ? {
2661
+ ...withPublicDirectory,
2662
+ entrypoint: entrypoint.value,
2663
+ routes: [{ source: "/*", destination: entrypoint.value }]
2664
+ } : withPublicDirectory;
2665
+ });
2666
+ var sinatra = {
2667
+ slug: "sinatra",
2668
+ name: "Sinatra",
2669
+ language: "ruby",
2670
+ detectors: [{ matchPackage: "sinatra" }],
2671
+ priority: 60,
2672
+ getDefaultConfig: () => rubyServerDefaults({ environmentVariables: { APP_ENV: "production", RACK_ENV: "production" } }),
2673
+ refineDefaultConfig: refineSinatraEntrypoint
2674
+ };
2675
+
2030
2676
  // src/detection/frameworks/slim.ts
2031
2677
  var slim = {
2032
2678
  slug: "slim",
@@ -2147,17 +2793,33 @@ var FRAMEWORK_DEFINITIONS = [
2147
2793
  mezzio,
2148
2794
  yii,
2149
2795
  slim,
2796
+ ...railsPresets,
2797
+ hanami,
2798
+ ...jekyllPresets,
2799
+ bridgetown,
2800
+ sinatra,
2801
+ roda,
2150
2802
  hono,
2151
2803
  elysia,
2152
2804
  fastify,
2153
2805
  express,
2806
+ rack,
2154
2807
  ...phpComposerProjects,
2155
2808
  ...phpSites,
2156
2809
  vite
2157
- ].sort((a, b) => b.priority - a.priority);
2810
+ ].map((framework) => {
2811
+ switch (framework.language) {
2812
+ case "php":
2813
+ return withComposerPhpRuntime(framework);
2814
+ case "ruby":
2815
+ return withRubyRuntime(framework);
2816
+ case "node":
2817
+ return framework;
2818
+ }
2819
+ }).sort((a, b) => b.priority - a.priority);
2158
2820
 
2159
2821
  // src/detection/generate-config.ts
2160
- var import_effect15 = require("effect");
2822
+ var import_effect23 = require("effect");
2161
2823
  var getInstallCommand = (pm) => {
2162
2824
  switch (pm) {
2163
2825
  case "bun":
@@ -2168,6 +2830,8 @@ var getInstallCommand = (pm) => {
2168
2830
  return "yarn install";
2169
2831
  case "composer":
2170
2832
  return "composer install";
2833
+ case "bundler":
2834
+ return "bundle install";
2171
2835
  case "npm":
2172
2836
  default:
2173
2837
  return "npm install";
@@ -2178,11 +2842,17 @@ var isPrivatePhpProjectFile = (projectPath) => {
2178
2842
  const segments = projectPath.split("/").filter((segment) => segment !== "" && segment !== ".");
2179
2843
  return segments.some((segment) => segment.startsWith(".")) || segments[0] === "vendor" || segments[0] === "node_modules" || segments.length === 1 && COMPOSER_ROOT_FILES.has(segments[0] ?? "");
2180
2844
  };
2181
- var generateConfig = import_effect15.Effect.fn("generateConfig")(function* (framework, packageManager, projectFolder, refinedDefaults) {
2845
+ var BUNDLER_FILES = /* @__PURE__ */ new Set(["Gemfile", "Gemfile.lock", "gems.rb", "gems.locked"]);
2846
+ var isPrivateRubyProjectFile = (projectPath) => {
2847
+ const segments = projectPath.split("/").filter((segment) => segment !== "" && segment !== ".");
2848
+ const fileName = segments.at(-1) ?? "";
2849
+ return segments.some((segment) => segment.startsWith(".")) || segments[0] === "vendor" || /\.(rb|ru)$/i.test(fileName) || BUNDLER_FILES.has(fileName);
2850
+ };
2851
+ var generateConfig = import_effect23.Effect.fn("generateConfig")(function* (framework, packageManager, projectFolder, refinedDefaults) {
2182
2852
  const defaults = refinedDefaults ?? framework.getDefaultConfig(packageManager);
2183
2853
  const installCmd = defaults.installCommand ?? getInstallCommand(packageManager);
2184
2854
  const commands = installCmd ? [installCmd, ...defaults.commands] : [...defaults.commands];
2185
- yield* import_effect15.Effect.logDebug(`Generating config for ${framework.name}`, {
2855
+ yield* import_effect23.Effect.logDebug(`Generating config for ${framework.name}`, {
2186
2856
  runtime: defaults.runtime,
2187
2857
  entrypoint: defaults.entrypoint,
2188
2858
  commands
@@ -2225,6 +2895,7 @@ var generateConfig = import_effect15.Effect.fn("generateConfig")(function* (fram
2225
2895
  for (const file of yield* collectAssetFiles(projectFolder, assetsDir)) {
2226
2896
  if (framework.language === "php" && /\.(php|phtml|phar)$/i.test(file)) continue;
2227
2897
  if (framework.language === "php" && isPrivatePhpProjectFile(`${assetsDir}/${file}`)) continue;
2898
+ if (framework.language === "ruby" && isPrivateRubyProjectFile(`${assetsDir}/${file}`)) continue;
2228
2899
  paths.push(`${assetsDir}/${file}`);
2229
2900
  if (!servesDirectoryIndexes || file in overrides) continue;
2230
2901
  if (file === "index.html") {
@@ -2247,80 +2918,10 @@ var generateConfig = import_effect15.Effect.fn("generateConfig")(function* (fram
2247
2918
  return config;
2248
2919
  });
2249
2920
 
2250
- // src/detection/read-dependencies.ts
2251
- var import_platform11 = require("@effect/platform");
2252
- var import_effect17 = require("effect");
2253
-
2254
- // src/detection/types.ts
2255
- var import_effect16 = require("effect");
2256
- var ManifestNotFoundError = class extends import_effect16.Schema.TaggedError()("ManifestNotFoundError", {
2257
- message: import_effect16.Schema.String,
2258
- filePath: import_effect16.Schema.String
2259
- }) {
2260
- };
2261
- var ManifestReadError = class extends import_effect16.Schema.TaggedError()("ManifestReadError", {
2262
- message: import_effect16.Schema.String,
2263
- filePath: import_effect16.Schema.String
2264
- }) {
2265
- };
2266
- var ManifestParseError = class extends import_effect16.Schema.TaggedError()("ManifestParseError", {
2267
- message: import_effect16.Schema.String,
2268
- filePath: import_effect16.Schema.String
2269
- }) {
2270
- };
2271
- var FrameworkNotDetectedError = class extends import_effect16.Schema.TaggedError()(
2272
- "FrameworkNotDetectedError",
2273
- {
2274
- message: import_effect16.Schema.String,
2275
- directory: import_effect16.Schema.String
2276
- }
2277
- ) {
2278
- };
2279
-
2280
- // src/detection/read-dependencies.ts
2281
- var MANIFEST_CONFIG = {
2282
- node: { file: "package.json", depKeys: ["dependencies", "devDependencies"] },
2283
- php: { file: "composer.json", depKeys: ["require", "require-dev"] }
2284
- };
2285
- var readManifest = import_effect17.Effect.fn("readManifest")(function* (filePath) {
2286
- const fs = yield* import_platform11.FileSystem.FileSystem;
2287
- const exists = yield* fs.exists(filePath).pipe(import_effect17.Effect.catchAll(() => import_effect17.Effect.succeed(false)));
2288
- if (!exists) {
2289
- return yield* import_effect17.Effect.fail(new ManifestNotFoundError({ message: "Manifest not found", filePath }));
2290
- }
2291
- const content = yield* fs.readFileString(filePath).pipe(import_effect17.Effect.mapError(() => new ManifestReadError({ message: "Failed to read manifest", filePath })));
2292
- const parsed = yield* import_effect17.Effect.try({
2293
- try: () => JSON.parse(content),
2294
- catch: () => new ManifestParseError({ message: "Failed to parse manifest JSON", filePath })
2295
- });
2296
- return parsed;
2297
- });
2298
- var readDependencies = import_effect17.Effect.fn("readDependencies")(function* (projectFolder, language) {
2299
- const pathService = yield* import_platform11.Path.Path;
2300
- const config = MANIFEST_CONFIG[language];
2301
- const filePath = pathService.join(projectFolder, config.file);
2302
- const manifest = yield* readManifest(filePath).pipe(
2303
- import_effect17.Effect.catchTag("ManifestNotFoundError", () => import_effect17.Effect.succeed(null))
2304
- );
2305
- if (!manifest) {
2306
- return /* @__PURE__ */ new Set();
2307
- }
2308
- const deps = /* @__PURE__ */ new Set();
2309
- for (const key of config.depKeys) {
2310
- const section = manifest[key];
2311
- if (section && typeof section === "object" && !Array.isArray(section)) {
2312
- for (const name of Object.keys(section)) {
2313
- deps.add(name);
2314
- }
2315
- }
2316
- }
2317
- return deps;
2318
- });
2319
-
2320
2921
  // src/detection/detect-framework.ts
2321
- var matchesDetectionItem = import_effect18.Effect.fn("matchesDetectionItem")(function* (item, projectFolder, framework, cachedReadDeps) {
2322
- const fs = yield* import_platform12.FileSystem.FileSystem;
2323
- const pathService = yield* import_platform12.Path.Path;
2922
+ var matchesDetectionItem = import_effect24.Effect.fn("matchesDetectionItem")(function* (item, projectFolder, framework, cachedReadDeps) {
2923
+ const fs = yield* import_platform16.FileSystem.FileSystem;
2924
+ const pathService = yield* import_platform16.Path.Path;
2324
2925
  if (item.matchPackage != null) {
2325
2926
  const deps = yield* cachedReadDeps(`${projectFolder}\0${framework.language}`);
2326
2927
  if (!deps.has(item.matchPackage)) {
@@ -2329,12 +2930,12 @@ var matchesDetectionItem = import_effect18.Effect.fn("matchesDetectionItem")(fun
2329
2930
  }
2330
2931
  if (item.path != null) {
2331
2932
  const filePath = pathService.join(projectFolder, item.path);
2332
- const exists = yield* fs.exists(filePath).pipe(import_effect18.Effect.catchAll(() => import_effect18.Effect.succeed(false)));
2933
+ const exists = yield* fs.exists(filePath).pipe(import_effect24.Effect.catchAll(() => import_effect24.Effect.succeed(false)));
2333
2934
  if (!exists) {
2334
2935
  return false;
2335
2936
  }
2336
2937
  if (item.matchContent != null) {
2337
- const content = yield* fs.readFileString(filePath).pipe(import_effect18.Effect.catchAll(() => import_effect18.Effect.succeed("")));
2938
+ const content = yield* fs.readFileString(filePath).pipe(import_effect24.Effect.catchAll(() => import_effect24.Effect.succeed("")));
2338
2939
  let regexMatch = false;
2339
2940
  try {
2340
2941
  regexMatch = new RegExp(item.matchContent).test(content);
@@ -2347,7 +2948,7 @@ var matchesDetectionItem = import_effect18.Effect.fn("matchesDetectionItem")(fun
2347
2948
  }
2348
2949
  return true;
2349
2950
  });
2350
- var matchesFramework = import_effect18.Effect.fn("matchesFramework")(function* (framework, projectFolder, cachedReadDeps) {
2951
+ var matchesFramework = import_effect24.Effect.fn("matchesFramework")(function* (framework, projectFolder, cachedReadDeps) {
2351
2952
  for (const detector of framework.detectors) {
2352
2953
  const matches = yield* matchesDetectionItem(detector, projectFolder, framework, cachedReadDeps);
2353
2954
  if (!matches) {
@@ -2356,9 +2957,19 @@ var matchesFramework = import_effect18.Effect.fn("matchesFramework")(function* (
2356
2957
  }
2357
2958
  return true;
2358
2959
  });
2359
- var detectFramework = import_effect18.Effect.fn("detectFramework")(function* (projectFolder) {
2360
- yield* import_effect18.Effect.logDebug(`Detecting framework in ${projectFolder}`);
2361
- const cachedReadDeps = yield* import_effect18.Effect.cachedFunction((key) => {
2960
+ var packageManagerForLanguage = (language, detected) => {
2961
+ switch (language) {
2962
+ case "php":
2963
+ return "composer";
2964
+ case "ruby":
2965
+ return "bundler";
2966
+ case "node":
2967
+ return detected === "bundler" ? "npm" : detected;
2968
+ }
2969
+ };
2970
+ var detectFramework = import_effect24.Effect.fn("detectFramework")(function* (projectFolder) {
2971
+ yield* import_effect24.Effect.logDebug(`Detecting framework in ${projectFolder}`);
2972
+ const cachedReadDeps = yield* import_effect24.Effect.cachedFunction((key) => {
2362
2973
  const sepIndex = key.lastIndexOf("\0");
2363
2974
  const folder = key.slice(0, sepIndex);
2364
2975
  const language = key.slice(sepIndex + 1);
@@ -2367,16 +2978,16 @@ var detectFramework = import_effect18.Effect.fn("detectFramework")(function* (pr
2367
2978
  for (const framework of FRAMEWORK_DEFINITIONS) {
2368
2979
  const matches = yield* matchesFramework(framework, projectFolder, cachedReadDeps);
2369
2980
  if (matches) {
2370
- yield* import_effect18.Effect.log(`Detected framework: ${framework.name}`, { slug: framework.slug });
2981
+ yield* import_effect24.Effect.log(`Detected framework: ${framework.name}`, { slug: framework.slug });
2371
2982
  const detectedPackageManager = yield* detectPackageManager(projectFolder);
2372
- const packageManager = framework.language === "php" ? "composer" : detectedPackageManager;
2983
+ const packageManager = packageManagerForLanguage(framework.language, detectedPackageManager);
2373
2984
  const defaults = framework.getDefaultConfig(packageManager);
2374
2985
  const refinedDefaults = framework.refineDefaultConfig ? yield* framework.refineDefaultConfig(defaults, projectFolder) : defaults;
2375
2986
  const config = yield* generateConfig(framework, packageManager, projectFolder, refinedDefaults);
2376
2987
  return { framework, packageManager, config };
2377
2988
  }
2378
2989
  }
2379
- return yield* import_effect18.Effect.fail(
2990
+ return yield* import_effect24.Effect.fail(
2380
2991
  new FrameworkNotDetectedError({
2381
2992
  message: `No framework detected in project directory`,
2382
2993
  directory: projectFolder
@@ -2385,9 +2996,9 @@ var detectFramework = import_effect18.Effect.fn("detectFramework")(function* (pr
2385
2996
  });
2386
2997
 
2387
2998
  // src/detection/merge-config.ts
2388
- var import_effect19 = require("effect");
2389
- var mergeWithFrameworkDefaults = import_effect19.Effect.fn("mergeWithFrameworkDefaults")(function* (userConfig, frameworkConfig) {
2390
- yield* import_effect19.Effect.logDebug("Merging user config with framework defaults");
2999
+ var import_effect25 = require("effect");
3000
+ var mergeWithFrameworkDefaults = import_effect25.Effect.fn("mergeWithFrameworkDefaults")(function* (userConfig, frameworkConfig) {
3001
+ yield* import_effect25.Effect.logDebug("Merging user config with framework defaults");
2391
3002
  const userHasAssets = (userConfig.assets?.paths?.length ?? 0) > 0 || (userConfig.assets?.prefixes?.length ?? 0) > 0 || (userConfig.assets?.manifests?.length ?? 0) > 0;
2392
3003
  const isContainer = (entrypoint) => entrypoint.runtime === CONTAINER_RUNTIME;
2393
3004
  const userFileFunctions = userConfig.entrypoints.filter((entrypoint) => !isContainer(entrypoint));
@@ -2428,23 +3039,23 @@ var filterFunctionsFromAssets = (config) => {
2428
3039
  };
2429
3040
 
2430
3041
  // src/parse-config.ts
2431
- var import_effect25 = require("effect");
3042
+ var import_effect31 = require("effect");
2432
3043
 
2433
3044
  // src/services/raw-config-reader.ts
2434
- var import_platform13 = require("@effect/platform");
2435
- var import_effect21 = require("effect");
3045
+ var import_platform17 = require("@effect/platform");
3046
+ var import_effect27 = require("effect");
2436
3047
  var import_yaml2 = require("yaml");
2437
3048
 
2438
3049
  // src/services/config-module-loader.ts
2439
- var import_effect20 = require("effect");
3050
+ var import_effect26 = require("effect");
2440
3051
  var import_jiti = require("jiti");
2441
3052
  var MISSING_DEFAULT_EXPORT = /* @__PURE__ */ Symbol("MissingDefaultExport");
2442
3053
  var STRICT_DEFAULT_EXPORT_EXTENSIONS = [".ts", ".mts", ".mjs"];
2443
- var ConfigModuleLoader = class extends import_effect20.Effect.Service()("ConfigModuleLoader", {
2444
- effect: import_effect20.Effect.gen(function* () {
2445
- const loadConfigModule = import_effect20.Effect.fn("ConfigModuleLoader.loadConfigModule")(function* (filePath) {
3054
+ var ConfigModuleLoader = class extends import_effect26.Effect.Service()("ConfigModuleLoader", {
3055
+ effect: import_effect26.Effect.gen(function* () {
3056
+ const loadConfigModule = import_effect26.Effect.fn("ConfigModuleLoader.loadConfigModule")(function* (filePath) {
2446
3057
  const extension = filePath.slice(filePath.lastIndexOf(".")).toLowerCase();
2447
- const mod = yield* import_effect20.Effect.tryPromise({
3058
+ const mod = yield* import_effect26.Effect.tryPromise({
2448
3059
  try: async () => {
2449
3060
  const jiti = (0, import_jiti.createJiti)(filePath, { fsCache: false, interopDefault: true, moduleCache: false });
2450
3061
  const namespace = await jiti.import(filePath);
@@ -2463,7 +3074,7 @@ var ConfigModuleLoader = class extends import_effect20.Effect.Service()("ConfigM
2463
3074
  })
2464
3075
  });
2465
3076
  if (mod === MISSING_DEFAULT_EXPORT) {
2466
- return yield* import_effect20.Effect.fail(
3077
+ return yield* import_effect26.Effect.fail(
2467
3078
  new ConfigModuleLoadError({
2468
3079
  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.`,
2469
3080
  filePath
@@ -2471,7 +3082,7 @@ var ConfigModuleLoader = class extends import_effect20.Effect.Service()("ConfigM
2471
3082
  );
2472
3083
  }
2473
3084
  if (typeof mod === "function") {
2474
- return yield* import_effect20.Effect.fail(
3085
+ return yield* import_effect26.Effect.fail(
2475
3086
  new ConfigModuleLoadError({
2476
3087
  message: `Config module at ${filePath} default-exports a function; config factories are not supported. Export a config object instead (optionally wrapped in defineConfig).`,
2477
3088
  filePath
@@ -2479,7 +3090,7 @@ var ConfigModuleLoader = class extends import_effect20.Effect.Service()("ConfigM
2479
3090
  );
2480
3091
  }
2481
3092
  if (typeof mod !== "object" || mod === null || Array.isArray(mod)) {
2482
- return yield* import_effect20.Effect.fail(
3093
+ return yield* import_effect26.Effect.fail(
2483
3094
  new ConfigModuleLoadError({
2484
3095
  message: `Config module at ${filePath} must default-export a config object.`,
2485
3096
  filePath
@@ -2509,36 +3120,36 @@ var ALLOWED_CONFIG_NAMES = [
2509
3120
  "nebula.json"
2510
3121
  ];
2511
3122
  var MODULE_EXTENSIONS = [".ts", ".mts", ".cts", ".js", ".mjs", ".cjs"];
2512
- var RawConfigReader = class extends import_effect21.Effect.Service()("RawConfigReader", {
3123
+ var RawConfigReader = class extends import_effect27.Effect.Service()("RawConfigReader", {
2513
3124
  dependencies: [ConfigModuleLoader.Default],
2514
- effect: import_effect21.Effect.gen(function* () {
2515
- const fs = yield* import_platform13.FileSystem.FileSystem;
2516
- const pathService = yield* import_platform13.Path.Path;
3125
+ effect: import_effect27.Effect.gen(function* () {
3126
+ const fs = yield* import_platform17.FileSystem.FileSystem;
3127
+ const pathService = yield* import_platform17.Path.Path;
2517
3128
  const moduleLoader = yield* ConfigModuleLoader;
2518
- const findConfig = import_effect21.Effect.fn("RawConfigReader.findConfig")(function* (projectFolder) {
3129
+ const findConfig = import_effect27.Effect.fn("RawConfigReader.findConfig")(function* (projectFolder) {
2519
3130
  for (const name of ALLOWED_CONFIG_NAMES) {
2520
3131
  const filePath = pathService.join(projectFolder, name);
2521
- const exists = yield* fs.exists(filePath).pipe(import_effect21.Effect.catchAll(() => import_effect21.Effect.succeed(false)));
3132
+ const exists = yield* fs.exists(filePath).pipe(import_effect27.Effect.catchAll(() => import_effect27.Effect.succeed(false)));
2522
3133
  if (exists) {
2523
3134
  return filePath;
2524
3135
  }
2525
3136
  }
2526
3137
  return null;
2527
3138
  });
2528
- const readRawConfig = import_effect21.Effect.fn("RawConfigReader.readRawConfig")(function* (filePath, options) {
2529
- const exists = yield* fs.exists(filePath).pipe(import_effect21.Effect.catchAll(() => import_effect21.Effect.succeed(false)));
3139
+ const readRawConfig = import_effect27.Effect.fn("RawConfigReader.readRawConfig")(function* (filePath, options) {
3140
+ const exists = yield* fs.exists(filePath).pipe(import_effect27.Effect.catchAll(() => import_effect27.Effect.succeed(false)));
2530
3141
  if (!exists) {
2531
- return yield* import_effect21.Effect.fail(
3142
+ return yield* import_effect27.Effect.fail(
2532
3143
  new ConfigFileNotFoundError({ message: `Config file not found at ${filePath}`, filePath })
2533
3144
  );
2534
3145
  }
2535
3146
  const fileContents = yield* fs.readFileString(filePath).pipe(
2536
- import_effect21.Effect.mapError(
3147
+ import_effect27.Effect.mapError(
2537
3148
  () => new ConfigFileParseError({ message: `Failed to read config file at ${filePath}`, filePath })
2538
3149
  )
2539
3150
  );
2540
3151
  if (fileContents.length === 0) {
2541
- return yield* import_effect21.Effect.fail(
3152
+ return yield* import_effect27.Effect.fail(
2542
3153
  new ConfigFileEmptyError({ message: `Config file is empty at ${filePath}`, filePath })
2543
3154
  );
2544
3155
  }
@@ -2554,7 +3165,7 @@ var RawConfigReader = class extends import_effect21.Effect.Service()("RawConfigR
2554
3165
  parsed = (0, import_yaml2.parse)(fileContents);
2555
3166
  }
2556
3167
  } catch (error) {
2557
- return yield* import_effect21.Effect.fail(
3168
+ return yield* import_effect27.Effect.fail(
2558
3169
  new ConfigFileParseError({
2559
3170
  message: `Failed to parse config file at ${filePath}: ${error instanceof Error ? error.message : "Unknown error"}`,
2560
3171
  filePath,
@@ -2564,21 +3175,21 @@ var RawConfigReader = class extends import_effect21.Effect.Service()("RawConfigR
2564
3175
  }
2565
3176
  }
2566
3177
  if (parsed == null) {
2567
- return yield* import_effect21.Effect.fail(
3178
+ return yield* import_effect27.Effect.fail(
2568
3179
  new ConfigFileParseError({ message: `Config file could not be parsed at ${filePath}`, filePath })
2569
3180
  );
2570
3181
  }
2571
3182
  if (!options?.disableVersionCheck && typeof parsed.version !== "number") {
2572
- return yield* import_effect21.Effect.fail(
3183
+ return yield* import_effect27.Effect.fail(
2573
3184
  new ConfigVersionError({ message: `Config file is missing version at ${filePath}`, filePath })
2574
3185
  );
2575
3186
  }
2576
3187
  return parsed;
2577
3188
  });
2578
3189
  const readConfigFile = (configFilePath) => readRawConfig(configFilePath, { disableVersionCheck: true }).pipe(
2579
- import_effect21.Effect.map((parsed) => parsed),
2580
- import_effect21.Effect.catchTag("ConfigFileNotFoundError", () => import_effect21.Effect.succeed(null)),
2581
- import_effect21.Effect.withSpan("RawConfigReader.readConfigFile")
3190
+ import_effect27.Effect.map((parsed) => parsed),
3191
+ import_effect27.Effect.catchTag("ConfigFileNotFoundError", () => import_effect27.Effect.succeed(null)),
3192
+ import_effect27.Effect.withSpan("RawConfigReader.readConfigFile")
2582
3193
  );
2583
3194
  return { findConfig, readRawConfig, readConfigFile };
2584
3195
  })
@@ -2588,17 +3199,17 @@ var RawConfigReader = class extends import_effect21.Effect.Service()("RawConfigR
2588
3199
  // src/services/schema-validator.ts
2589
3200
  var import_ajv = __toESM(require("ajv"));
2590
3201
  var import_ajv_formats = __toESM(require("ajv-formats"));
2591
- var import_effect22 = require("effect");
2592
- var SchemaValidator = class extends import_effect22.Effect.Service()("SchemaValidator", {
2593
- effect: import_effect22.Effect.gen(function* () {
3202
+ var import_effect28 = require("effect");
3203
+ var SchemaValidator = class extends import_effect28.Effect.Service()("SchemaValidator", {
3204
+ effect: import_effect28.Effect.gen(function* () {
2594
3205
  const ajv = new import_ajv.default();
2595
3206
  (0, import_ajv_formats.default)(ajv);
2596
- const validate = import_effect22.Effect.fn("SchemaValidator.validate")(function* (config, schema, filePath) {
3207
+ const validate = import_effect28.Effect.fn("SchemaValidator.validate")(function* (config, schema, filePath) {
2597
3208
  const compiledValidate = ajv.compile(schema);
2598
3209
  const valid = compiledValidate(config);
2599
3210
  if (!valid) {
2600
3211
  const errors = compiledValidate.errors?.map((e) => `${e.instancePath || "/"} ${e.message ?? ""}`.trim()) ?? [];
2601
- return yield* import_effect22.Effect.fail(
3212
+ return yield* import_effect28.Effect.fail(
2602
3213
  new ConfigSchemaValidationError({
2603
3214
  message: `Config file at ${filePath} is invalid: ${ajv.errorsText(compiledValidate.errors)}`,
2604
3215
  filePath,
@@ -2654,7 +3265,7 @@ var getFilesForPattern = async (pattern, projectFolder, excludeFiles = []) => {
2654
3265
  };
2655
3266
 
2656
3267
  // src/services/v4-config-parser.ts
2657
- var import_effect23 = require("effect");
3268
+ var import_effect29 = require("effect");
2658
3269
  var import_minimatch2 = require("minimatch");
2659
3270
  var import_node_path2 = require("path");
2660
3271
  var import_safe_regex2 = __toESM(require("safe-regex2"));
@@ -2670,7 +3281,7 @@ var toArray = (value) => {
2670
3281
  if (value == null) return void 0;
2671
3282
  return Array.isArray(value) ? value : [value];
2672
3283
  };
2673
- var runtimeStreamsByDefault = (runtime) => runtime == null || runtime.startsWith("node-") || runtime.startsWith("bun-");
3284
+ var runtimeStreamsByDefault = (runtime) => runtime == null || runtime.startsWith("node-") || runtime.startsWith("bun-") || runtime.startsWith("ruby-");
2674
3285
  var normalizeImagePolicy = (images) => {
2675
3286
  if (!images) return void 0;
2676
3287
  return {
@@ -2805,7 +3416,7 @@ var mapRoute = (route, entrypoints) => ({
2805
3416
  negativeRequirements: route.missing,
2806
3417
  status: route.statusCode
2807
3418
  });
2808
- var parseEntrypoints = import_effect23.Effect.fn("parseEntrypoints")(function* (config, projectFolder) {
3419
+ var parseEntrypoints = import_effect29.Effect.fn("parseEntrypoints")(function* (config, projectFolder) {
2809
3420
  const entrypoints = [];
2810
3421
  const dockerFunctions = [];
2811
3422
  if (config.functions == null) return { entrypoints, dockerFunctions };
@@ -2816,7 +3427,7 @@ var parseEntrypoints = import_effect23.Effect.fn("parseEntrypoints")(function* (
2816
3427
  functionPath: fnPath
2817
3428
  });
2818
3429
  }
2819
- const matchedFiles = yield* import_effect23.Effect.tryPromise({
3430
+ const matchedFiles = yield* import_effect29.Effect.tryPromise({
2820
3431
  try: () => getFilesForPattern(fnPath, projectFolder, func.excludeFiles),
2821
3432
  catch: (error) => new FunctionConfigError({
2822
3433
  message: `Failed to resolve files for function pattern '${fnPath}': ${error instanceof Error ? error.message : String(error)}`,
@@ -2891,13 +3502,13 @@ var parseEntrypoints = import_effect23.Effect.fn("parseEntrypoints")(function* (
2891
3502
  }
2892
3503
  return { entrypoints, dockerFunctions };
2893
3504
  });
2894
- var collectAssets = import_effect23.Effect.fn("collectAssets")(function* (config, projectFolder) {
3505
+ var collectAssets = import_effect29.Effect.fn("collectAssets")(function* (config, projectFolder) {
2895
3506
  if (config.assets == null) return [];
2896
3507
  const assetNames = yield* collectAssetFiles(projectFolder, config.assets);
2897
3508
  return assetNames.filter((assetName) => getFunctionSettings(`${config.assets}/${assetName}`, config) == null).map((assetName) => `${config.assets}/${assetName}`);
2898
3509
  });
2899
3510
  var reservedRuntimePorts = (entrypoint) => entrypoint.runtime === CONTAINER_RUNTIME ? [] : entrypoint.runtime.startsWith("php-") ? [8080, 9e3] : [8080];
2900
- var parseContainers = import_effect23.Effect.fn("parseContainers")(function* (config, projectFolder, fileEntrypoints, dockerFunctions) {
3511
+ var parseContainers = import_effect29.Effect.fn("parseContainers")(function* (config, projectFolder, fileEntrypoints, dockerFunctions) {
2901
3512
  const warnings = [];
2902
3513
  let containers = {};
2903
3514
  if (config.compose != null) {
@@ -2930,16 +3541,16 @@ var parseContainers = import_effect23.Effect.fn("parseContainers")(function* (co
2930
3541
  }
2931
3542
  return { ...result, warnings };
2932
3543
  });
2933
- var V4ConfigParser = class extends import_effect23.Effect.Service()("V4ConfigParser", {
3544
+ var V4ConfigParser = class extends import_effect29.Effect.Service()("V4ConfigParser", {
2934
3545
  accessors: true,
2935
- effect: import_effect23.Effect.succeed({
3546
+ effect: import_effect29.Effect.succeed({
2936
3547
  /**
2937
3548
  * Parses a ConfigV4 into a NormalizedConfig.
2938
3549
  *
2939
3550
  * @param config - The raw V4 config object
2940
3551
  * @param projectFolder - Absolute path to the project root
2941
3552
  */
2942
- parse: import_effect23.Effect.fn("V4ConfigParser.parse")(function* (config, projectFolder) {
3553
+ parse: import_effect29.Effect.fn("V4ConfigParser.parse")(function* (config, projectFolder) {
2943
3554
  const { entrypoints: fileEntrypoints, dockerFunctions } = yield* parseEntrypoints(config, projectFolder);
2944
3555
  const containers = yield* parseContainers(config, projectFolder, fileEntrypoints, dockerFunctions);
2945
3556
  const entrypoints = [...fileEntrypoints, ...containers.entrypoints];
@@ -2981,7 +3592,7 @@ var V4ConfigParser = class extends import_effect23.Effect.Service()("V4ConfigPar
2981
3592
  };
2982
3593
 
2983
3594
  // src/services/vercel-build-output-parser.ts
2984
- var import_platform14 = require("@effect/platform");
3595
+ var import_platform18 = require("@effect/platform");
2985
3596
 
2986
3597
  // ../commons/src/deep-merge.ts
2987
3598
  var deepMerge = (target, ...partials) => {
@@ -3010,7 +3621,7 @@ var deepMerge = (target, ...partials) => {
3010
3621
  };
3011
3622
 
3012
3623
  // src/services/vercel-build-output-parser.ts
3013
- var import_effect24 = require("effect");
3624
+ var import_effect30 = require("effect");
3014
3625
 
3015
3626
  // src/build-output-v3/determine-repo-root.ts
3016
3627
  var import_path = __toESM(require("path"));
@@ -3106,11 +3717,11 @@ var translateVercelRuntime = (runtime) => {
3106
3717
  var CONFIG_PATH = ".vercel/output/config.json";
3107
3718
  var FUNCTIONS_FOLDER = ".vercel/output/functions";
3108
3719
  var FUNCTION_CONFIGS_PATTERN = `${FUNCTIONS_FOLDER}/**/*.func/.vc-config.json`;
3109
- var VercelBuildOutputParser = class extends import_effect24.Effect.Service()("VercelBuildOutputParser", {
3110
- effect: import_effect24.Effect.gen(function* () {
3720
+ var VercelBuildOutputParser = class extends import_effect30.Effect.Service()("VercelBuildOutputParser", {
3721
+ effect: import_effect30.Effect.gen(function* () {
3111
3722
  const rawConfigReader = yield* RawConfigReader;
3112
- const pathService = yield* import_platform14.Path.Path;
3113
- const parse = import_effect24.Effect.fn("VercelBuildOutputParser.parse")(function* (parseResult, projectFolder) {
3723
+ const pathService = yield* import_platform18.Path.Path;
3724
+ const parse = import_effect30.Effect.fn("VercelBuildOutputParser.parse")(function* (parseResult, projectFolder) {
3114
3725
  const config = yield* rawConfigReader.readConfigFile(pathService.join(projectFolder, CONFIG_PATH));
3115
3726
  if (!config || typeof config.version !== "number" || config.version < 3) {
3116
3727
  return parseResult;
@@ -3122,8 +3733,8 @@ var VercelBuildOutputParser = class extends import_effect24.Effect.Service()("Ve
3122
3733
  merged.regions = [...new Set(merged.regions)];
3123
3734
  return merged;
3124
3735
  });
3125
- const loadFunctions = import_effect24.Effect.fn("VercelBuildOutputParser.loadFunctions")(function* (config, parseResult, projectFolder) {
3126
- const functionConfigs = yield* import_effect24.Effect.tryPromise({
3736
+ const loadFunctions = import_effect30.Effect.fn("VercelBuildOutputParser.loadFunctions")(function* (config, parseResult, projectFolder) {
3737
+ const functionConfigs = yield* import_effect30.Effect.tryPromise({
3127
3738
  try: () => getFilesForPattern(FUNCTION_CONFIGS_PATTERN, projectFolder),
3128
3739
  catch: (error) => new ConfigFileParseError({
3129
3740
  message: `Failed to scan for function configs: ${error instanceof Error ? error.message : String(error)}`,
@@ -3420,7 +4031,7 @@ var schema_default = {
3420
4031
  },
3421
4032
  streaming: {
3422
4033
  type: "boolean",
3423
- description: "Enable function response streaming. When omitted, Node and Bun runtimes stream by default."
4034
+ description: "Enable function response streaming. When omitted, Node, Bun and Ruby runtimes stream by default."
3424
4035
  },
3425
4036
  schedule: {
3426
4037
  $ref: "#/$defs/schedule",
@@ -3986,7 +4597,19 @@ var schema_default = {
3986
4597
  },
3987
4598
  runtimes: {
3988
4599
  type: "string",
3989
- enum: ["php-84", "php-83", "php-81", "node-22", "node-20", "node-18", "node-16", "bun-1"]
4600
+ enum: [
4601
+ "php-84",
4602
+ "php-83",
4603
+ "php-81",
4604
+ "ruby-40",
4605
+ "ruby-34",
4606
+ "ruby-33",
4607
+ "node-22",
4608
+ "node-20",
4609
+ "node-18",
4610
+ "node-16",
4611
+ "bun-1"
4612
+ ]
3990
4613
  },
3991
4614
  matchRequirements: {
3992
4615
  description: "An array of requirements that are needed to match",
@@ -4040,7 +4663,7 @@ var schema_default = {
4040
4663
  };
4041
4664
 
4042
4665
  // src/parse-config.ts
4043
- var parseConfigRaw = import_effect25.Effect.fn("parseConfigRaw")(function* (filePath, projectFolder) {
4666
+ var parseConfigRaw = import_effect31.Effect.fn("parseConfigRaw")(function* (filePath, projectFolder) {
4044
4667
  const rawReader = yield* RawConfigReader;
4045
4668
  const validator = yield* SchemaValidator;
4046
4669
  const v4Parser = yield* V4ConfigParser;
@@ -4051,7 +4674,7 @@ var parseConfigRaw = import_effect25.Effect.fn("parseConfigRaw")(function* (file
4051
4674
  };
4052
4675
  const schema = schemaMap[version];
4053
4676
  if (!schema) {
4054
- return yield* import_effect25.Effect.fail(
4677
+ return yield* import_effect31.Effect.fail(
4055
4678
  new ConfigVersionError({
4056
4679
  message: `Config file at ${filePath} has an unsupported version: ${version}`,
4057
4680
  filePath,
@@ -4062,11 +4685,11 @@ var parseConfigRaw = import_effect25.Effect.fn("parseConfigRaw")(function* (file
4062
4685
  yield* validator.validate(parsed, schema, filePath);
4063
4686
  return yield* v4Parser.parse(parsed, projectFolder);
4064
4687
  });
4065
- var parseConfig = import_effect25.Effect.fn("parseConfig")(function* (filePath, projectFolder) {
4688
+ var parseConfig = import_effect31.Effect.fn("parseConfig")(function* (filePath, projectFolder) {
4066
4689
  const parseResult = yield* parseConfigRaw(filePath, projectFolder);
4067
4690
  return yield* postProcessConfig(parseResult, projectFolder);
4068
4691
  });
4069
- var postProcessConfig = import_effect25.Effect.fn("postProcessConfig")(function* (config, projectFolder) {
4692
+ var postProcessConfig = import_effect31.Effect.fn("postProcessConfig")(function* (config, projectFolder) {
4070
4693
  const vercelParser = yield* VercelBuildOutputParser;
4071
4694
  let result = yield* vercelParser.parse(config, projectFolder);
4072
4695
  const hasAssets = (result.assets?.paths?.length ?? 0) > 0 || (result.assets?.prefixes?.length ?? 0) > 0 || (result.assets?.manifests?.length ?? 0) > 0;
@@ -4114,6 +4737,9 @@ var RUNTIME_DEFINITIONS = [
4114
4737
  "php-84",
4115
4738
  "php-83",
4116
4739
  "php-81",
4740
+ "ruby-40",
4741
+ "ruby-34",
4742
+ "ruby-33",
4117
4743
  "node-22",
4118
4744
  "node-20",
4119
4745
  "node-18",
@@ -4123,14 +4749,14 @@ var RUNTIME_DEFINITIONS = [
4123
4749
  var AVAILABLE_RUNTIMES = [...RUNTIME_DEFINITIONS];
4124
4750
 
4125
4751
  // src/services/index.ts
4126
- var import_effect26 = require("effect");
4127
- var BaseLayers = import_effect26.Layer.mergeAll(
4752
+ var import_effect32 = require("effect");
4753
+ var BaseLayers = import_effect32.Layer.mergeAll(
4128
4754
  ConfigModuleLoader.Default,
4129
4755
  RawConfigReader.Default,
4130
4756
  SchemaValidator.Default,
4131
4757
  V4ConfigParser.Default
4132
4758
  );
4133
- var NetworkConfigLive = VercelBuildOutputParser.Default.pipe(import_effect26.Layer.provideMerge(BaseLayers));
4759
+ var NetworkConfigLive = VercelBuildOutputParser.Default.pipe(import_effect32.Layer.provideMerge(BaseLayers));
4134
4760
  // Annotate the CommonJS export names for ESM import in node:
4135
4761
  0 && (module.exports = {
4136
4762
  ALLOWED_CONFIG_NAMES,
@@ -4149,6 +4775,7 @@ var NetworkConfigLive = VercelBuildOutputParser.Default.pipe(import_effect26.Lay
4149
4775
  ContainerConfigError,
4150
4776
  DEFAULT_CONTAINER_MEMORY_MB,
4151
4777
  DEFAULT_FUNCTION_DURATION_SECONDS,
4778
+ DEFAULT_RUBY_RUNTIME,
4152
4779
  DEFAULT_SIDECAR_MEMORY_MB,
4153
4780
  FRAMEWORK_DEFINITIONS,
4154
4781
  FrameworkNotDetectedError,
@@ -4185,6 +4812,7 @@ var NetworkConfigLive = VercelBuildOutputParser.Default.pipe(import_effect26.Lay
4185
4812
  detectContainerProject,
4186
4813
  detectFramework,
4187
4814
  detectPackageManager,
4815
+ detectRubyRuntime,
4188
4816
  dockerFunctionContainerName,
4189
4817
  filterFunctionsFromAssets,
4190
4818
  generateConfig,
@@ -4200,6 +4828,9 @@ var NetworkConfigLive = VercelBuildOutputParser.Default.pipe(import_effect26.Lay
4200
4828
  postProcessConfig,
4201
4829
  readComposeContainers,
4202
4830
  readDependencies,
4831
+ rubyRuntimeForRequirement,
4832
+ rubyRuntimeForVersion,
4833
+ rubyRuntimeFromProjectFiles,
4203
4834
  splitCommandWords
4204
4835
  });
4205
4836
  //# sourceMappingURL=index.js.map