@valbuild/cli 0.72.4 → 0.73.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/dist/valbuild-cli-cli.cjs.dev.js +333 -19
- package/cli/dist/valbuild-cli-cli.cjs.prod.js +333 -19
- package/cli/dist/valbuild-cli-cli.esm.js +331 -21
- package/package.json +6 -5
- package/src/cli.ts +13 -1
- package/src/getVersions.ts +4 -4
- package/src/login.ts +112 -0
- package/src/utils/evalValConfigFile.ts +90 -0
- package/src/utils/getFileExt.ts +4 -0
- package/src/utils/getValCoreVersion.ts +5 -0
- package/src/validate.ts +321 -25
@@ -9,6 +9,10 @@ var fastGlob = require('fast-glob');
|
|
9
9
|
var picocolors = require('picocolors');
|
10
10
|
var eslint = require('eslint');
|
11
11
|
var fs = require('fs/promises');
|
12
|
+
var vm = require('node:vm');
|
13
|
+
var ts = require('typescript');
|
14
|
+
var z = require('zod');
|
15
|
+
var fs$1 = require('fs');
|
12
16
|
|
13
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
14
18
|
|
@@ -35,21 +39,95 @@ var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
|
35
39
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
36
40
|
var picocolors__default = /*#__PURE__*/_interopDefault(picocolors);
|
37
41
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
42
|
+
var vm__default = /*#__PURE__*/_interopDefault(vm);
|
43
|
+
var ts__default = /*#__PURE__*/_interopDefault(ts);
|
44
|
+
var z__default = /*#__PURE__*/_interopDefault(z);
|
45
|
+
var fs__default$1 = /*#__PURE__*/_interopDefault(fs$1);
|
38
46
|
|
39
47
|
function error(message) {
|
40
48
|
console.error(chalk__default["default"].red("❌Error: ") + message);
|
41
49
|
}
|
42
50
|
|
51
|
+
const ValConfigSchema = z__default["default"].object({
|
52
|
+
project: z__default["default"].string().optional(),
|
53
|
+
root: z__default["default"].string().optional(),
|
54
|
+
files: z__default["default"].object({
|
55
|
+
directory: z__default["default"].string().refine(val => val.startsWith("/public/val"), {
|
56
|
+
message: "files.directory must start with '/public/val'"
|
57
|
+
})
|
58
|
+
}).optional(),
|
59
|
+
gitCommit: z__default["default"].string().optional(),
|
60
|
+
gitBranch: z__default["default"].string().optional(),
|
61
|
+
defaultTheme: z__default["default"].union([z__default["default"].literal("light"), z__default["default"].literal("dark")]).optional(),
|
62
|
+
ai: z__default["default"].object({
|
63
|
+
commitMessages: z__default["default"].object({
|
64
|
+
disabled: z__default["default"].boolean().optional()
|
65
|
+
}).optional()
|
66
|
+
}).optional()
|
67
|
+
});
|
68
|
+
async function evalValConfigFile(projectRoot, configFileName) {
|
69
|
+
const valConfigPath = path__default["default"].join(projectRoot, configFileName);
|
70
|
+
let code = null;
|
71
|
+
try {
|
72
|
+
code = await fs__default["default"].readFile(valConfigPath, "utf-8");
|
73
|
+
} catch (err) {
|
74
|
+
//
|
75
|
+
}
|
76
|
+
if (!code) {
|
77
|
+
return null;
|
78
|
+
}
|
79
|
+
const transpiled = ts__default["default"].transpileModule(code, {
|
80
|
+
compilerOptions: {
|
81
|
+
target: ts__default["default"].ScriptTarget.ES2020,
|
82
|
+
module: ts__default["default"].ModuleKind.CommonJS,
|
83
|
+
esModuleInterop: true
|
84
|
+
},
|
85
|
+
fileName: valConfigPath
|
86
|
+
});
|
87
|
+
const exportsObj = {};
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
89
|
+
const sandbox = {
|
90
|
+
exports: exportsObj,
|
91
|
+
module: {
|
92
|
+
exports: exportsObj
|
93
|
+
},
|
94
|
+
require,
|
95
|
+
// NOTE: this is a security risk, but this code is running in the users own environment at the CLI level
|
96
|
+
__filename: valConfigPath,
|
97
|
+
__dirname: path__default["default"].dirname(valConfigPath),
|
98
|
+
console,
|
99
|
+
process
|
100
|
+
};
|
101
|
+
sandbox.global = sandbox;
|
102
|
+
const context = vm__default["default"].createContext(sandbox);
|
103
|
+
const script = new vm__default["default"].Script(transpiled.outputText, {
|
104
|
+
filename: valConfigPath
|
105
|
+
});
|
106
|
+
script.runInContext(context);
|
107
|
+
const valConfig = sandbox.module.exports.config;
|
108
|
+
if (!valConfig) {
|
109
|
+
throw Error(`Val config file at path: '${valConfigPath}' must export a config object. Got: ${valConfig}`);
|
110
|
+
}
|
111
|
+
const result = ValConfigSchema.safeParse(valConfig);
|
112
|
+
if (!result.success) {
|
113
|
+
throw Error(`Val config file at path: '${valConfigPath}' has invalid schema: ${result.error.message}`);
|
114
|
+
}
|
115
|
+
return result.data;
|
116
|
+
}
|
117
|
+
|
43
118
|
async function validate({
|
44
119
|
root,
|
45
120
|
fix,
|
46
121
|
noEslint
|
47
122
|
}) {
|
123
|
+
const valRemoteHost = process.env.VAL_REMOTE_HOST || core.DEFAULT_VAL_REMOTE_HOST;
|
48
124
|
const projectRoot = root ? path__default["default"].resolve(root) : process.cwd();
|
49
125
|
const eslint$1 = new eslint.ESLint({
|
50
126
|
cwd: projectRoot,
|
51
127
|
ignore: false
|
52
128
|
});
|
129
|
+
const valConfigFile = (await evalValConfigFile(projectRoot, "val.config.ts")) || (await evalValConfigFile(projectRoot, "val.config.js"));
|
130
|
+
console.log(picocolors__default["default"].greenBright(`Validating project${valConfigFile !== null && valConfigFile !== void 0 && valConfigFile.project ? ` '${picocolors__default["default"].inverse(valConfigFile === null || valConfigFile === void 0 ? void 0 : valConfigFile.project)}'` : ""}...`));
|
53
131
|
const service = await server.createService(projectRoot, {});
|
54
132
|
const checkKeyIsValid = async (key, sourcePath) => {
|
55
133
|
const [moduleFilePath, modulePath] = core.Internal.splitModuleFilePathAndModulePath(sourcePath);
|
@@ -117,7 +195,8 @@ async function validate({
|
|
117
195
|
});
|
118
196
|
console.log(errors === 0 ? picocolors__default["default"].green("✔") : picocolors__default["default"].red("✘"), "ESlint complete", lintFiles.length, "files");
|
119
197
|
}
|
120
|
-
console.log("
|
198
|
+
console.log(picocolors__default["default"].greenBright(`Found ${valFiles.length} files...`));
|
199
|
+
let publicProjectId;
|
121
200
|
let didFix = false; // TODO: ugly
|
122
201
|
async function validateFile(file) {
|
123
202
|
var _eslintResultsByFile;
|
@@ -130,6 +209,9 @@ async function validate({
|
|
130
209
|
});
|
131
210
|
const fileContent = await fs__default["default"].readFile(path__default["default"].join(projectRoot, file), "utf-8");
|
132
211
|
const eslintResult = (_eslintResultsByFile = eslintResultsByFile) === null || _eslintResultsByFile === void 0 ? void 0 : _eslintResultsByFile[file];
|
212
|
+
const remoteFiles = {};
|
213
|
+
let remoteFileBuckets = null;
|
214
|
+
let remoteFilesCounter = 0;
|
133
215
|
eslintResult === null || eslintResult === void 0 || eslintResult.messages.forEach(m => {
|
134
216
|
// display surrounding code
|
135
217
|
logEslintMessage(fileContent, moduleFilePath, m);
|
@@ -140,6 +222,7 @@ async function validate({
|
|
140
222
|
} else {
|
141
223
|
var _eslintResultsByFile2;
|
142
224
|
let errors = ((_eslintResultsByFile2 = eslintResultsByFile) === null || _eslintResultsByFile2 === void 0 || (_eslintResultsByFile2 = _eslintResultsByFile2[file]) === null || _eslintResultsByFile2 === void 0 ? void 0 : _eslintResultsByFile2.messages.reduce((prev, m) => m.severity >= 2 ? prev + 1 : prev, 0)) || 0;
|
225
|
+
let fixedErrors = 0;
|
143
226
|
if (valModule.errors) {
|
144
227
|
if (valModule.errors.validation) {
|
145
228
|
for (const [sourcePath, validationErrors] of Object.entries(valModule.errors.validation)) {
|
@@ -150,20 +233,24 @@ async function validate({
|
|
150
233
|
) || v.fixes.includes("image:check-metadata") || v.fixes.includes("image:add-metadata") || v.fixes.includes("file:check-metadata") || v.fixes.includes("file:add-metadata")) {
|
151
234
|
const [, modulePath] = core.Internal.splitModuleFilePathAndModulePath(sourcePath);
|
152
235
|
if (valModule.source && valModule.schema) {
|
153
|
-
var _fileSource$source;
|
154
236
|
const fileSource = core.Internal.resolvePath(modulePath, valModule.source, valModule.schema);
|
155
|
-
|
156
|
-
(_fileSource$source = fileSource.source) === null || _fileSource$source === void 0 ? void 0 : _fileSource$source[core.FILE_REF_PROP]);
|
237
|
+
let filePath = null;
|
157
238
|
try {
|
239
|
+
var _fileSource$source;
|
240
|
+
filePath = path__default["default"].join(projectRoot, // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
241
|
+
(_fileSource$source = fileSource.source) === null || _fileSource$source === void 0 ? void 0 : _fileSource$source[core.FILE_REF_PROP]);
|
158
242
|
await fs__default["default"].access(filePath);
|
159
243
|
} catch {
|
160
|
-
|
244
|
+
if (filePath) {
|
245
|
+
console.log(picocolors__default["default"].red("✘"), `File ${filePath} does not exist`);
|
246
|
+
} else {
|
247
|
+
console.log(picocolors__default["default"].red("✘"), `Expected file to be defined at: ${sourcePath} but no file was found`);
|
248
|
+
}
|
161
249
|
errors += 1;
|
162
250
|
continue;
|
163
251
|
}
|
164
252
|
}
|
165
253
|
} else if (v.fixes.includes("keyof:check-keys")) {
|
166
|
-
const prevErrors = errors;
|
167
254
|
if (v.value && typeof v.value === "object" && "key" in v.value && "sourcePath" in v.value) {
|
168
255
|
const {
|
169
256
|
key,
|
@@ -186,32 +273,168 @@ async function validate({
|
|
186
273
|
console.log(picocolors__default["default"].red("✘"), "Unexpected error in", `${sourcePath}:`, v.message, " (Expected value to be an object with 'key' and 'sourcePath' properties - this is likely a bug in Val)");
|
187
274
|
errors += 1;
|
188
275
|
}
|
189
|
-
|
190
|
-
|
276
|
+
} else if (v.fixes.includes("image:upload-remote") || v.fixes.includes("file:upload-remote")) {
|
277
|
+
if (!fix) {
|
278
|
+
console.log(picocolors__default["default"].red("✘"), `Remote file ${sourcePath} needs to be uploaded (use --fix to upload)`);
|
279
|
+
errors += 1;
|
280
|
+
continue;
|
281
|
+
}
|
282
|
+
const [, modulePath] = core.Internal.splitModuleFilePathAndModulePath(sourcePath);
|
283
|
+
if (valModule.source && valModule.schema) {
|
284
|
+
const resolvedRemoteFileAtSourcePath = core.Internal.resolvePath(modulePath, valModule.source, valModule.schema);
|
285
|
+
let filePath = null;
|
286
|
+
try {
|
287
|
+
var _resolvedRemoteFileAt;
|
288
|
+
filePath = path__default["default"].join(projectRoot, // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
289
|
+
(_resolvedRemoteFileAt = resolvedRemoteFileAtSourcePath.source) === null || _resolvedRemoteFileAt === void 0 ? void 0 : _resolvedRemoteFileAt[core.FILE_REF_PROP]);
|
290
|
+
await fs__default["default"].access(filePath);
|
291
|
+
} catch {
|
292
|
+
if (filePath) {
|
293
|
+
console.log(picocolors__default["default"].red("✘"), `File ${filePath} does not exist`);
|
294
|
+
} else {
|
295
|
+
console.log(picocolors__default["default"].red("✘"), `Expected file to be defined at: ${sourcePath} but no file was found`);
|
296
|
+
}
|
297
|
+
errors += 1;
|
298
|
+
continue;
|
299
|
+
}
|
300
|
+
const patFile = server.getPersonalAccessTokenPath(projectRoot);
|
301
|
+
try {
|
302
|
+
await fs__default["default"].access(patFile);
|
303
|
+
} catch {
|
304
|
+
// TODO: display this error only once:
|
305
|
+
console.log(picocolors__default["default"].red("✘"), `File: ${path__default["default"].join(projectRoot, file)} has remote images that are not uploaded and you are not logged in.\n\nFix this error by logging in:\n\t"npx val login"\n`);
|
306
|
+
errors += 1;
|
307
|
+
continue;
|
308
|
+
}
|
309
|
+
const parsedPatFile = server.parsePersonalAccessTokenFile(await fs__default["default"].readFile(patFile, "utf-8"));
|
310
|
+
if (!parsedPatFile.success) {
|
311
|
+
console.log(picocolors__default["default"].red("✘"), `Error parsing personal access token file: ${parsedPatFile.error}. You need to login again.`);
|
312
|
+
errors += 1;
|
313
|
+
continue;
|
314
|
+
}
|
315
|
+
const {
|
316
|
+
pat
|
317
|
+
} = parsedPatFile.data;
|
318
|
+
if (remoteFiles[sourcePath]) {
|
319
|
+
console.log(picocolors__default["default"].yellow("⚠"), `Remote file ${filePath} already uploaded`);
|
320
|
+
continue;
|
321
|
+
}
|
322
|
+
// TODO: parallelize this:
|
323
|
+
console.log(picocolors__default["default"].yellow("⚠"), `Uploading remote file ${filePath}...`);
|
324
|
+
if (!resolvedRemoteFileAtSourcePath.schema) {
|
325
|
+
console.log(picocolors__default["default"].red("✘"), `Cannot upload remote file: schema not found for ${sourcePath}`);
|
326
|
+
errors += 1;
|
327
|
+
continue;
|
328
|
+
}
|
329
|
+
const actualRemoteFileSource = resolvedRemoteFileAtSourcePath.source;
|
330
|
+
const fileSourceMetadata = core.Internal.isFile(actualRemoteFileSource) ? actualRemoteFileSource.metadata : undefined;
|
331
|
+
const resolveRemoteFileSchema = resolvedRemoteFileAtSourcePath.schema;
|
332
|
+
if (!resolveRemoteFileSchema) {
|
333
|
+
console.log(picocolors__default["default"].red("✘"), `Could not resolve schema for remote file: ${sourcePath}`);
|
334
|
+
errors += 1;
|
335
|
+
continue;
|
336
|
+
}
|
337
|
+
if (!publicProjectId || !remoteFileBuckets) {
|
338
|
+
let projectName = process.env.VAL_PROJECT;
|
339
|
+
if (!projectName) {
|
340
|
+
projectName = valConfigFile === null || valConfigFile === void 0 ? void 0 : valConfigFile.project;
|
341
|
+
}
|
342
|
+
if (!projectName) {
|
343
|
+
console.log(picocolors__default["default"].red("✘"), "Project name not found. Set VAL_PROJECT environment variable or add project name to val.config");
|
344
|
+
errors += 1;
|
345
|
+
continue;
|
346
|
+
}
|
347
|
+
const settingsRes = await server.getSettings(projectName, {
|
348
|
+
pat
|
349
|
+
});
|
350
|
+
if (!settingsRes.success) {
|
351
|
+
console.log(picocolors__default["default"].red("✘"), `Could not get public project id: ${settingsRes.message}.`);
|
352
|
+
errors += 1;
|
353
|
+
continue;
|
354
|
+
}
|
355
|
+
publicProjectId = settingsRes.data.publicProjectId;
|
356
|
+
remoteFileBuckets = settingsRes.data.remoteFileBuckets.map(b => b.bucket);
|
357
|
+
}
|
358
|
+
if (!publicProjectId) {
|
359
|
+
console.log(picocolors__default["default"].red("✘"), "Could not get public project id");
|
360
|
+
errors += 1;
|
361
|
+
continue;
|
362
|
+
}
|
363
|
+
if (resolveRemoteFileSchema.type !== "image" && resolveRemoteFileSchema.type !== "file") {
|
364
|
+
console.log(picocolors__default["default"].red("✘"), `The schema is the remote is neither image nor file: ${sourcePath}`);
|
365
|
+
}
|
366
|
+
remoteFilesCounter += 1;
|
367
|
+
const bucket = remoteFileBuckets[remoteFilesCounter % remoteFileBuckets.length];
|
368
|
+
if (!bucket) {
|
369
|
+
console.log(picocolors__default["default"].red("✘"), `Internal error: could not allocate a bucket for the remote file located at ${sourcePath}`);
|
370
|
+
errors += 1;
|
371
|
+
continue;
|
372
|
+
}
|
373
|
+
let fileBuffer;
|
374
|
+
try {
|
375
|
+
fileBuffer = await fs__default["default"].readFile(filePath);
|
376
|
+
} catch (e) {
|
377
|
+
console.log(picocolors__default["default"].red("✘"), `Error reading file: ${e}`);
|
378
|
+
errors += 1;
|
379
|
+
continue;
|
380
|
+
}
|
381
|
+
const relativeFilePath = path__default["default"].relative(projectRoot, filePath).split(path__default["default"].sep).join("/");
|
382
|
+
if (!relativeFilePath.startsWith("public/val/")) {
|
383
|
+
console.log(picocolors__default["default"].red("✘"), `File path must be within the public/val/ directory (e.g. public/val/path/to/file.txt). Got: ${relativeFilePath}`);
|
384
|
+
errors += 1;
|
385
|
+
continue;
|
386
|
+
}
|
387
|
+
const remoteFileUpload = await server.uploadRemoteFile(valRemoteHost, fileBuffer, publicProjectId, bucket, relativeFilePath, resolveRemoteFileSchema, fileSourceMetadata, {
|
388
|
+
pat
|
389
|
+
});
|
390
|
+
if (!remoteFileUpload.success) {
|
391
|
+
console.log(picocolors__default["default"].red("✘"), `Error uploading remote file: ${remoteFileUpload.error}`);
|
392
|
+
errors += 1;
|
393
|
+
continue;
|
394
|
+
}
|
395
|
+
console.log(picocolors__default["default"].yellow("⚠"), `Uploaded remote file ${filePath}`);
|
396
|
+
remoteFiles[sourcePath] = {
|
397
|
+
ref: remoteFileUpload.ref,
|
398
|
+
metadata: fileSourceMetadata
|
399
|
+
};
|
400
|
+
}
|
401
|
+
} else if (v.fixes.includes("image:download-remote") || v.fixes.includes("file:download-remote")) {
|
402
|
+
if (fix) {
|
403
|
+
console.log(picocolors__default["default"].yellow("⚠"), `Downloading remote file in ${sourcePath}...`);
|
404
|
+
} else {
|
405
|
+
console.log(picocolors__default["default"].red("✘"), `Remote file ${sourcePath} needs to be downloaded (use --fix to download)`);
|
406
|
+
errors += 1;
|
407
|
+
continue;
|
191
408
|
}
|
192
|
-
} else {
|
193
|
-
console.log(picocolors__default["default"].red("✘"), "
|
409
|
+
} else if (v.fixes.includes("image:check-remote") || v.fixes.includes("file:check-remote")) ; else {
|
410
|
+
console.log(picocolors__default["default"].red("✘"), "Unknown fix", v.fixes, "for", sourcePath);
|
194
411
|
errors += 1;
|
412
|
+
continue;
|
195
413
|
}
|
196
414
|
const fixPatch = await server.createFixPatch({
|
197
|
-
projectRoot
|
198
|
-
|
415
|
+
projectRoot,
|
416
|
+
remoteHost: valRemoteHost
|
417
|
+
}, !!fix, sourcePath, v, remoteFiles, valModule.source, valModule.schema);
|
199
418
|
if (fix && fixPatch !== null && fixPatch !== void 0 && fixPatch.patch && (fixPatch === null || fixPatch === void 0 ? void 0 : fixPatch.patch.length) > 0) {
|
200
419
|
await service.patch(moduleFilePath, fixPatch.patch);
|
201
420
|
didFix = true;
|
421
|
+
fixedErrors += 1;
|
202
422
|
console.log(picocolors__default["default"].yellow("⚠"), "Applied fix for", sourcePath);
|
203
423
|
}
|
204
424
|
fixPatch === null || fixPatch === void 0 || (_fixPatch$remainingEr = fixPatch.remainingErrors) === null || _fixPatch$remainingEr === void 0 || _fixPatch$remainingEr.forEach(e => {
|
205
425
|
errors += 1;
|
206
|
-
console.log(
|
426
|
+
console.log(e.fixes && e.fixes.length ? picocolors__default["default"].yellow("⚠") : picocolors__default["default"].red("✘"), `Got ${e.fixes && e.fixes.length ? "fixable " : ""}error in`, `${sourcePath}:`, e.message);
|
207
427
|
});
|
208
428
|
} else {
|
209
429
|
errors += 1;
|
210
|
-
console.log(picocolors__default["default"].red("✘"), "
|
430
|
+
console.log(picocolors__default["default"].red("✘"), "Got error in", `${sourcePath}:`, v.message);
|
211
431
|
}
|
212
432
|
}
|
213
433
|
}
|
214
434
|
}
|
435
|
+
if (fixedErrors === errors && (!valModule.errors.fatal || valModule.errors.fatal.length == 0)) {
|
436
|
+
console.log(picocolors__default["default"].green("✔"), moduleFilePath, "is valid (" + (Date.now() - start) + "ms)");
|
437
|
+
}
|
215
438
|
for (const fatalError of valModule.errors.fatal || []) {
|
216
439
|
errors += 1;
|
217
440
|
console.log(picocolors__default["default"].red("✘"), moduleFilePath, "is invalid:", fatalError.message);
|
@@ -219,6 +442,9 @@ async function validate({
|
|
219
442
|
} else {
|
220
443
|
console.log(picocolors__default["default"].green("✔"), moduleFilePath, "is valid (" + (Date.now() - start) + "ms)");
|
221
444
|
}
|
445
|
+
if (errors > 0) {
|
446
|
+
console.log(picocolors__default["default"].red("✘"), `${`/${file}`} contains ${errors} error${errors > 1 ? "s" : ""}`, " (" + (Date.now() - start) + "ms)");
|
447
|
+
}
|
222
448
|
return errors;
|
223
449
|
}
|
224
450
|
}
|
@@ -236,7 +462,7 @@ async function validate({
|
|
236
462
|
}
|
237
463
|
}
|
238
464
|
if (errors > 0) {
|
239
|
-
console.log(picocolors__default["default"].red("✘"), "
|
465
|
+
console.log(picocolors__default["default"].red("✘"), "Got", errors, "error" + (errors > 1 ? "s" : ""));
|
240
466
|
process.exit(1);
|
241
467
|
} else {
|
242
468
|
console.log(picocolors__default["default"].green("✔"), "No validation errors found");
|
@@ -362,8 +588,8 @@ function isFileRef(value) {
|
|
362
588
|
return false;
|
363
589
|
}
|
364
590
|
|
365
|
-
const getVersions =
|
366
|
-
const coreVersion =
|
591
|
+
const getVersions = () => {
|
592
|
+
const coreVersion = (() => {
|
367
593
|
try {
|
368
594
|
var _require;
|
369
595
|
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
|
@@ -372,7 +598,7 @@ const getVersions = async () => {
|
|
372
598
|
return null;
|
373
599
|
}
|
374
600
|
})();
|
375
|
-
const nextVersion =
|
601
|
+
const nextVersion = (() => {
|
376
602
|
try {
|
377
603
|
var _require2;
|
378
604
|
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
|
@@ -387,6 +613,83 @@ const getVersions = async () => {
|
|
387
613
|
};
|
388
614
|
};
|
389
615
|
|
616
|
+
const host = process.env.VAL_BUILD_URL || "https://app.val.build";
|
617
|
+
async function login(options) {
|
618
|
+
try {
|
619
|
+
var _response$headers$get;
|
620
|
+
console.log(picocolors__default["default"].cyan("\nStarting login process...\n"));
|
621
|
+
|
622
|
+
// Step 1: Initiate login and get token and URL
|
623
|
+
const response = await fetch(`${host}/api/login`, {
|
624
|
+
method: "POST",
|
625
|
+
headers: {
|
626
|
+
"Content-Type": "application/json"
|
627
|
+
}
|
628
|
+
});
|
629
|
+
let token;
|
630
|
+
let url;
|
631
|
+
if (!((_response$headers$get = response.headers.get("content-type")) !== null && _response$headers$get !== void 0 && _response$headers$get.includes("application/json"))) {
|
632
|
+
const text = await response.text();
|
633
|
+
console.error(picocolors__default["default"].red("Unexpected failure while trying to login (content type was not JSON). Server response:"), text || "<empty>");
|
634
|
+
process.exit(1);
|
635
|
+
}
|
636
|
+
const json = await response.json();
|
637
|
+
if (json) {
|
638
|
+
token = json.nonce;
|
639
|
+
url = json.url;
|
640
|
+
}
|
641
|
+
if (!token || !url) {
|
642
|
+
console.error(picocolors__default["default"].red("Unexpected response from the server."), json);
|
643
|
+
process.exit(1);
|
644
|
+
}
|
645
|
+
console.log(picocolors__default["default"].green("Open the following URL in your browser to log in:"));
|
646
|
+
console.log(picocolors__default["default"].underline(picocolors__default["default"].blue(url)));
|
647
|
+
console.log(picocolors__default["default"].dim("\nWaiting for login confirmation...\n"));
|
648
|
+
|
649
|
+
// Step 2: Poll for login confirmation
|
650
|
+
const result = await pollForConfirmation(token);
|
651
|
+
|
652
|
+
// Step 3: Save the token
|
653
|
+
const filePath = server.getPersonalAccessTokenPath(options.root || process.cwd());
|
654
|
+
saveToken(result, filePath);
|
655
|
+
} catch (error) {
|
656
|
+
console.error(picocolors__default["default"].red("An error occurred during the login process. Check your internet connection. Details:"), error instanceof Error ? error.message : JSON.stringify(error, null, 2));
|
657
|
+
process.exit(1);
|
658
|
+
}
|
659
|
+
}
|
660
|
+
const MAX_DURATION = 5 * 60 * 1000; // 5 minutes
|
661
|
+
async function pollForConfirmation(token) {
|
662
|
+
const start = Date.now();
|
663
|
+
while (Date.now() - start < MAX_DURATION) {
|
664
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
665
|
+
const response = await fetch(`${host}/api/login?token=${token}&consume=true`);
|
666
|
+
if (response.status === 500) {
|
667
|
+
console.error(picocolors__default["default"].red("An error occurred on the server."));
|
668
|
+
process.exit(1);
|
669
|
+
}
|
670
|
+
if (response.status === 200) {
|
671
|
+
const json = await response.json();
|
672
|
+
if (json) {
|
673
|
+
if (typeof json.profile.username === "string" && typeof json.pat === "string") {
|
674
|
+
return json;
|
675
|
+
} else {
|
676
|
+
console.error(picocolors__default["default"].red("Unexpected response from the server."));
|
677
|
+
process.exit(1);
|
678
|
+
}
|
679
|
+
}
|
680
|
+
}
|
681
|
+
}
|
682
|
+
console.error(picocolors__default["default"].red("Login confirmation timed out."));
|
683
|
+
process.exit(1);
|
684
|
+
}
|
685
|
+
function saveToken(result, filePath) {
|
686
|
+
fs__default$1["default"].mkdirSync(path__default["default"].dirname(filePath), {
|
687
|
+
recursive: true
|
688
|
+
});
|
689
|
+
fs__default$1["default"].writeFileSync(filePath, JSON.stringify(result, null, 2));
|
690
|
+
console.log(picocolors__default["default"].green(`Token for ${picocolors__default["default"].cyan(result.profile.username)} saved to ${picocolors__default["default"].cyan(filePath)}`));
|
691
|
+
}
|
692
|
+
|
390
693
|
async function main() {
|
391
694
|
const {
|
392
695
|
input,
|
@@ -401,6 +704,7 @@ async function main() {
|
|
401
704
|
|
402
705
|
Commands:
|
403
706
|
validate
|
707
|
+
login
|
404
708
|
list-files
|
405
709
|
versions
|
406
710
|
|
@@ -411,6 +715,12 @@ async function main() {
|
|
411
715
|
--fix [fix] Attempt to fix validation errors
|
412
716
|
--noEslint [noEslint] Disable eslint validation during validate
|
413
717
|
|
718
|
+
|
719
|
+
Command: login
|
720
|
+
Description: login to app.val.build and generate a Personal Access Token
|
721
|
+
Options:
|
722
|
+
--root [root], -r [root] Set project root directory (default process.cwd())
|
723
|
+
|
414
724
|
|
415
725
|
Command: files
|
416
726
|
Description: EXPERIMENTAL.
|
@@ -464,6 +774,10 @@ async function main() {
|
|
464
774
|
});
|
465
775
|
case "versions":
|
466
776
|
return versions();
|
777
|
+
case "login":
|
778
|
+
return login({
|
779
|
+
root: flags.root
|
780
|
+
});
|
467
781
|
case "validate":
|
468
782
|
case "idate":
|
469
783
|
if (flags.managedDir) {
|
@@ -483,7 +797,7 @@ void main().catch(err => {
|
|
483
797
|
process.exitCode = 1;
|
484
798
|
});
|
485
799
|
async function versions() {
|
486
|
-
const foundVersions =
|
800
|
+
const foundVersions = getVersions();
|
487
801
|
console.log(`${chalk__default["default"].cyan("@valbuild/core")}: ${foundVersions.coreVersion}`);
|
488
802
|
console.log(`${chalk__default["default"].cyan("@valbuild/next")}: ${foundVersions.nextVersion}`);
|
489
803
|
}
|