@valbuild/cli 0.73.0 → 0.73.2
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 +108 -33
- package/cli/dist/valbuild-cli-cli.cjs.prod.js +108 -33
- package/cli/dist/valbuild-cli-cli.esm.js +105 -33
- package/package.json +6 -5
- package/src/utils/evalValConfigFile.ts +90 -0
- package/src/validate.ts +61 -49
@@ -9,6 +9,9 @@ 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');
|
12
15
|
var fs$1 = require('fs');
|
13
16
|
|
14
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
@@ -36,23 +39,102 @@ var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
|
36
39
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
37
40
|
var picocolors__default = /*#__PURE__*/_interopDefault(picocolors);
|
38
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);
|
39
45
|
var fs__default$1 = /*#__PURE__*/_interopDefault(fs$1);
|
40
46
|
|
41
47
|
function error(message) {
|
42
48
|
console.error(chalk__default["default"].red("❌Error: ") + message);
|
43
49
|
}
|
44
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
|
+
|
118
|
+
function getFileExt(filePath) {
|
119
|
+
// NOTE: We do not import the path module. This code is copied in different projects. We want the same implementation and which means that this might running in browser where path is not available).
|
120
|
+
return filePath.split(".").pop() || "";
|
121
|
+
}
|
122
|
+
|
123
|
+
const textEncoder = new TextEncoder();
|
45
124
|
async function validate({
|
46
125
|
root,
|
47
126
|
fix,
|
48
127
|
noEslint
|
49
128
|
}) {
|
50
129
|
const valRemoteHost = process.env.VAL_REMOTE_HOST || core.DEFAULT_VAL_REMOTE_HOST;
|
130
|
+
const contentHostUrl = process.env.VAL_CONTENT_URL || "https://content.val.build";
|
51
131
|
const projectRoot = root ? path__default["default"].resolve(root) : process.cwd();
|
52
132
|
const eslint$1 = new eslint.ESLint({
|
53
133
|
cwd: projectRoot,
|
54
134
|
ignore: false
|
55
135
|
});
|
136
|
+
const valConfigFile = (await evalValConfigFile(projectRoot, "val.config.ts")) || (await evalValConfigFile(projectRoot, "val.config.js"));
|
137
|
+
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)}'` : ""}...`));
|
56
138
|
const service = await server.createService(projectRoot, {});
|
57
139
|
const checkKeyIsValid = async (key, sourcePath) => {
|
58
140
|
const [moduleFilePath, modulePath] = core.Internal.splitModuleFilePathAndModulePath(sourcePath);
|
@@ -120,7 +202,7 @@ async function validate({
|
|
120
202
|
});
|
121
203
|
console.log(errors === 0 ? picocolors__default["default"].green("✔") : picocolors__default["default"].red("✘"), "ESlint complete", lintFiles.length, "files");
|
122
204
|
}
|
123
|
-
console.log("
|
205
|
+
console.log(picocolors__default["default"].greenBright(`Found ${valFiles.length} files...`));
|
124
206
|
let publicProjectId;
|
125
207
|
let didFix = false; // TODO: ugly
|
126
208
|
async function validateFile(file) {
|
@@ -208,7 +290,6 @@ async function validate({
|
|
208
290
|
if (valModule.source && valModule.schema) {
|
209
291
|
const resolvedRemoteFileAtSourcePath = core.Internal.resolvePath(modulePath, valModule.source, valModule.schema);
|
210
292
|
let filePath = null;
|
211
|
-
console.log(sourcePath, resolvedRemoteFileAtSourcePath.source);
|
212
293
|
try {
|
213
294
|
var _resolvedRemoteFileAt;
|
214
295
|
filePath = path__default["default"].join(projectRoot, // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
@@ -245,8 +326,7 @@ async function validate({
|
|
245
326
|
console.log(picocolors__default["default"].yellow("⚠"), `Remote file ${filePath} already uploaded`);
|
246
327
|
continue;
|
247
328
|
}
|
248
|
-
// TODO: parallelize
|
249
|
-
console.log(picocolors__default["default"].yellow("⚠"), `Uploading remote file ${filePath}...`);
|
329
|
+
// TODO: parallelize uploading files
|
250
330
|
if (!resolvedRemoteFileAtSourcePath.schema) {
|
251
331
|
console.log(picocolors__default["default"].red("✘"), `Cannot upload remote file: schema not found for ${sourcePath}`);
|
252
332
|
errors += 1;
|
@@ -263,31 +343,7 @@ async function validate({
|
|
263
343
|
if (!publicProjectId || !remoteFileBuckets) {
|
264
344
|
let projectName = process.env.VAL_PROJECT;
|
265
345
|
if (!projectName) {
|
266
|
-
|
267
|
-
var _require;
|
268
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
269
|
-
projectName = (_require = require(`${root}/val.config`)) === null || _require === void 0 || (_require = _require.config) === null || _require === void 0 ? void 0 : _require.project;
|
270
|
-
} catch {
|
271
|
-
// ignore
|
272
|
-
}
|
273
|
-
}
|
274
|
-
if (!projectName) {
|
275
|
-
try {
|
276
|
-
var _require2;
|
277
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
278
|
-
projectName = (_require2 = require(`${root}/val.config.ts`)) === null || _require2 === void 0 || (_require2 = _require2.config) === null || _require2 === void 0 ? void 0 : _require2.project;
|
279
|
-
} catch {
|
280
|
-
// ignore
|
281
|
-
}
|
282
|
-
}
|
283
|
-
if (!projectName) {
|
284
|
-
try {
|
285
|
-
var _require3;
|
286
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
287
|
-
projectName = (_require3 = require(`${root}/val.config.js`)) === null || _require3 === void 0 || (_require3 = _require3.config) === null || _require3 === void 0 ? void 0 : _require3.project;
|
288
|
-
} catch {
|
289
|
-
// ignore
|
290
|
-
}
|
346
|
+
projectName = valConfigFile === null || valConfigFile === void 0 ? void 0 : valConfigFile.project;
|
291
347
|
}
|
292
348
|
if (!projectName) {
|
293
349
|
console.log(picocolors__default["default"].red("✘"), "Project name not found. Set VAL_PROJECT environment variable or add project name to val.config");
|
@@ -310,6 +366,11 @@ async function validate({
|
|
310
366
|
errors += 1;
|
311
367
|
continue;
|
312
368
|
}
|
369
|
+
if (!(valConfigFile !== null && valConfigFile !== void 0 && valConfigFile.project)) {
|
370
|
+
console.log(picocolors__default["default"].red("✘"), `Could not get project. Check that your val.config has the 'project' field set, or set it using the VAL_PROJECT environment variable`);
|
371
|
+
errors += 1;
|
372
|
+
continue;
|
373
|
+
}
|
313
374
|
if (resolveRemoteFileSchema.type !== "image" && resolveRemoteFileSchema.type !== "file") {
|
314
375
|
console.log(picocolors__default["default"].red("✘"), `The schema is the remote is neither image nor file: ${sourcePath}`);
|
315
376
|
}
|
@@ -334,17 +395,31 @@ async function validate({
|
|
334
395
|
errors += 1;
|
335
396
|
continue;
|
336
397
|
}
|
337
|
-
const
|
398
|
+
const fileHash = core.Internal.remote.getFileHash(fileBuffer);
|
399
|
+
const coreVersion = core.Internal.VERSION.core || "unknown";
|
400
|
+
const fileExt = getFileExt(filePath);
|
401
|
+
const schema = resolveRemoteFileSchema;
|
402
|
+
const metadata = fileSourceMetadata;
|
403
|
+
const ref = core.Internal.remote.createRemoteRef(valRemoteHost, {
|
404
|
+
publicProjectId,
|
405
|
+
coreVersion,
|
406
|
+
bucket,
|
407
|
+
validationHash: core.Internal.remote.getValidationHash(coreVersion, schema, fileExt, metadata, fileHash, textEncoder),
|
408
|
+
fileHash,
|
409
|
+
filePath: relativeFilePath
|
410
|
+
});
|
411
|
+
console.log(picocolors__default["default"].yellow("⚠"), `Uploading remote file: '${ref}'...`);
|
412
|
+
const remoteFileUpload = await server.uploadRemoteFile(contentHostUrl, valConfigFile.project, bucket, fileHash, fileExt, fileBuffer, {
|
338
413
|
pat
|
339
414
|
});
|
340
415
|
if (!remoteFileUpload.success) {
|
341
|
-
console.log(picocolors__default["default"].red("✘"), `
|
416
|
+
console.log(picocolors__default["default"].red("✘"), `Could not upload remote file: '${ref}'. Error: ${remoteFileUpload.error}`);
|
342
417
|
errors += 1;
|
343
418
|
continue;
|
344
419
|
}
|
345
|
-
console.log(picocolors__default["default"].
|
420
|
+
console.log(picocolors__default["default"].green("✔"), `Completed upload of remote file: '${ref}'`);
|
346
421
|
remoteFiles[sourcePath] = {
|
347
|
-
ref
|
422
|
+
ref,
|
348
423
|
metadata: fileSourceMetadata
|
349
424
|
};
|
350
425
|
}
|
@@ -9,6 +9,9 @@ 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');
|
12
15
|
var fs$1 = require('fs');
|
13
16
|
|
14
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
@@ -36,23 +39,102 @@ var chalk__default = /*#__PURE__*/_interopDefault(chalk);
|
|
36
39
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
37
40
|
var picocolors__default = /*#__PURE__*/_interopDefault(picocolors);
|
38
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);
|
39
45
|
var fs__default$1 = /*#__PURE__*/_interopDefault(fs$1);
|
40
46
|
|
41
47
|
function error(message) {
|
42
48
|
console.error(chalk__default["default"].red("❌Error: ") + message);
|
43
49
|
}
|
44
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
|
+
|
118
|
+
function getFileExt(filePath) {
|
119
|
+
// NOTE: We do not import the path module. This code is copied in different projects. We want the same implementation and which means that this might running in browser where path is not available).
|
120
|
+
return filePath.split(".").pop() || "";
|
121
|
+
}
|
122
|
+
|
123
|
+
const textEncoder = new TextEncoder();
|
45
124
|
async function validate({
|
46
125
|
root,
|
47
126
|
fix,
|
48
127
|
noEslint
|
49
128
|
}) {
|
50
129
|
const valRemoteHost = process.env.VAL_REMOTE_HOST || core.DEFAULT_VAL_REMOTE_HOST;
|
130
|
+
const contentHostUrl = process.env.VAL_CONTENT_URL || "https://content.val.build";
|
51
131
|
const projectRoot = root ? path__default["default"].resolve(root) : process.cwd();
|
52
132
|
const eslint$1 = new eslint.ESLint({
|
53
133
|
cwd: projectRoot,
|
54
134
|
ignore: false
|
55
135
|
});
|
136
|
+
const valConfigFile = (await evalValConfigFile(projectRoot, "val.config.ts")) || (await evalValConfigFile(projectRoot, "val.config.js"));
|
137
|
+
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)}'` : ""}...`));
|
56
138
|
const service = await server.createService(projectRoot, {});
|
57
139
|
const checkKeyIsValid = async (key, sourcePath) => {
|
58
140
|
const [moduleFilePath, modulePath] = core.Internal.splitModuleFilePathAndModulePath(sourcePath);
|
@@ -120,7 +202,7 @@ async function validate({
|
|
120
202
|
});
|
121
203
|
console.log(errors === 0 ? picocolors__default["default"].green("✔") : picocolors__default["default"].red("✘"), "ESlint complete", lintFiles.length, "files");
|
122
204
|
}
|
123
|
-
console.log("
|
205
|
+
console.log(picocolors__default["default"].greenBright(`Found ${valFiles.length} files...`));
|
124
206
|
let publicProjectId;
|
125
207
|
let didFix = false; // TODO: ugly
|
126
208
|
async function validateFile(file) {
|
@@ -208,7 +290,6 @@ async function validate({
|
|
208
290
|
if (valModule.source && valModule.schema) {
|
209
291
|
const resolvedRemoteFileAtSourcePath = core.Internal.resolvePath(modulePath, valModule.source, valModule.schema);
|
210
292
|
let filePath = null;
|
211
|
-
console.log(sourcePath, resolvedRemoteFileAtSourcePath.source);
|
212
293
|
try {
|
213
294
|
var _resolvedRemoteFileAt;
|
214
295
|
filePath = path__default["default"].join(projectRoot, // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
@@ -245,8 +326,7 @@ async function validate({
|
|
245
326
|
console.log(picocolors__default["default"].yellow("⚠"), `Remote file ${filePath} already uploaded`);
|
246
327
|
continue;
|
247
328
|
}
|
248
|
-
// TODO: parallelize
|
249
|
-
console.log(picocolors__default["default"].yellow("⚠"), `Uploading remote file ${filePath}...`);
|
329
|
+
// TODO: parallelize uploading files
|
250
330
|
if (!resolvedRemoteFileAtSourcePath.schema) {
|
251
331
|
console.log(picocolors__default["default"].red("✘"), `Cannot upload remote file: schema not found for ${sourcePath}`);
|
252
332
|
errors += 1;
|
@@ -263,31 +343,7 @@ async function validate({
|
|
263
343
|
if (!publicProjectId || !remoteFileBuckets) {
|
264
344
|
let projectName = process.env.VAL_PROJECT;
|
265
345
|
if (!projectName) {
|
266
|
-
|
267
|
-
var _require;
|
268
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
269
|
-
projectName = (_require = require(`${root}/val.config`)) === null || _require === void 0 || (_require = _require.config) === null || _require === void 0 ? void 0 : _require.project;
|
270
|
-
} catch {
|
271
|
-
// ignore
|
272
|
-
}
|
273
|
-
}
|
274
|
-
if (!projectName) {
|
275
|
-
try {
|
276
|
-
var _require2;
|
277
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
278
|
-
projectName = (_require2 = require(`${root}/val.config.ts`)) === null || _require2 === void 0 || (_require2 = _require2.config) === null || _require2 === void 0 ? void 0 : _require2.project;
|
279
|
-
} catch {
|
280
|
-
// ignore
|
281
|
-
}
|
282
|
-
}
|
283
|
-
if (!projectName) {
|
284
|
-
try {
|
285
|
-
var _require3;
|
286
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
287
|
-
projectName = (_require3 = require(`${root}/val.config.js`)) === null || _require3 === void 0 || (_require3 = _require3.config) === null || _require3 === void 0 ? void 0 : _require3.project;
|
288
|
-
} catch {
|
289
|
-
// ignore
|
290
|
-
}
|
346
|
+
projectName = valConfigFile === null || valConfigFile === void 0 ? void 0 : valConfigFile.project;
|
291
347
|
}
|
292
348
|
if (!projectName) {
|
293
349
|
console.log(picocolors__default["default"].red("✘"), "Project name not found. Set VAL_PROJECT environment variable or add project name to val.config");
|
@@ -310,6 +366,11 @@ async function validate({
|
|
310
366
|
errors += 1;
|
311
367
|
continue;
|
312
368
|
}
|
369
|
+
if (!(valConfigFile !== null && valConfigFile !== void 0 && valConfigFile.project)) {
|
370
|
+
console.log(picocolors__default["default"].red("✘"), `Could not get project. Check that your val.config has the 'project' field set, or set it using the VAL_PROJECT environment variable`);
|
371
|
+
errors += 1;
|
372
|
+
continue;
|
373
|
+
}
|
313
374
|
if (resolveRemoteFileSchema.type !== "image" && resolveRemoteFileSchema.type !== "file") {
|
314
375
|
console.log(picocolors__default["default"].red("✘"), `The schema is the remote is neither image nor file: ${sourcePath}`);
|
315
376
|
}
|
@@ -334,17 +395,31 @@ async function validate({
|
|
334
395
|
errors += 1;
|
335
396
|
continue;
|
336
397
|
}
|
337
|
-
const
|
398
|
+
const fileHash = core.Internal.remote.getFileHash(fileBuffer);
|
399
|
+
const coreVersion = core.Internal.VERSION.core || "unknown";
|
400
|
+
const fileExt = getFileExt(filePath);
|
401
|
+
const schema = resolveRemoteFileSchema;
|
402
|
+
const metadata = fileSourceMetadata;
|
403
|
+
const ref = core.Internal.remote.createRemoteRef(valRemoteHost, {
|
404
|
+
publicProjectId,
|
405
|
+
coreVersion,
|
406
|
+
bucket,
|
407
|
+
validationHash: core.Internal.remote.getValidationHash(coreVersion, schema, fileExt, metadata, fileHash, textEncoder),
|
408
|
+
fileHash,
|
409
|
+
filePath: relativeFilePath
|
410
|
+
});
|
411
|
+
console.log(picocolors__default["default"].yellow("⚠"), `Uploading remote file: '${ref}'...`);
|
412
|
+
const remoteFileUpload = await server.uploadRemoteFile(contentHostUrl, valConfigFile.project, bucket, fileHash, fileExt, fileBuffer, {
|
338
413
|
pat
|
339
414
|
});
|
340
415
|
if (!remoteFileUpload.success) {
|
341
|
-
console.log(picocolors__default["default"].red("✘"), `
|
416
|
+
console.log(picocolors__default["default"].red("✘"), `Could not upload remote file: '${ref}'. Error: ${remoteFileUpload.error}`);
|
342
417
|
errors += 1;
|
343
418
|
continue;
|
344
419
|
}
|
345
|
-
console.log(picocolors__default["default"].
|
420
|
+
console.log(picocolors__default["default"].green("✔"), `Completed upload of remote file: '${ref}'`);
|
346
421
|
remoteFiles[sourcePath] = {
|
347
|
-
ref
|
422
|
+
ref,
|
348
423
|
metadata: fileSourceMetadata
|
349
424
|
};
|
350
425
|
}
|
@@ -7,23 +7,102 @@ import { glob } from 'fast-glob';
|
|
7
7
|
import picocolors from 'picocolors';
|
8
8
|
import { ESLint } from 'eslint';
|
9
9
|
import fs from 'fs/promises';
|
10
|
+
import vm from 'node:vm';
|
11
|
+
import ts from 'typescript';
|
12
|
+
import z from 'zod';
|
10
13
|
import fs$1 from 'fs';
|
11
14
|
|
12
15
|
function error(message) {
|
13
16
|
console.error(chalk.red("❌Error: ") + message);
|
14
17
|
}
|
15
18
|
|
19
|
+
const ValConfigSchema = z.object({
|
20
|
+
project: z.string().optional(),
|
21
|
+
root: z.string().optional(),
|
22
|
+
files: z.object({
|
23
|
+
directory: z.string().refine(val => val.startsWith("/public/val"), {
|
24
|
+
message: "files.directory must start with '/public/val'"
|
25
|
+
})
|
26
|
+
}).optional(),
|
27
|
+
gitCommit: z.string().optional(),
|
28
|
+
gitBranch: z.string().optional(),
|
29
|
+
defaultTheme: z.union([z.literal("light"), z.literal("dark")]).optional(),
|
30
|
+
ai: z.object({
|
31
|
+
commitMessages: z.object({
|
32
|
+
disabled: z.boolean().optional()
|
33
|
+
}).optional()
|
34
|
+
}).optional()
|
35
|
+
});
|
36
|
+
async function evalValConfigFile(projectRoot, configFileName) {
|
37
|
+
const valConfigPath = path.join(projectRoot, configFileName);
|
38
|
+
let code = null;
|
39
|
+
try {
|
40
|
+
code = await fs.readFile(valConfigPath, "utf-8");
|
41
|
+
} catch (err) {
|
42
|
+
//
|
43
|
+
}
|
44
|
+
if (!code) {
|
45
|
+
return null;
|
46
|
+
}
|
47
|
+
const transpiled = ts.transpileModule(code, {
|
48
|
+
compilerOptions: {
|
49
|
+
target: ts.ScriptTarget.ES2020,
|
50
|
+
module: ts.ModuleKind.CommonJS,
|
51
|
+
esModuleInterop: true
|
52
|
+
},
|
53
|
+
fileName: valConfigPath
|
54
|
+
});
|
55
|
+
const exportsObj = {};
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
57
|
+
const sandbox = {
|
58
|
+
exports: exportsObj,
|
59
|
+
module: {
|
60
|
+
exports: exportsObj
|
61
|
+
},
|
62
|
+
require,
|
63
|
+
// NOTE: this is a security risk, but this code is running in the users own environment at the CLI level
|
64
|
+
__filename: valConfigPath,
|
65
|
+
__dirname: path.dirname(valConfigPath),
|
66
|
+
console,
|
67
|
+
process
|
68
|
+
};
|
69
|
+
sandbox.global = sandbox;
|
70
|
+
const context = vm.createContext(sandbox);
|
71
|
+
const script = new vm.Script(transpiled.outputText, {
|
72
|
+
filename: valConfigPath
|
73
|
+
});
|
74
|
+
script.runInContext(context);
|
75
|
+
const valConfig = sandbox.module.exports.config;
|
76
|
+
if (!valConfig) {
|
77
|
+
throw Error(`Val config file at path: '${valConfigPath}' must export a config object. Got: ${valConfig}`);
|
78
|
+
}
|
79
|
+
const result = ValConfigSchema.safeParse(valConfig);
|
80
|
+
if (!result.success) {
|
81
|
+
throw Error(`Val config file at path: '${valConfigPath}' has invalid schema: ${result.error.message}`);
|
82
|
+
}
|
83
|
+
return result.data;
|
84
|
+
}
|
85
|
+
|
86
|
+
function getFileExt(filePath) {
|
87
|
+
// NOTE: We do not import the path module. This code is copied in different projects. We want the same implementation and which means that this might running in browser where path is not available).
|
88
|
+
return filePath.split(".").pop() || "";
|
89
|
+
}
|
90
|
+
|
91
|
+
const textEncoder = new TextEncoder();
|
16
92
|
async function validate({
|
17
93
|
root,
|
18
94
|
fix,
|
19
95
|
noEslint
|
20
96
|
}) {
|
21
97
|
const valRemoteHost = process.env.VAL_REMOTE_HOST || DEFAULT_VAL_REMOTE_HOST;
|
98
|
+
const contentHostUrl = process.env.VAL_CONTENT_URL || "https://content.val.build";
|
22
99
|
const projectRoot = root ? path.resolve(root) : process.cwd();
|
23
100
|
const eslint = new ESLint({
|
24
101
|
cwd: projectRoot,
|
25
102
|
ignore: false
|
26
103
|
});
|
104
|
+
const valConfigFile = (await evalValConfigFile(projectRoot, "val.config.ts")) || (await evalValConfigFile(projectRoot, "val.config.js"));
|
105
|
+
console.log(picocolors.greenBright(`Validating project${valConfigFile !== null && valConfigFile !== void 0 && valConfigFile.project ? ` '${picocolors.inverse(valConfigFile === null || valConfigFile === void 0 ? void 0 : valConfigFile.project)}'` : ""}...`));
|
27
106
|
const service = await createService(projectRoot, {});
|
28
107
|
const checkKeyIsValid = async (key, sourcePath) => {
|
29
108
|
const [moduleFilePath, modulePath] = Internal.splitModuleFilePathAndModulePath(sourcePath);
|
@@ -91,7 +170,7 @@ async function validate({
|
|
91
170
|
});
|
92
171
|
console.log(errors === 0 ? picocolors.green("✔") : picocolors.red("✘"), "ESlint complete", lintFiles.length, "files");
|
93
172
|
}
|
94
|
-
console.log(
|
173
|
+
console.log(picocolors.greenBright(`Found ${valFiles.length} files...`));
|
95
174
|
let publicProjectId;
|
96
175
|
let didFix = false; // TODO: ugly
|
97
176
|
async function validateFile(file) {
|
@@ -179,7 +258,6 @@ async function validate({
|
|
179
258
|
if (valModule.source && valModule.schema) {
|
180
259
|
const resolvedRemoteFileAtSourcePath = Internal.resolvePath(modulePath, valModule.source, valModule.schema);
|
181
260
|
let filePath = null;
|
182
|
-
console.log(sourcePath, resolvedRemoteFileAtSourcePath.source);
|
183
261
|
try {
|
184
262
|
var _resolvedRemoteFileAt;
|
185
263
|
filePath = path.join(projectRoot, // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
@@ -216,8 +294,7 @@ async function validate({
|
|
216
294
|
console.log(picocolors.yellow("⚠"), `Remote file ${filePath} already uploaded`);
|
217
295
|
continue;
|
218
296
|
}
|
219
|
-
// TODO: parallelize
|
220
|
-
console.log(picocolors.yellow("⚠"), `Uploading remote file ${filePath}...`);
|
297
|
+
// TODO: parallelize uploading files
|
221
298
|
if (!resolvedRemoteFileAtSourcePath.schema) {
|
222
299
|
console.log(picocolors.red("✘"), `Cannot upload remote file: schema not found for ${sourcePath}`);
|
223
300
|
errors += 1;
|
@@ -234,31 +311,7 @@ async function validate({
|
|
234
311
|
if (!publicProjectId || !remoteFileBuckets) {
|
235
312
|
let projectName = process.env.VAL_PROJECT;
|
236
313
|
if (!projectName) {
|
237
|
-
|
238
|
-
var _require;
|
239
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
240
|
-
projectName = (_require = require(`${root}/val.config`)) === null || _require === void 0 || (_require = _require.config) === null || _require === void 0 ? void 0 : _require.project;
|
241
|
-
} catch {
|
242
|
-
// ignore
|
243
|
-
}
|
244
|
-
}
|
245
|
-
if (!projectName) {
|
246
|
-
try {
|
247
|
-
var _require2;
|
248
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
249
|
-
projectName = (_require2 = require(`${root}/val.config.ts`)) === null || _require2 === void 0 || (_require2 = _require2.config) === null || _require2 === void 0 ? void 0 : _require2.project;
|
250
|
-
} catch {
|
251
|
-
// ignore
|
252
|
-
}
|
253
|
-
}
|
254
|
-
if (!projectName) {
|
255
|
-
try {
|
256
|
-
var _require3;
|
257
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
258
|
-
projectName = (_require3 = require(`${root}/val.config.js`)) === null || _require3 === void 0 || (_require3 = _require3.config) === null || _require3 === void 0 ? void 0 : _require3.project;
|
259
|
-
} catch {
|
260
|
-
// ignore
|
261
|
-
}
|
314
|
+
projectName = valConfigFile === null || valConfigFile === void 0 ? void 0 : valConfigFile.project;
|
262
315
|
}
|
263
316
|
if (!projectName) {
|
264
317
|
console.log(picocolors.red("✘"), "Project name not found. Set VAL_PROJECT environment variable or add project name to val.config");
|
@@ -281,6 +334,11 @@ async function validate({
|
|
281
334
|
errors += 1;
|
282
335
|
continue;
|
283
336
|
}
|
337
|
+
if (!(valConfigFile !== null && valConfigFile !== void 0 && valConfigFile.project)) {
|
338
|
+
console.log(picocolors.red("✘"), `Could not get project. Check that your val.config has the 'project' field set, or set it using the VAL_PROJECT environment variable`);
|
339
|
+
errors += 1;
|
340
|
+
continue;
|
341
|
+
}
|
284
342
|
if (resolveRemoteFileSchema.type !== "image" && resolveRemoteFileSchema.type !== "file") {
|
285
343
|
console.log(picocolors.red("✘"), `The schema is the remote is neither image nor file: ${sourcePath}`);
|
286
344
|
}
|
@@ -305,17 +363,31 @@ async function validate({
|
|
305
363
|
errors += 1;
|
306
364
|
continue;
|
307
365
|
}
|
308
|
-
const
|
366
|
+
const fileHash = Internal.remote.getFileHash(fileBuffer);
|
367
|
+
const coreVersion = Internal.VERSION.core || "unknown";
|
368
|
+
const fileExt = getFileExt(filePath);
|
369
|
+
const schema = resolveRemoteFileSchema;
|
370
|
+
const metadata = fileSourceMetadata;
|
371
|
+
const ref = Internal.remote.createRemoteRef(valRemoteHost, {
|
372
|
+
publicProjectId,
|
373
|
+
coreVersion,
|
374
|
+
bucket,
|
375
|
+
validationHash: Internal.remote.getValidationHash(coreVersion, schema, fileExt, metadata, fileHash, textEncoder),
|
376
|
+
fileHash,
|
377
|
+
filePath: relativeFilePath
|
378
|
+
});
|
379
|
+
console.log(picocolors.yellow("⚠"), `Uploading remote file: '${ref}'...`);
|
380
|
+
const remoteFileUpload = await uploadRemoteFile(contentHostUrl, valConfigFile.project, bucket, fileHash, fileExt, fileBuffer, {
|
309
381
|
pat
|
310
382
|
});
|
311
383
|
if (!remoteFileUpload.success) {
|
312
|
-
console.log(picocolors.red("✘"), `
|
384
|
+
console.log(picocolors.red("✘"), `Could not upload remote file: '${ref}'. Error: ${remoteFileUpload.error}`);
|
313
385
|
errors += 1;
|
314
386
|
continue;
|
315
387
|
}
|
316
|
-
console.log(picocolors.
|
388
|
+
console.log(picocolors.green("✔"), `Completed upload of remote file: '${ref}'`);
|
317
389
|
remoteFiles[sourcePath] = {
|
318
|
-
ref
|
390
|
+
ref,
|
319
391
|
metadata: fileSourceMetadata
|
320
392
|
};
|
321
393
|
}
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@valbuild/cli",
|
3
3
|
"private": false,
|
4
|
-
"version": "0.73.
|
4
|
+
"version": "0.73.2",
|
5
5
|
"description": "Val CLI tools",
|
6
6
|
"bin": {
|
7
7
|
"val": "./bin.js"
|
@@ -18,9 +18,9 @@
|
|
18
18
|
"typecheck": "tsc --noEmit"
|
19
19
|
},
|
20
20
|
"dependencies": {
|
21
|
-
"@valbuild/core": "~0.73.
|
22
|
-
"@valbuild/server": "~0.73.
|
23
|
-
"@valbuild/eslint-plugin": "~0.73.
|
21
|
+
"@valbuild/core": "~0.73.2",
|
22
|
+
"@valbuild/server": "~0.73.2",
|
23
|
+
"@valbuild/eslint-plugin": "~0.73.2",
|
24
24
|
"eslint": "^8.31.0",
|
25
25
|
"@inquirer/confirm": "^2.0.15",
|
26
26
|
"@inquirer/prompts": "^3.0.2",
|
@@ -34,7 +34,8 @@
|
|
34
34
|
"zod": "^3.22.4"
|
35
35
|
},
|
36
36
|
"peerDependencies": {
|
37
|
-
"prettier": "*"
|
37
|
+
"prettier": "*",
|
38
|
+
"typescript": ">=5.0.0"
|
38
39
|
},
|
39
40
|
"preconstruct": {
|
40
41
|
"entrypoints": [
|
@@ -0,0 +1,90 @@
|
|
1
|
+
import path from "path";
|
2
|
+
import fs from "fs/promises";
|
3
|
+
import vm from "node:vm";
|
4
|
+
import ts from "typescript"; // TODO: make this dependency optional (only required if the file is val.config.ts not val.config.js)
|
5
|
+
import z from "zod";
|
6
|
+
import { ValConfig } from "@valbuild/core";
|
7
|
+
|
8
|
+
const ValConfigSchema = z.object({
|
9
|
+
project: z.string().optional(),
|
10
|
+
root: z.string().optional(),
|
11
|
+
files: z
|
12
|
+
.object({
|
13
|
+
directory: z
|
14
|
+
.string()
|
15
|
+
.refine((val): val is `/public/val` => val.startsWith("/public/val"), {
|
16
|
+
message: "files.directory must start with '/public/val'",
|
17
|
+
}),
|
18
|
+
})
|
19
|
+
.optional(),
|
20
|
+
gitCommit: z.string().optional(),
|
21
|
+
gitBranch: z.string().optional(),
|
22
|
+
defaultTheme: z.union([z.literal("light"), z.literal("dark")]).optional(),
|
23
|
+
ai: z
|
24
|
+
.object({
|
25
|
+
commitMessages: z
|
26
|
+
.object({
|
27
|
+
disabled: z.boolean().optional(),
|
28
|
+
})
|
29
|
+
.optional(),
|
30
|
+
})
|
31
|
+
.optional(),
|
32
|
+
});
|
33
|
+
|
34
|
+
export async function evalValConfigFile(
|
35
|
+
projectRoot: string,
|
36
|
+
configFileName: string,
|
37
|
+
): Promise<ValConfig | null> {
|
38
|
+
const valConfigPath = path.join(projectRoot, configFileName);
|
39
|
+
|
40
|
+
let code: string | null = null;
|
41
|
+
try {
|
42
|
+
code = await fs.readFile(valConfigPath, "utf-8");
|
43
|
+
} catch (err) {
|
44
|
+
//
|
45
|
+
}
|
46
|
+
if (!code) {
|
47
|
+
return null;
|
48
|
+
}
|
49
|
+
|
50
|
+
const transpiled = ts.transpileModule(code, {
|
51
|
+
compilerOptions: {
|
52
|
+
target: ts.ScriptTarget.ES2020,
|
53
|
+
module: ts.ModuleKind.CommonJS,
|
54
|
+
esModuleInterop: true,
|
55
|
+
},
|
56
|
+
fileName: valConfigPath,
|
57
|
+
});
|
58
|
+
|
59
|
+
const exportsObj = {};
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
61
|
+
const sandbox: Record<string, any> = {
|
62
|
+
exports: exportsObj,
|
63
|
+
module: { exports: exportsObj },
|
64
|
+
require, // NOTE: this is a security risk, but this code is running in the users own environment at the CLI level
|
65
|
+
__filename: valConfigPath,
|
66
|
+
__dirname: path.dirname(valConfigPath),
|
67
|
+
console,
|
68
|
+
process,
|
69
|
+
};
|
70
|
+
sandbox.global = sandbox;
|
71
|
+
|
72
|
+
const context = vm.createContext(sandbox);
|
73
|
+
const script = new vm.Script(transpiled.outputText, {
|
74
|
+
filename: valConfigPath,
|
75
|
+
});
|
76
|
+
script.runInContext(context);
|
77
|
+
const valConfig = sandbox.module.exports.config;
|
78
|
+
if (!valConfig) {
|
79
|
+
throw Error(
|
80
|
+
`Val config file at path: '${valConfigPath}' must export a config object. Got: ${valConfig}`,
|
81
|
+
);
|
82
|
+
}
|
83
|
+
const result = ValConfigSchema.safeParse(valConfig);
|
84
|
+
if (!result.success) {
|
85
|
+
throw Error(
|
86
|
+
`Val config file at path: '${valConfigPath}' has invalid schema: ${result.error.message}`,
|
87
|
+
);
|
88
|
+
}
|
89
|
+
return result.data;
|
90
|
+
}
|
package/src/validate.ts
CHANGED
@@ -22,7 +22,10 @@ import { glob } from "fast-glob";
|
|
22
22
|
import picocolors from "picocolors";
|
23
23
|
import { ESLint } from "eslint";
|
24
24
|
import fs from "fs/promises";
|
25
|
+
import { evalValConfigFile } from "./utils/evalValConfigFile";
|
26
|
+
import { getFileExt } from "./utils/getFileExt";
|
25
27
|
|
28
|
+
const textEncoder = new TextEncoder();
|
26
29
|
export async function validate({
|
27
30
|
root,
|
28
31
|
fix,
|
@@ -33,11 +36,21 @@ export async function validate({
|
|
33
36
|
noEslint?: boolean;
|
34
37
|
}) {
|
35
38
|
const valRemoteHost = process.env.VAL_REMOTE_HOST || DEFAULT_VAL_REMOTE_HOST;
|
39
|
+
const contentHostUrl =
|
40
|
+
process.env.VAL_CONTENT_URL || "https://content.val.build";
|
36
41
|
const projectRoot = root ? path.resolve(root) : process.cwd();
|
37
42
|
const eslint = new ESLint({
|
38
43
|
cwd: projectRoot,
|
39
44
|
ignore: false,
|
40
45
|
});
|
46
|
+
const valConfigFile =
|
47
|
+
(await evalValConfigFile(projectRoot, "val.config.ts")) ||
|
48
|
+
(await evalValConfigFile(projectRoot, "val.config.js"));
|
49
|
+
console.log(
|
50
|
+
picocolors.greenBright(
|
51
|
+
`Validating project${valConfigFile?.project ? ` '${picocolors.inverse(valConfigFile?.project)}'` : ""}...`,
|
52
|
+
),
|
53
|
+
);
|
41
54
|
const service = await createService(projectRoot, {});
|
42
55
|
const checkKeyIsValid = async (
|
43
56
|
key: string,
|
@@ -130,8 +143,7 @@ export async function validate({
|
|
130
143
|
"files",
|
131
144
|
);
|
132
145
|
}
|
133
|
-
console.log(
|
134
|
-
|
146
|
+
console.log(picocolors.greenBright(`Found ${valFiles.length} files...`));
|
135
147
|
let publicProjectId: string | undefined;
|
136
148
|
let didFix = false; // TODO: ugly
|
137
149
|
async function validateFile(file: string): Promise<number> {
|
@@ -287,10 +299,6 @@ export async function validate({
|
|
287
299
|
valModule.schema,
|
288
300
|
);
|
289
301
|
let filePath: string | null = null;
|
290
|
-
console.log(
|
291
|
-
sourcePath,
|
292
|
-
resolvedRemoteFileAtSourcePath.source,
|
293
|
-
);
|
294
302
|
try {
|
295
303
|
filePath = path.join(
|
296
304
|
projectRoot,
|
@@ -348,12 +356,7 @@ export async function validate({
|
|
348
356
|
);
|
349
357
|
continue;
|
350
358
|
}
|
351
|
-
// TODO: parallelize
|
352
|
-
console.log(
|
353
|
-
picocolors.yellow("⚠"),
|
354
|
-
`Uploading remote file ${filePath}...`,
|
355
|
-
);
|
356
|
-
|
359
|
+
// TODO: parallelize uploading files
|
357
360
|
if (!resolvedRemoteFileAtSourcePath.schema) {
|
358
361
|
console.log(
|
359
362
|
picocolors.red("✘"),
|
@@ -383,31 +386,7 @@ export async function validate({
|
|
383
386
|
if (!publicProjectId || !remoteFileBuckets) {
|
384
387
|
let projectName = process.env.VAL_PROJECT;
|
385
388
|
if (!projectName) {
|
386
|
-
|
387
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
388
|
-
projectName = require(`${root}/val.config`)?.config
|
389
|
-
?.project;
|
390
|
-
} catch {
|
391
|
-
// ignore
|
392
|
-
}
|
393
|
-
}
|
394
|
-
if (!projectName) {
|
395
|
-
try {
|
396
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
397
|
-
projectName = require(`${root}/val.config.ts`)?.config
|
398
|
-
?.project;
|
399
|
-
} catch {
|
400
|
-
// ignore
|
401
|
-
}
|
402
|
-
}
|
403
|
-
if (!projectName) {
|
404
|
-
try {
|
405
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
406
|
-
projectName = require(`${root}/val.config.js`)?.config
|
407
|
-
?.project;
|
408
|
-
} catch {
|
409
|
-
// ignore
|
410
|
-
}
|
389
|
+
projectName = valConfigFile?.project;
|
411
390
|
}
|
412
391
|
if (!projectName) {
|
413
392
|
console.log(
|
@@ -440,6 +419,14 @@ export async function validate({
|
|
440
419
|
errors += 1;
|
441
420
|
continue;
|
442
421
|
}
|
422
|
+
if (!valConfigFile?.project) {
|
423
|
+
console.log(
|
424
|
+
picocolors.red("✘"),
|
425
|
+
`Could not get project. Check that your val.config has the 'project' field set, or set it using the VAL_PROJECT environment variable`,
|
426
|
+
);
|
427
|
+
errors += 1;
|
428
|
+
continue;
|
429
|
+
}
|
443
430
|
if (
|
444
431
|
resolveRemoteFileSchema.type !== "image" &&
|
445
432
|
resolveRemoteFileSchema.type !== "file"
|
@@ -485,32 +472,57 @@ export async function validate({
|
|
485
472
|
errors += 1;
|
486
473
|
continue;
|
487
474
|
}
|
488
|
-
|
489
|
-
|
490
|
-
|
475
|
+
|
476
|
+
const fileHash = Internal.remote.getFileHash(fileBuffer);
|
477
|
+
const coreVersion = Internal.VERSION.core || "unknown";
|
478
|
+
const fileExt = getFileExt(filePath);
|
479
|
+
const schema = resolveRemoteFileSchema as
|
480
|
+
| SerializedImageSchema
|
481
|
+
| SerializedFileSchema;
|
482
|
+
const metadata = fileSourceMetadata;
|
483
|
+
const ref = Internal.remote.createRemoteRef(valRemoteHost, {
|
491
484
|
publicProjectId,
|
485
|
+
coreVersion,
|
492
486
|
bucket,
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
487
|
+
validationHash: Internal.remote.getValidationHash(
|
488
|
+
coreVersion,
|
489
|
+
schema,
|
490
|
+
fileExt,
|
491
|
+
metadata,
|
492
|
+
fileHash,
|
493
|
+
textEncoder,
|
494
|
+
),
|
495
|
+
fileHash,
|
496
|
+
filePath: relativeFilePath,
|
497
|
+
});
|
498
|
+
console.log(
|
499
|
+
picocolors.yellow("⚠"),
|
500
|
+
`Uploading remote file: '${ref}'...`,
|
501
|
+
);
|
502
|
+
|
503
|
+
const remoteFileUpload = await uploadRemoteFile(
|
504
|
+
contentHostUrl,
|
505
|
+
valConfigFile.project,
|
506
|
+
bucket,
|
507
|
+
fileHash,
|
508
|
+
fileExt,
|
509
|
+
fileBuffer,
|
498
510
|
{ pat },
|
499
511
|
);
|
500
512
|
if (!remoteFileUpload.success) {
|
501
513
|
console.log(
|
502
514
|
picocolors.red("✘"),
|
503
|
-
`
|
515
|
+
`Could not upload remote file: '${ref}'. Error: ${remoteFileUpload.error}`,
|
504
516
|
);
|
505
517
|
errors += 1;
|
506
518
|
continue;
|
507
519
|
}
|
508
520
|
console.log(
|
509
|
-
picocolors.
|
510
|
-
`
|
521
|
+
picocolors.green("✔"),
|
522
|
+
`Completed upload of remote file: '${ref}'`,
|
511
523
|
);
|
512
524
|
remoteFiles[sourcePath as SourcePath] = {
|
513
|
-
ref
|
525
|
+
ref,
|
514
526
|
metadata: fileSourceMetadata,
|
515
527
|
};
|
516
528
|
}
|