@vercel/fs-detectors 6.15.10 → 7.0.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/detect-builders.d.ts +2 -9
- package/dist/detect-builders.js +3 -47
- package/dist/index.d.ts +1 -9
- package/dist/index.js +2 -40
- package/package.json +4 -6
- package/dist/services/auto-detect.d.ts +0 -46
- package/dist/services/auto-detect.js +0 -268
- package/dist/services/detect-procfile.d.ts +0 -22
- package/dist/services/detect-procfile.js +0 -249
- package/dist/services/detect-railway.d.ts +0 -22
- package/dist/services/detect-railway.js +0 -241
- package/dist/services/detect-render.d.ts +0 -14
- package/dist/services/detect-render.js +0 -230
- package/dist/services/detect-services.d.ts +0 -48
- package/dist/services/detect-services.js +0 -423
- package/dist/services/get-services-builders.d.ts +0 -43
- package/dist/services/get-services-builders.js +0 -161
- package/dist/services/resolve-v2.d.ts +0 -11
- package/dist/services/resolve-v2.js +0 -395
- package/dist/services/resolve.d.ts +0 -69
- package/dist/services/resolve.js +0 -914
- package/dist/services/types.d.ts +0 -134
- package/dist/services/types.js +0 -77
- package/dist/services/utils.d.ts +0 -95
- package/dist/services/utils.js +0 -265
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var detect_procfile_exports = {};
|
|
20
|
-
__export(detect_procfile_exports, {
|
|
21
|
-
detectProcfileServices: () => detectProcfileServices
|
|
22
|
-
});
|
|
23
|
-
module.exports = __toCommonJS(detect_procfile_exports);
|
|
24
|
-
var import_detect_framework = require("../detect-framework");
|
|
25
|
-
var import_utils = require("./utils");
|
|
26
|
-
const PROCFILE = "Procfile";
|
|
27
|
-
const PROCFILE_LINE_RE = /^\s*([A-Za-z_][A-Za-z0-9_-]*):\s*(.+)/;
|
|
28
|
-
const PY_IDENT = "[A-Za-z_][A-Za-z0-9_]*";
|
|
29
|
-
const PY_MODULE_RE = new RegExp(
|
|
30
|
-
`^${PY_IDENT}(?:\\.${PY_IDENT})*(?::${PY_IDENT})?$`
|
|
31
|
-
);
|
|
32
|
-
const SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
33
|
-
".js",
|
|
34
|
-
".cjs",
|
|
35
|
-
".mjs",
|
|
36
|
-
".ts",
|
|
37
|
-
".cts",
|
|
38
|
-
".mts",
|
|
39
|
-
".py",
|
|
40
|
-
".go",
|
|
41
|
-
".rs",
|
|
42
|
-
".rb",
|
|
43
|
-
".ru"
|
|
44
|
-
]);
|
|
45
|
-
const SUPPORTED_WORKER_COMMANDS = /* @__PURE__ */ new Set(["celery", "dramatiq"]);
|
|
46
|
-
async function detectProcfileServices(options) {
|
|
47
|
-
const { fs } = options;
|
|
48
|
-
const raw = await readProcfile(fs);
|
|
49
|
-
if (raw.warning) {
|
|
50
|
-
return { services: null, errors: [], warnings: [raw.warning] };
|
|
51
|
-
}
|
|
52
|
-
if (!raw.content) {
|
|
53
|
-
return { services: null, errors: [], warnings: [] };
|
|
54
|
-
}
|
|
55
|
-
const entries = parseProcfile(raw.content);
|
|
56
|
-
if (entries.length === 0) {
|
|
57
|
-
return { services: null, errors: [], warnings: [] };
|
|
58
|
-
}
|
|
59
|
-
const services = {};
|
|
60
|
-
const errors = [];
|
|
61
|
-
const warnings = [];
|
|
62
|
-
let releaseCommand;
|
|
63
|
-
const serviceEntries = [];
|
|
64
|
-
for (const entry of entries) {
|
|
65
|
-
if (entry.processType === "release") {
|
|
66
|
-
releaseCommand = entry.command;
|
|
67
|
-
} else {
|
|
68
|
-
serviceEntries.push(entry);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (serviceEntries.length === 0 && releaseCommand) {
|
|
72
|
-
warnings.push({
|
|
73
|
-
code: "PROCFILE_RELEASE_ONLY",
|
|
74
|
-
message: `Found only a release process in Procfile (command: "${releaseCommand}"). The release command can be used as a build step. You can add it as part of a web service if you add it to "buildCommand".`
|
|
75
|
-
});
|
|
76
|
-
return { services: null, errors: [], warnings };
|
|
77
|
-
}
|
|
78
|
-
if (serviceEntries.length === 0) {
|
|
79
|
-
return { services: null, errors: [], warnings: [] };
|
|
80
|
-
}
|
|
81
|
-
const frameworks = await (0, import_detect_framework.detectFrameworks)({
|
|
82
|
-
fs,
|
|
83
|
-
frameworkList: import_utils.DETECTION_FRAMEWORKS,
|
|
84
|
-
useExperimentalFrameworks: true
|
|
85
|
-
});
|
|
86
|
-
if (frameworks.length > 1) {
|
|
87
|
-
const names = frameworks.map((f) => f.name).join(", ");
|
|
88
|
-
return {
|
|
89
|
-
services: null,
|
|
90
|
-
errors: [
|
|
91
|
-
{
|
|
92
|
-
code: "MULTIPLE_FRAMEWORKS_SERVICE",
|
|
93
|
-
message: `Multiple frameworks detected: ${names}. Use explicit services config.`
|
|
94
|
-
}
|
|
95
|
-
],
|
|
96
|
-
warnings
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
const detectedFramework = frameworks.length === 1 ? frameworks[0] : null;
|
|
100
|
-
const serviceNames = /* @__PURE__ */ new Set();
|
|
101
|
-
for (const entry of serviceEntries) {
|
|
102
|
-
const { processType, command } = entry;
|
|
103
|
-
const tokens = command.split(/\s+/).filter(Boolean);
|
|
104
|
-
const entrypoint = await extractEntrypoint(tokens, fs);
|
|
105
|
-
const isWorkerLikeProcess = processType.includes("worker") || hasSupportedWorkerCommand(tokens);
|
|
106
|
-
if (serviceNames.has(processType)) {
|
|
107
|
-
errors.push({
|
|
108
|
-
code: "DUPLICATE_SERVICE",
|
|
109
|
-
message: `Duplicate process type "${processType}" in Procfile.`,
|
|
110
|
-
serviceName: processType
|
|
111
|
-
});
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
serviceNames.add(processType);
|
|
115
|
-
if (isWorkerLikeProcess) {
|
|
116
|
-
if (hasSupportedWorkerCommand(tokens) && entrypoint?.endsWith(".py")) {
|
|
117
|
-
services[processType] = {
|
|
118
|
-
root: ".",
|
|
119
|
-
type: "worker",
|
|
120
|
-
entrypoint,
|
|
121
|
-
runtime: "python"
|
|
122
|
-
};
|
|
123
|
-
} else {
|
|
124
|
-
emitWorkerHint(processType, command, entrypoint, warnings);
|
|
125
|
-
}
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
if (!detectedFramework && !entrypoint) {
|
|
129
|
-
warnings.push({
|
|
130
|
-
code: "SERVICE_SKIPPED",
|
|
131
|
-
message: `Skipped Procfile process "${processType}": no framework detected and could not infer entrypoint from command "${command}". Configure it manually in services.`
|
|
132
|
-
});
|
|
133
|
-
continue;
|
|
134
|
-
}
|
|
135
|
-
services[processType] = {
|
|
136
|
-
root: ".",
|
|
137
|
-
type: "web",
|
|
138
|
-
...detectedFramework?.slug ? { framework: detectedFramework.slug } : {},
|
|
139
|
-
entrypoint: entrypoint ?? "."
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
if (errors.length > 0) {
|
|
143
|
-
return { services: null, errors, warnings };
|
|
144
|
-
}
|
|
145
|
-
if (Object.keys(services).length === 0) {
|
|
146
|
-
return { services: null, errors: [], warnings };
|
|
147
|
-
}
|
|
148
|
-
if (releaseCommand && services.web) {
|
|
149
|
-
services.web.buildCommand = releaseCommand;
|
|
150
|
-
} else if (releaseCommand) {
|
|
151
|
-
const firstService = Object.values(services)[0];
|
|
152
|
-
if (firstService) {
|
|
153
|
-
firstService.buildCommand = releaseCommand;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
warnings.push(...(0, import_utils.assignMountPaths)(services));
|
|
157
|
-
return { services, errors: [], warnings };
|
|
158
|
-
}
|
|
159
|
-
function parseProcfile(content) {
|
|
160
|
-
const entries = [];
|
|
161
|
-
for (const rawLine of content.split("\n")) {
|
|
162
|
-
const match = rawLine.match(PROCFILE_LINE_RE);
|
|
163
|
-
if (match) {
|
|
164
|
-
entries.push({ processType: match[1], command: match[2].trim() });
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
return entries;
|
|
168
|
-
}
|
|
169
|
-
async function extractEntrypoint(tokens, fs) {
|
|
170
|
-
let firstModulePath;
|
|
171
|
-
let lastFilePath;
|
|
172
|
-
for (const token of tokens) {
|
|
173
|
-
if (!firstModulePath && PY_MODULE_RE.test(token)) {
|
|
174
|
-
const resolved = await resolvePythonModule(token, fs);
|
|
175
|
-
if (resolved)
|
|
176
|
-
firstModulePath = resolved;
|
|
177
|
-
}
|
|
178
|
-
if (hasSupportedExtension(token)) {
|
|
179
|
-
lastFilePath = token;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
return firstModulePath ?? lastFilePath;
|
|
183
|
-
}
|
|
184
|
-
async function resolvePythonModule(spec, fs) {
|
|
185
|
-
const [modulePart] = spec.split(":");
|
|
186
|
-
const filePath = `${modulePart.replace(/\./g, "/")}.py`;
|
|
187
|
-
const initPath = `${modulePart.replace(/\./g, "/")}/__init__.py`;
|
|
188
|
-
try {
|
|
189
|
-
if (await fs.isFile(filePath))
|
|
190
|
-
return filePath;
|
|
191
|
-
if (await fs.isFile(initPath))
|
|
192
|
-
return initPath;
|
|
193
|
-
} catch {
|
|
194
|
-
}
|
|
195
|
-
return void 0;
|
|
196
|
-
}
|
|
197
|
-
function hasSupportedExtension(token) {
|
|
198
|
-
const dot = token.lastIndexOf(".");
|
|
199
|
-
return dot > 0 && SUPPORTED_EXTENSIONS.has(token.slice(dot));
|
|
200
|
-
}
|
|
201
|
-
function hasSupportedWorkerCommand(tokens) {
|
|
202
|
-
return tokens.some((t) => SUPPORTED_WORKER_COMMANDS.has(baseCommand(t)));
|
|
203
|
-
}
|
|
204
|
-
function emitWorkerHint(processType, command, entrypoint, warnings) {
|
|
205
|
-
const hint = {
|
|
206
|
-
type: "worker",
|
|
207
|
-
entrypoint: entrypoint ?? "<path-to-handler>",
|
|
208
|
-
runtime: "python"
|
|
209
|
-
};
|
|
210
|
-
if (entrypoint?.endsWith(".py")) {
|
|
211
|
-
warnings.push({
|
|
212
|
-
code: "PROCFILE_WORKER_HINT",
|
|
213
|
-
message: `Found Procfile worker process "${processType}". Python workers that use Celery, Dramatiq and Django tasks are supported. You can add the following to define this worker:
|
|
214
|
-
"${processType}": ${JSON.stringify(hint, null, 2)}`
|
|
215
|
-
});
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
warnings.push({
|
|
219
|
-
code: "PROCFILE_WORKER_HINT",
|
|
220
|
-
message: `Found Procfile worker process "${processType}" (command: "${command}"). Could not determine runtime. Only Python workers are currently supported.`
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
function baseCommand(token) {
|
|
224
|
-
if (!token)
|
|
225
|
-
return "";
|
|
226
|
-
const parts = token.split("/");
|
|
227
|
-
return parts[parts.length - 1];
|
|
228
|
-
}
|
|
229
|
-
async function readProcfile(fs) {
|
|
230
|
-
try {
|
|
231
|
-
const exists = await fs.isFile(PROCFILE);
|
|
232
|
-
if (!exists)
|
|
233
|
-
return { content: null };
|
|
234
|
-
const buf = await fs.readFile(PROCFILE);
|
|
235
|
-
return { content: buf.toString("utf-8") };
|
|
236
|
-
} catch (err) {
|
|
237
|
-
return {
|
|
238
|
-
content: null,
|
|
239
|
-
warning: {
|
|
240
|
-
code: "PROCFILE_READ_ERROR",
|
|
241
|
-
message: `Failed to read ${PROCFILE}: ${err instanceof Error ? err.message : String(err)}`
|
|
242
|
-
}
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
247
|
-
0 && (module.exports = {
|
|
248
|
-
detectProcfileServices
|
|
249
|
-
});
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { DetectEntrypointFn } from '@vercel/build-utils';
|
|
2
|
-
import type { DetectorFilesystem } from '../detectors/filesystem';
|
|
3
|
-
import type { InferredServicesConfig, ServiceDetectionError, ServiceDetectionWarning } from './types';
|
|
4
|
-
export interface RailwayDetectResult {
|
|
5
|
-
services: InferredServicesConfig | null;
|
|
6
|
-
errors: ServiceDetectionError[];
|
|
7
|
-
warnings: ServiceDetectionWarning[];
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Detect Railway service configurations in the project.
|
|
11
|
-
*
|
|
12
|
-
* Scans for railway.{json,toml} files, parses them,
|
|
13
|
-
* tries to detect frameworks in each service directory, and maps to
|
|
14
|
-
* services format.
|
|
15
|
-
*
|
|
16
|
-
* When a Railway config has `deploy.preDeployCommand`, it's added to
|
|
17
|
-
* `buildCommand` since we don't have a separate pre-deploy yet.
|
|
18
|
-
*/
|
|
19
|
-
export declare function detectRailwayServices(options: {
|
|
20
|
-
fs: DetectorFilesystem;
|
|
21
|
-
detectEntrypoint?: DetectEntrypointFn;
|
|
22
|
-
}): Promise<RailwayDetectResult>;
|
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __export = (target, all) => {
|
|
9
|
-
for (var name in all)
|
|
10
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
-
};
|
|
12
|
-
var __copyProps = (to, from, except, desc) => {
|
|
13
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
-
for (let key of __getOwnPropNames(from))
|
|
15
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
-
}
|
|
18
|
-
return to;
|
|
19
|
-
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
-
var detect_railway_exports = {};
|
|
30
|
-
__export(detect_railway_exports, {
|
|
31
|
-
detectRailwayServices: () => detectRailwayServices
|
|
32
|
-
});
|
|
33
|
-
module.exports = __toCommonJS(detect_railway_exports);
|
|
34
|
-
var import_path = require("path");
|
|
35
|
-
var import_smol_toml = __toESM(require("smol-toml"));
|
|
36
|
-
var import_detect_framework = require("../detect-framework");
|
|
37
|
-
var import_utils = require("./utils");
|
|
38
|
-
const RAILWAY_JSON = "railway.json";
|
|
39
|
-
const RAILWAY_TOML = "railway.toml";
|
|
40
|
-
const MAX_SCAN_DEPTH = 5;
|
|
41
|
-
const SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
42
|
-
".hg",
|
|
43
|
-
".git",
|
|
44
|
-
".svn",
|
|
45
|
-
".cache",
|
|
46
|
-
".next",
|
|
47
|
-
".now",
|
|
48
|
-
".vercel",
|
|
49
|
-
".venv",
|
|
50
|
-
".yarn",
|
|
51
|
-
".turbo",
|
|
52
|
-
".output",
|
|
53
|
-
"node_modules",
|
|
54
|
-
"__pycache__",
|
|
55
|
-
"venv",
|
|
56
|
-
"CVS"
|
|
57
|
-
]);
|
|
58
|
-
async function detectRailwayServices(options) {
|
|
59
|
-
const { fs, detectEntrypoint } = options;
|
|
60
|
-
const { configs, warnings } = await findRailwayConfigs(fs);
|
|
61
|
-
if (configs.length === 0) {
|
|
62
|
-
return { services: null, errors: [], warnings };
|
|
63
|
-
}
|
|
64
|
-
const services = {};
|
|
65
|
-
const serviceDirs = /* @__PURE__ */ new Map();
|
|
66
|
-
const errors = [];
|
|
67
|
-
for (const cf of configs) {
|
|
68
|
-
const serviceFs = cf.dirPath === "." ? fs : fs.chdir(cf.dirPath);
|
|
69
|
-
const dirLabel = cf.dirPath === "." ? "root" : cf.dirPath;
|
|
70
|
-
const frameworks = await (0, import_detect_framework.detectFrameworks)({
|
|
71
|
-
fs: serviceFs,
|
|
72
|
-
frameworkList: import_utils.DETECTION_FRAMEWORKS,
|
|
73
|
-
useExperimentalFrameworks: true
|
|
74
|
-
});
|
|
75
|
-
if (cf.config.deploy?.cronSchedule) {
|
|
76
|
-
const schedule = cf.config.deploy.cronSchedule;
|
|
77
|
-
const runtime = frameworks.length === 1 ? (0, import_utils.inferRuntimeFromFramework)(frameworks[0].slug) : void 0;
|
|
78
|
-
const hint = {
|
|
79
|
-
type: "job",
|
|
80
|
-
trigger: "schedule",
|
|
81
|
-
schedule,
|
|
82
|
-
entrypoint: "<path-to-handler>"
|
|
83
|
-
};
|
|
84
|
-
if (runtime) {
|
|
85
|
-
hint.runtime = runtime;
|
|
86
|
-
}
|
|
87
|
-
warnings.push({
|
|
88
|
-
code: "RAILWAY_CRON_HINT",
|
|
89
|
-
message: `Found Railway cron in ${dirLabel}/ (schedule: "${schedule}"). Vercel crons work with a file entrypoint. You can add the following to define this scheduled job service:
|
|
90
|
-
"${deriveServiceName(cf.dirPath)}": ${JSON.stringify(hint, null, 2)}`
|
|
91
|
-
});
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
const serviceName = deriveServiceName(cf.dirPath);
|
|
95
|
-
const existingDir = serviceDirs.get(serviceName);
|
|
96
|
-
if (existingDir) {
|
|
97
|
-
errors.push({
|
|
98
|
-
code: "DUPLICATE_SERVICE",
|
|
99
|
-
message: `Duplicate service name "${serviceName}" derived from ${existingDir}/ and ${dirLabel}/. Rename one of the directories to avoid conflicts.`,
|
|
100
|
-
serviceName
|
|
101
|
-
});
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
serviceDirs.set(serviceName, dirLabel);
|
|
105
|
-
if (frameworks.length === 0) {
|
|
106
|
-
warnings.push({
|
|
107
|
-
code: "SERVICE_SKIPPED",
|
|
108
|
-
message: `Skipped service in ${dirLabel}/: no framework detected. Configure it manually in services.`
|
|
109
|
-
});
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
if (frameworks.length > 1) {
|
|
113
|
-
const names = frameworks.map((f) => f.name).join(", ");
|
|
114
|
-
errors.push({
|
|
115
|
-
code: "MULTIPLE_FRAMEWORKS_SERVICE",
|
|
116
|
-
message: `Multiple frameworks detected in ${dirLabel}/: ${names}. Use explicit services config.`,
|
|
117
|
-
serviceName
|
|
118
|
-
});
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
const framework = frameworks[0];
|
|
122
|
-
const slug = framework.slug ?? void 0;
|
|
123
|
-
const serviceConfig = {
|
|
124
|
-
root: cf.dirPath,
|
|
125
|
-
framework: slug
|
|
126
|
-
};
|
|
127
|
-
if (cf.dirPath !== "." && detectEntrypoint && !(0, import_utils.isFrontendFramework)(slug)) {
|
|
128
|
-
const detected = await detectEntrypoint({
|
|
129
|
-
workPath: cf.dirPath,
|
|
130
|
-
framework: slug
|
|
131
|
-
});
|
|
132
|
-
if (detected) {
|
|
133
|
-
serviceConfig.entrypoint = detected.entrypoint;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
if (cf.config.build?.buildCommand) {
|
|
137
|
-
serviceConfig.buildCommand = cf.config.build.buildCommand;
|
|
138
|
-
}
|
|
139
|
-
const railwayPreDeploy = cf.config.deploy?.preDeployCommand;
|
|
140
|
-
if (railwayPreDeploy) {
|
|
141
|
-
serviceConfig.preDeployCommand = Array.isArray(railwayPreDeploy) ? railwayPreDeploy.join(" && ") : railwayPreDeploy;
|
|
142
|
-
}
|
|
143
|
-
services[serviceName] = serviceConfig;
|
|
144
|
-
}
|
|
145
|
-
if (errors.length > 0) {
|
|
146
|
-
return { services: null, errors, warnings };
|
|
147
|
-
}
|
|
148
|
-
const serviceNames = Object.keys(services);
|
|
149
|
-
if (serviceNames.length === 0) {
|
|
150
|
-
return { services: null, errors: [], warnings };
|
|
151
|
-
}
|
|
152
|
-
warnings.push(...(0, import_utils.assignMountPaths)(services));
|
|
153
|
-
return { services, errors: [], warnings };
|
|
154
|
-
}
|
|
155
|
-
async function findRailwayConfigs(fs, dirPath = ".", depth = 0) {
|
|
156
|
-
const configs = [];
|
|
157
|
-
const warnings = [];
|
|
158
|
-
const readResult = await readRailwayConfigRaw(fs, dirPath);
|
|
159
|
-
warnings.push(...readResult.warnings);
|
|
160
|
-
const { config, warning } = tryParseRailwayConfig(readResult.raw);
|
|
161
|
-
if (warning) {
|
|
162
|
-
warnings.push(warning);
|
|
163
|
-
}
|
|
164
|
-
if (config) {
|
|
165
|
-
configs.push({ dirPath, config });
|
|
166
|
-
}
|
|
167
|
-
if (depth >= MAX_SCAN_DEPTH) {
|
|
168
|
-
return { configs, warnings };
|
|
169
|
-
}
|
|
170
|
-
const readPath = dirPath === "." ? "/" : dirPath;
|
|
171
|
-
let entries;
|
|
172
|
-
try {
|
|
173
|
-
entries = await fs.readdir(readPath);
|
|
174
|
-
} catch {
|
|
175
|
-
return { configs, warnings };
|
|
176
|
-
}
|
|
177
|
-
for (const entry of entries) {
|
|
178
|
-
if (entry.type !== "dir" || SKIP_DIRS.has(entry.name)) {
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
const childPath = dirPath === "." ? entry.name : import_path.posix.join(dirPath, entry.name);
|
|
182
|
-
const child = await findRailwayConfigs(fs, childPath, depth + 1);
|
|
183
|
-
configs.push(...child.configs);
|
|
184
|
-
warnings.push(...child.warnings);
|
|
185
|
-
}
|
|
186
|
-
return { configs, warnings };
|
|
187
|
-
}
|
|
188
|
-
async function readRailwayConfigRaw(fs, dirPath) {
|
|
189
|
-
const warnings = [];
|
|
190
|
-
for (const filename of [RAILWAY_JSON, RAILWAY_TOML]) {
|
|
191
|
-
const filePath = dirPath === "." ? filename : import_path.posix.join(dirPath, filename);
|
|
192
|
-
try {
|
|
193
|
-
const exists = await fs.isFile(filePath);
|
|
194
|
-
if (!exists)
|
|
195
|
-
continue;
|
|
196
|
-
} catch {
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
try {
|
|
200
|
-
const buf = await fs.readFile(filePath);
|
|
201
|
-
return {
|
|
202
|
-
raw: { path: filePath, content: buf.toString("utf-8") },
|
|
203
|
-
warnings
|
|
204
|
-
};
|
|
205
|
-
} catch (err) {
|
|
206
|
-
warnings.push({
|
|
207
|
-
code: "RAILWAY_CONFIG_ERROR",
|
|
208
|
-
message: `Failed to read ${filePath}: ${err instanceof Error ? err.message : String(err)}`
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
return { raw: null, warnings };
|
|
213
|
-
}
|
|
214
|
-
function tryParseRailwayConfig(raw) {
|
|
215
|
-
if (!raw) {
|
|
216
|
-
return { config: null };
|
|
217
|
-
}
|
|
218
|
-
try {
|
|
219
|
-
const config = raw.path.endsWith(".toml") ? import_smol_toml.default.parse(raw.content) : JSON.parse(raw.content);
|
|
220
|
-
return { config };
|
|
221
|
-
} catch (err) {
|
|
222
|
-
return {
|
|
223
|
-
config: null,
|
|
224
|
-
warning: {
|
|
225
|
-
code: "RAILWAY_PARSE_ERROR",
|
|
226
|
-
message: `Failed to parse ${raw.path}: ${err instanceof Error ? err.message : String(err)}`
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
function deriveServiceName(dirPath) {
|
|
232
|
-
if (dirPath === ".") {
|
|
233
|
-
return "web";
|
|
234
|
-
}
|
|
235
|
-
const segments = dirPath.split("/");
|
|
236
|
-
return segments[segments.length - 1];
|
|
237
|
-
}
|
|
238
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
239
|
-
0 && (module.exports = {
|
|
240
|
-
detectRailwayServices
|
|
241
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { DetectorFilesystem } from '../detectors/filesystem';
|
|
2
|
-
import type { DetectEntrypointFn, InferredServicesConfig, ServiceDetectionError, ServiceDetectionWarning } from './types';
|
|
3
|
-
export interface RenderDetectResult {
|
|
4
|
-
services: InferredServicesConfig | null;
|
|
5
|
-
errors: ServiceDetectionError[];
|
|
6
|
-
warnings: ServiceDetectionWarning[];
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Detect Render service configurations from render.yaml.
|
|
10
|
-
*/
|
|
11
|
-
export declare function detectRenderServices(options: {
|
|
12
|
-
fs: DetectorFilesystem;
|
|
13
|
-
detectEntrypoint?: DetectEntrypointFn;
|
|
14
|
-
}): Promise<RenderDetectResult>;
|