@valbuild/server 0.48.1 → 0.50.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.
@@ -31,7 +31,7 @@ export declare class LocalValServer implements ValServer {
|
|
31
31
|
private badRequest;
|
32
32
|
postCommit(): Promise<ValServerJsonResult<{}>>;
|
33
33
|
authorize(): Promise<ValServerRedirectResult<VAL_STATE_COOKIE>>;
|
34
|
-
callback(): Promise<ValServerRedirectResult<VAL_STATE_COOKIE | VAL_SESSION_COOKIE>>;
|
34
|
+
callback(): Promise<ValServerRedirectResult<VAL_STATE_COOKIE | VAL_SESSION_COOKIE | VAL_ENABLE_COOKIE_NAME>>;
|
35
35
|
logout(): Promise<ValServerResult<VAL_STATE_COOKIE | VAL_SESSION_COOKIE>>;
|
36
36
|
getFiles(): Promise<ValServerResult<never, ReadableStream<Uint8Array>>>;
|
37
37
|
getPatches(): Promise<ValServerJsonResult<ApiGetPatchResponse>>;
|
@@ -22,7 +22,7 @@ export interface ValServer {
|
|
22
22
|
callback(query: {
|
23
23
|
code?: string;
|
24
24
|
state?: string;
|
25
|
-
}, cookies: ValCookies<VAL_STATE_COOKIE>): Promise<ValServerRedirectResult<VAL_STATE_COOKIE | VAL_SESSION_COOKIE>>;
|
25
|
+
}, cookies: ValCookies<VAL_STATE_COOKIE>): Promise<ValServerRedirectResult<VAL_STATE_COOKIE | VAL_SESSION_COOKIE | VAL_ENABLE_COOKIE_NAME>>;
|
26
26
|
enable(query: {
|
27
27
|
redirect_to?: string;
|
28
28
|
}): Promise<ValServerRedirectResult<VAL_ENABLE_COOKIE_NAME>>;
|
@@ -320,7 +320,6 @@ const printer = ts__default["default"].createPrinter({
|
|
320
320
|
newLine: newLine
|
321
321
|
// neverAsciiEscape: true,
|
322
322
|
});
|
323
|
-
|
324
323
|
function replaceNodeValue(document, node, value) {
|
325
324
|
const replacementText = printer.printNode(ts__default["default"].EmitHint.Unspecified, toExpression(value), document);
|
326
325
|
const span = ts__default["default"].createTextSpanFromBounds(node.getStart(document, false), node.end);
|
@@ -663,7 +662,6 @@ const patchValFile = async (id, valConfigPath, patch$1, sourceFileHandler, runti
|
|
663
662
|
sourceFileHandler.writeSourceFile(newSourceFile.value);
|
664
663
|
// console.timeEnd("patchValFile" + timeId);
|
665
664
|
};
|
666
|
-
|
667
665
|
function convertDataUrlToBase64(dataUrl) {
|
668
666
|
const base64 = dataUrl.slice(dataUrl.indexOf(",") + 1);
|
669
667
|
return Buffer.from(base64, "base64");
|
@@ -888,7 +886,6 @@ class ValModuleLoader {
|
|
888
886
|
}
|
889
887
|
}
|
890
888
|
}
|
891
|
-
|
892
889
|
return compiledCode;
|
893
890
|
}
|
894
891
|
resolveModulePath(containingFilePath, requestedModuleName) {
|
@@ -1218,7 +1215,7 @@ class LocalValServer {
|
|
1218
1215
|
if (treePath && !path__namespace["default"].join(dir, file).replace(rootDir, "").startsWith(treePath)) {
|
1219
1216
|
continue;
|
1220
1217
|
}
|
1221
|
-
moduleIds.push(path__namespace["default"].join(dir, file).replace(rootDir, "").replace(".val.js", "").replace(".val.ts", ""));
|
1218
|
+
moduleIds.push(path__namespace["default"].join(dir, file).replace(rootDir, "").replace(".val.js", "").replace(".val.ts", "").split(path__namespace["default"].sep).join("/"));
|
1222
1219
|
}
|
1223
1220
|
}
|
1224
1221
|
};
|
@@ -1308,7 +1305,6 @@ class LocalValServer {
|
|
1308
1305
|
json: {} // no patch ids created
|
1309
1306
|
};
|
1310
1307
|
}
|
1311
|
-
|
1312
1308
|
badRequest() {
|
1313
1309
|
return {
|
1314
1310
|
status: 400,
|
@@ -1382,7 +1378,6 @@ function decodeJwt(token, secretKey) {
|
|
1382
1378
|
function getExpire() {
|
1383
1379
|
return Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 4; // 4 days
|
1384
1380
|
}
|
1385
|
-
|
1386
1381
|
const JwtHeaderSchema = z.z.object({
|
1387
1382
|
alg: z.z.literal("HS256"),
|
1388
1383
|
typ: z.z.literal("JWT")
|
@@ -1422,12 +1417,12 @@ class ProxyValServer {
|
|
1422
1417
|
"Content-Type": fetchRes.headers.get("Content-Type") || "",
|
1423
1418
|
"Content-Length": fetchRes.headers.get("Content-Length") || "0"
|
1424
1419
|
},
|
1425
|
-
|
1420
|
+
json: fetchRes.body
|
1426
1421
|
};
|
1427
1422
|
} else {
|
1428
1423
|
return {
|
1429
1424
|
status: 500,
|
1430
|
-
|
1425
|
+
json: {
|
1431
1426
|
message: "No body in response"
|
1432
1427
|
}
|
1433
1428
|
};
|
@@ -1435,7 +1430,7 @@ class ProxyValServer {
|
|
1435
1430
|
} else {
|
1436
1431
|
return {
|
1437
1432
|
status: fetchRes.status,
|
1438
|
-
|
1433
|
+
json: {
|
1439
1434
|
message: "Failed to get files"
|
1440
1435
|
}
|
1441
1436
|
};
|
@@ -1468,7 +1463,6 @@ class ProxyValServer {
|
|
1468
1463
|
}
|
1469
1464
|
}
|
1470
1465
|
},
|
1471
|
-
|
1472
1466
|
status: 302,
|
1473
1467
|
redirectTo: appAuthorizeUrl
|
1474
1468
|
};
|
@@ -1542,6 +1536,7 @@ class ProxyValServer {
|
|
1542
1536
|
[internal.VAL_STATE_COOKIE]: {
|
1543
1537
|
value: null
|
1544
1538
|
},
|
1539
|
+
[internal.VAL_ENABLE_COOKIE_NAME]: ENABLE_COOKIE_VALUE,
|
1545
1540
|
[internal.VAL_SESSION_COOKIE]: {
|
1546
1541
|
value: cookie,
|
1547
1542
|
options: {
|
@@ -1553,7 +1548,6 @@ class ProxyValServer {
|
|
1553
1548
|
}
|
1554
1549
|
}
|
1555
1550
|
},
|
1556
|
-
|
1557
1551
|
redirectTo: callbackReqSuccess.redirect_uri || "/"
|
1558
1552
|
};
|
1559
1553
|
}
|
@@ -1596,7 +1590,7 @@ class ProxyValServer {
|
|
1596
1590
|
console.error(`Failed while processing: ${errorMessageType}`, err);
|
1597
1591
|
return {
|
1598
1592
|
status: 500,
|
1599
|
-
|
1593
|
+
json: {
|
1600
1594
|
message: err.message
|
1601
1595
|
}
|
1602
1596
|
};
|
@@ -1628,8 +1622,9 @@ class ProxyValServer {
|
|
1628
1622
|
} else {
|
1629
1623
|
return {
|
1630
1624
|
status: fetchRes.status,
|
1631
|
-
|
1632
|
-
message: "Failed to
|
1625
|
+
json: {
|
1626
|
+
message: "Failed to authorize",
|
1627
|
+
...(await fetchRes.json())
|
1633
1628
|
}
|
1634
1629
|
};
|
1635
1630
|
}
|
@@ -1646,7 +1641,7 @@ class ProxyValServer {
|
|
1646
1641
|
if (!commit) {
|
1647
1642
|
return {
|
1648
1643
|
status: 400,
|
1649
|
-
|
1644
|
+
json: {
|
1650
1645
|
message: "Could not detect the git commit. Check if env is missing VAL_GIT_COMMIT."
|
1651
1646
|
}
|
1652
1647
|
};
|
@@ -1690,7 +1685,7 @@ class ProxyValServer {
|
|
1690
1685
|
} catch (err) {
|
1691
1686
|
return {
|
1692
1687
|
status: 500,
|
1693
|
-
|
1688
|
+
json: {
|
1694
1689
|
message: "Failed to fetch: check network connection"
|
1695
1690
|
}
|
1696
1691
|
};
|
@@ -1705,7 +1700,7 @@ class ProxyValServer {
|
|
1705
1700
|
if (!commit) {
|
1706
1701
|
return {
|
1707
1702
|
status: 400,
|
1708
|
-
|
1703
|
+
json: {
|
1709
1704
|
message: "Could not detect the git commit. Check if env is missing VAL_GIT_COMMIT."
|
1710
1705
|
}
|
1711
1706
|
};
|
@@ -1726,7 +1721,7 @@ class ProxyValServer {
|
|
1726
1721
|
} else {
|
1727
1722
|
return {
|
1728
1723
|
status: fetchRes.status,
|
1729
|
-
|
1724
|
+
json: {
|
1730
1725
|
message: "Failed to get patches"
|
1731
1726
|
}
|
1732
1727
|
};
|
@@ -1754,7 +1749,7 @@ class ProxyValServer {
|
|
1754
1749
|
if (!patchJSON.success) {
|
1755
1750
|
return {
|
1756
1751
|
status: 400,
|
1757
|
-
|
1752
|
+
json: {
|
1758
1753
|
message: "Invalid patch",
|
1759
1754
|
details: patchJSON.error.issues
|
1760
1755
|
}
|
@@ -2273,7 +2268,17 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
|
|
2273
2268
|
const filename = path__namespace["default"].join(config.projectRoot, maybeRef);
|
2274
2269
|
const buffer = fs__default["default"].readFileSync(filename);
|
2275
2270
|
const imageSize = sizeOf__default["default"](buffer);
|
2276
|
-
|
2271
|
+
let mimeType = null;
|
2272
|
+
if (imageSize.type) {
|
2273
|
+
const possibleMimeType = `image/${imageSize.type}`;
|
2274
|
+
if (internal.MIME_TYPES_TO_EXT[possibleMimeType]) {
|
2275
|
+
mimeType = possibleMimeType;
|
2276
|
+
}
|
2277
|
+
const filenameBasedLookup = internal.filenameToMimeType(filename);
|
2278
|
+
if (filenameBasedLookup) {
|
2279
|
+
mimeType = filenameBasedLookup;
|
2280
|
+
}
|
2281
|
+
}
|
2277
2282
|
if (!mimeType) {
|
2278
2283
|
throw Error("Cannot determine mimetype of image");
|
2279
2284
|
}
|
@@ -2294,6 +2299,26 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
|
|
2294
2299
|
mimeType
|
2295
2300
|
};
|
2296
2301
|
}
|
2302
|
+
async function getFileMetadata() {
|
2303
|
+
const maybeRef = validationError.value && typeof validationError.value === "object" && core.FILE_REF_PROP in validationError.value && typeof validationError.value[core.FILE_REF_PROP] === "string" ? validationError.value[core.FILE_REF_PROP] : undefined;
|
2304
|
+
if (!maybeRef) {
|
2305
|
+
// TODO:
|
2306
|
+
throw Error("Cannot fix image without a file reference");
|
2307
|
+
}
|
2308
|
+
const filename = path__namespace["default"].join(config.projectRoot, maybeRef);
|
2309
|
+
const buffer = fs__default["default"].readFileSync(filename);
|
2310
|
+
let mimeType = internal.filenameToMimeType(filename);
|
2311
|
+
if (!mimeType) {
|
2312
|
+
mimeType = "application/octet-stream";
|
2313
|
+
}
|
2314
|
+
const sha256 = core.Internal.getSHA256Hash(textEncoder.encode(
|
2315
|
+
// TODO: we should probably store the mimetype in the metadata and reuse it here
|
2316
|
+
`data:${mimeType};base64,${buffer.toString("base64")}`));
|
2317
|
+
return {
|
2318
|
+
sha256,
|
2319
|
+
mimeType
|
2320
|
+
};
|
2321
|
+
}
|
2297
2322
|
const remainingErrors = [];
|
2298
2323
|
const patch$1 = [];
|
2299
2324
|
for (const fix of validationError.fixes || []) {
|
@@ -2379,6 +2404,72 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
|
|
2379
2404
|
}
|
2380
2405
|
});
|
2381
2406
|
}
|
2407
|
+
} else if (fix === "file:add-metadata" || fix === "file:check-metadata") {
|
2408
|
+
const fileMetadata = await getFileMetadata();
|
2409
|
+
if (fileMetadata.sha256 === undefined) {
|
2410
|
+
remainingErrors.push({
|
2411
|
+
...validationError,
|
2412
|
+
message: "Failed to get image metadata",
|
2413
|
+
fixes: undefined
|
2414
|
+
});
|
2415
|
+
} else if (fix === "file:check-metadata") {
|
2416
|
+
const currentValue = validationError.value;
|
2417
|
+
const metadataIsCorrect =
|
2418
|
+
// metadata is a prop that is an object
|
2419
|
+
typeof currentValue === "object" && currentValue && "metadata" in currentValue && currentValue.metadata && typeof currentValue.metadata === "object" &&
|
2420
|
+
// sha256 is correct
|
2421
|
+
"sha256" in currentValue.metadata && currentValue.metadata.sha256 === fileMetadata.sha256 &&
|
2422
|
+
// mimeType is correct
|
2423
|
+
"mimeType" in currentValue.metadata && currentValue.metadata.mimeType === fileMetadata.mimeType;
|
2424
|
+
|
2425
|
+
// skips if the metadata is already correct
|
2426
|
+
if (!metadataIsCorrect) {
|
2427
|
+
if (apply) {
|
2428
|
+
patch$1.push({
|
2429
|
+
op: "replace",
|
2430
|
+
path: patch.sourceToPatchPath(sourcePath).concat("metadata"),
|
2431
|
+
value: {
|
2432
|
+
sha256: fileMetadata.sha256,
|
2433
|
+
...(fileMetadata.mimeType ? {
|
2434
|
+
mimeType: fileMetadata.mimeType
|
2435
|
+
} : {})
|
2436
|
+
}
|
2437
|
+
});
|
2438
|
+
} else {
|
2439
|
+
if (typeof currentValue === "object" && currentValue && "metadata" in currentValue && currentValue.metadata && typeof currentValue.metadata === "object") {
|
2440
|
+
if (!("sha256" in currentValue.metadata) || currentValue.metadata.sha256 !== fileMetadata.sha256) {
|
2441
|
+
remainingErrors.push({
|
2442
|
+
message: "File metadata sha256 is incorrect! Found: " + ("sha256" in currentValue.metadata ? currentValue.metadata.sha256 : "<empty>") + ". Expected: " + fileMetadata.sha256 + ".",
|
2443
|
+
fixes: undefined
|
2444
|
+
});
|
2445
|
+
}
|
2446
|
+
if (!("mimeType" in currentValue.metadata) || currentValue.metadata.mimeType !== fileMetadata.mimeType) {
|
2447
|
+
remainingErrors.push({
|
2448
|
+
message: "File metadata mimeType is incorrect! Found: " + ("mimeType" in currentValue.metadata ? currentValue.metadata.mimeType : "<empty>") + ". Expected: " + fileMetadata.mimeType,
|
2449
|
+
fixes: undefined
|
2450
|
+
});
|
2451
|
+
}
|
2452
|
+
} else {
|
2453
|
+
remainingErrors.push({
|
2454
|
+
...validationError,
|
2455
|
+
message: "Image metadata is not an object!",
|
2456
|
+
fixes: undefined
|
2457
|
+
});
|
2458
|
+
}
|
2459
|
+
}
|
2460
|
+
}
|
2461
|
+
} else if (fix === "file:add-metadata") {
|
2462
|
+
patch$1.push({
|
2463
|
+
op: "add",
|
2464
|
+
path: patch.sourceToPatchPath(sourcePath).concat("metadata"),
|
2465
|
+
value: {
|
2466
|
+
sha256: fileMetadata.sha256,
|
2467
|
+
...(fileMetadata.mimeType ? {
|
2468
|
+
mimeType: fileMetadata.mimeType
|
2469
|
+
} : {})
|
2470
|
+
}
|
2471
|
+
});
|
2472
|
+
}
|
2382
2473
|
}
|
2383
2474
|
}
|
2384
2475
|
if (!validationError.fixes || validationError.fixes.length === 0) {
|
@@ -320,7 +320,6 @@ const printer = ts__default["default"].createPrinter({
|
|
320
320
|
newLine: newLine
|
321
321
|
// neverAsciiEscape: true,
|
322
322
|
});
|
323
|
-
|
324
323
|
function replaceNodeValue(document, node, value) {
|
325
324
|
const replacementText = printer.printNode(ts__default["default"].EmitHint.Unspecified, toExpression(value), document);
|
326
325
|
const span = ts__default["default"].createTextSpanFromBounds(node.getStart(document, false), node.end);
|
@@ -663,7 +662,6 @@ const patchValFile = async (id, valConfigPath, patch$1, sourceFileHandler, runti
|
|
663
662
|
sourceFileHandler.writeSourceFile(newSourceFile.value);
|
664
663
|
// console.timeEnd("patchValFile" + timeId);
|
665
664
|
};
|
666
|
-
|
667
665
|
function convertDataUrlToBase64(dataUrl) {
|
668
666
|
const base64 = dataUrl.slice(dataUrl.indexOf(",") + 1);
|
669
667
|
return Buffer.from(base64, "base64");
|
@@ -888,7 +886,6 @@ class ValModuleLoader {
|
|
888
886
|
}
|
889
887
|
}
|
890
888
|
}
|
891
|
-
|
892
889
|
return compiledCode;
|
893
890
|
}
|
894
891
|
resolveModulePath(containingFilePath, requestedModuleName) {
|
@@ -1218,7 +1215,7 @@ class LocalValServer {
|
|
1218
1215
|
if (treePath && !path__namespace["default"].join(dir, file).replace(rootDir, "").startsWith(treePath)) {
|
1219
1216
|
continue;
|
1220
1217
|
}
|
1221
|
-
moduleIds.push(path__namespace["default"].join(dir, file).replace(rootDir, "").replace(".val.js", "").replace(".val.ts", ""));
|
1218
|
+
moduleIds.push(path__namespace["default"].join(dir, file).replace(rootDir, "").replace(".val.js", "").replace(".val.ts", "").split(path__namespace["default"].sep).join("/"));
|
1222
1219
|
}
|
1223
1220
|
}
|
1224
1221
|
};
|
@@ -1308,7 +1305,6 @@ class LocalValServer {
|
|
1308
1305
|
json: {} // no patch ids created
|
1309
1306
|
};
|
1310
1307
|
}
|
1311
|
-
|
1312
1308
|
badRequest() {
|
1313
1309
|
return {
|
1314
1310
|
status: 400,
|
@@ -1382,7 +1378,6 @@ function decodeJwt(token, secretKey) {
|
|
1382
1378
|
function getExpire() {
|
1383
1379
|
return Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 4; // 4 days
|
1384
1380
|
}
|
1385
|
-
|
1386
1381
|
const JwtHeaderSchema = z.z.object({
|
1387
1382
|
alg: z.z.literal("HS256"),
|
1388
1383
|
typ: z.z.literal("JWT")
|
@@ -1422,12 +1417,12 @@ class ProxyValServer {
|
|
1422
1417
|
"Content-Type": fetchRes.headers.get("Content-Type") || "",
|
1423
1418
|
"Content-Length": fetchRes.headers.get("Content-Length") || "0"
|
1424
1419
|
},
|
1425
|
-
|
1420
|
+
json: fetchRes.body
|
1426
1421
|
};
|
1427
1422
|
} else {
|
1428
1423
|
return {
|
1429
1424
|
status: 500,
|
1430
|
-
|
1425
|
+
json: {
|
1431
1426
|
message: "No body in response"
|
1432
1427
|
}
|
1433
1428
|
};
|
@@ -1435,7 +1430,7 @@ class ProxyValServer {
|
|
1435
1430
|
} else {
|
1436
1431
|
return {
|
1437
1432
|
status: fetchRes.status,
|
1438
|
-
|
1433
|
+
json: {
|
1439
1434
|
message: "Failed to get files"
|
1440
1435
|
}
|
1441
1436
|
};
|
@@ -1468,7 +1463,6 @@ class ProxyValServer {
|
|
1468
1463
|
}
|
1469
1464
|
}
|
1470
1465
|
},
|
1471
|
-
|
1472
1466
|
status: 302,
|
1473
1467
|
redirectTo: appAuthorizeUrl
|
1474
1468
|
};
|
@@ -1542,6 +1536,7 @@ class ProxyValServer {
|
|
1542
1536
|
[internal.VAL_STATE_COOKIE]: {
|
1543
1537
|
value: null
|
1544
1538
|
},
|
1539
|
+
[internal.VAL_ENABLE_COOKIE_NAME]: ENABLE_COOKIE_VALUE,
|
1545
1540
|
[internal.VAL_SESSION_COOKIE]: {
|
1546
1541
|
value: cookie,
|
1547
1542
|
options: {
|
@@ -1553,7 +1548,6 @@ class ProxyValServer {
|
|
1553
1548
|
}
|
1554
1549
|
}
|
1555
1550
|
},
|
1556
|
-
|
1557
1551
|
redirectTo: callbackReqSuccess.redirect_uri || "/"
|
1558
1552
|
};
|
1559
1553
|
}
|
@@ -1596,7 +1590,7 @@ class ProxyValServer {
|
|
1596
1590
|
console.error(`Failed while processing: ${errorMessageType}`, err);
|
1597
1591
|
return {
|
1598
1592
|
status: 500,
|
1599
|
-
|
1593
|
+
json: {
|
1600
1594
|
message: err.message
|
1601
1595
|
}
|
1602
1596
|
};
|
@@ -1628,8 +1622,9 @@ class ProxyValServer {
|
|
1628
1622
|
} else {
|
1629
1623
|
return {
|
1630
1624
|
status: fetchRes.status,
|
1631
|
-
|
1632
|
-
message: "Failed to
|
1625
|
+
json: {
|
1626
|
+
message: "Failed to authorize",
|
1627
|
+
...(await fetchRes.json())
|
1633
1628
|
}
|
1634
1629
|
};
|
1635
1630
|
}
|
@@ -1646,7 +1641,7 @@ class ProxyValServer {
|
|
1646
1641
|
if (!commit) {
|
1647
1642
|
return {
|
1648
1643
|
status: 400,
|
1649
|
-
|
1644
|
+
json: {
|
1650
1645
|
message: "Could not detect the git commit. Check if env is missing VAL_GIT_COMMIT."
|
1651
1646
|
}
|
1652
1647
|
};
|
@@ -1690,7 +1685,7 @@ class ProxyValServer {
|
|
1690
1685
|
} catch (err) {
|
1691
1686
|
return {
|
1692
1687
|
status: 500,
|
1693
|
-
|
1688
|
+
json: {
|
1694
1689
|
message: "Failed to fetch: check network connection"
|
1695
1690
|
}
|
1696
1691
|
};
|
@@ -1705,7 +1700,7 @@ class ProxyValServer {
|
|
1705
1700
|
if (!commit) {
|
1706
1701
|
return {
|
1707
1702
|
status: 400,
|
1708
|
-
|
1703
|
+
json: {
|
1709
1704
|
message: "Could not detect the git commit. Check if env is missing VAL_GIT_COMMIT."
|
1710
1705
|
}
|
1711
1706
|
};
|
@@ -1726,7 +1721,7 @@ class ProxyValServer {
|
|
1726
1721
|
} else {
|
1727
1722
|
return {
|
1728
1723
|
status: fetchRes.status,
|
1729
|
-
|
1724
|
+
json: {
|
1730
1725
|
message: "Failed to get patches"
|
1731
1726
|
}
|
1732
1727
|
};
|
@@ -1754,7 +1749,7 @@ class ProxyValServer {
|
|
1754
1749
|
if (!patchJSON.success) {
|
1755
1750
|
return {
|
1756
1751
|
status: 400,
|
1757
|
-
|
1752
|
+
json: {
|
1758
1753
|
message: "Invalid patch",
|
1759
1754
|
details: patchJSON.error.issues
|
1760
1755
|
}
|
@@ -2273,7 +2268,17 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
|
|
2273
2268
|
const filename = path__namespace["default"].join(config.projectRoot, maybeRef);
|
2274
2269
|
const buffer = fs__default["default"].readFileSync(filename);
|
2275
2270
|
const imageSize = sizeOf__default["default"](buffer);
|
2276
|
-
|
2271
|
+
let mimeType = null;
|
2272
|
+
if (imageSize.type) {
|
2273
|
+
const possibleMimeType = `image/${imageSize.type}`;
|
2274
|
+
if (internal.MIME_TYPES_TO_EXT[possibleMimeType]) {
|
2275
|
+
mimeType = possibleMimeType;
|
2276
|
+
}
|
2277
|
+
const filenameBasedLookup = internal.filenameToMimeType(filename);
|
2278
|
+
if (filenameBasedLookup) {
|
2279
|
+
mimeType = filenameBasedLookup;
|
2280
|
+
}
|
2281
|
+
}
|
2277
2282
|
if (!mimeType) {
|
2278
2283
|
throw Error("Cannot determine mimetype of image");
|
2279
2284
|
}
|
@@ -2294,6 +2299,26 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
|
|
2294
2299
|
mimeType
|
2295
2300
|
};
|
2296
2301
|
}
|
2302
|
+
async function getFileMetadata() {
|
2303
|
+
const maybeRef = validationError.value && typeof validationError.value === "object" && core.FILE_REF_PROP in validationError.value && typeof validationError.value[core.FILE_REF_PROP] === "string" ? validationError.value[core.FILE_REF_PROP] : undefined;
|
2304
|
+
if (!maybeRef) {
|
2305
|
+
// TODO:
|
2306
|
+
throw Error("Cannot fix image without a file reference");
|
2307
|
+
}
|
2308
|
+
const filename = path__namespace["default"].join(config.projectRoot, maybeRef);
|
2309
|
+
const buffer = fs__default["default"].readFileSync(filename);
|
2310
|
+
let mimeType = internal.filenameToMimeType(filename);
|
2311
|
+
if (!mimeType) {
|
2312
|
+
mimeType = "application/octet-stream";
|
2313
|
+
}
|
2314
|
+
const sha256 = core.Internal.getSHA256Hash(textEncoder.encode(
|
2315
|
+
// TODO: we should probably store the mimetype in the metadata and reuse it here
|
2316
|
+
`data:${mimeType};base64,${buffer.toString("base64")}`));
|
2317
|
+
return {
|
2318
|
+
sha256,
|
2319
|
+
mimeType
|
2320
|
+
};
|
2321
|
+
}
|
2297
2322
|
const remainingErrors = [];
|
2298
2323
|
const patch$1 = [];
|
2299
2324
|
for (const fix of validationError.fixes || []) {
|
@@ -2379,6 +2404,72 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
|
|
2379
2404
|
}
|
2380
2405
|
});
|
2381
2406
|
}
|
2407
|
+
} else if (fix === "file:add-metadata" || fix === "file:check-metadata") {
|
2408
|
+
const fileMetadata = await getFileMetadata();
|
2409
|
+
if (fileMetadata.sha256 === undefined) {
|
2410
|
+
remainingErrors.push({
|
2411
|
+
...validationError,
|
2412
|
+
message: "Failed to get image metadata",
|
2413
|
+
fixes: undefined
|
2414
|
+
});
|
2415
|
+
} else if (fix === "file:check-metadata") {
|
2416
|
+
const currentValue = validationError.value;
|
2417
|
+
const metadataIsCorrect =
|
2418
|
+
// metadata is a prop that is an object
|
2419
|
+
typeof currentValue === "object" && currentValue && "metadata" in currentValue && currentValue.metadata && typeof currentValue.metadata === "object" &&
|
2420
|
+
// sha256 is correct
|
2421
|
+
"sha256" in currentValue.metadata && currentValue.metadata.sha256 === fileMetadata.sha256 &&
|
2422
|
+
// mimeType is correct
|
2423
|
+
"mimeType" in currentValue.metadata && currentValue.metadata.mimeType === fileMetadata.mimeType;
|
2424
|
+
|
2425
|
+
// skips if the metadata is already correct
|
2426
|
+
if (!metadataIsCorrect) {
|
2427
|
+
if (apply) {
|
2428
|
+
patch$1.push({
|
2429
|
+
op: "replace",
|
2430
|
+
path: patch.sourceToPatchPath(sourcePath).concat("metadata"),
|
2431
|
+
value: {
|
2432
|
+
sha256: fileMetadata.sha256,
|
2433
|
+
...(fileMetadata.mimeType ? {
|
2434
|
+
mimeType: fileMetadata.mimeType
|
2435
|
+
} : {})
|
2436
|
+
}
|
2437
|
+
});
|
2438
|
+
} else {
|
2439
|
+
if (typeof currentValue === "object" && currentValue && "metadata" in currentValue && currentValue.metadata && typeof currentValue.metadata === "object") {
|
2440
|
+
if (!("sha256" in currentValue.metadata) || currentValue.metadata.sha256 !== fileMetadata.sha256) {
|
2441
|
+
remainingErrors.push({
|
2442
|
+
message: "File metadata sha256 is incorrect! Found: " + ("sha256" in currentValue.metadata ? currentValue.metadata.sha256 : "<empty>") + ". Expected: " + fileMetadata.sha256 + ".",
|
2443
|
+
fixes: undefined
|
2444
|
+
});
|
2445
|
+
}
|
2446
|
+
if (!("mimeType" in currentValue.metadata) || currentValue.metadata.mimeType !== fileMetadata.mimeType) {
|
2447
|
+
remainingErrors.push({
|
2448
|
+
message: "File metadata mimeType is incorrect! Found: " + ("mimeType" in currentValue.metadata ? currentValue.metadata.mimeType : "<empty>") + ". Expected: " + fileMetadata.mimeType,
|
2449
|
+
fixes: undefined
|
2450
|
+
});
|
2451
|
+
}
|
2452
|
+
} else {
|
2453
|
+
remainingErrors.push({
|
2454
|
+
...validationError,
|
2455
|
+
message: "Image metadata is not an object!",
|
2456
|
+
fixes: undefined
|
2457
|
+
});
|
2458
|
+
}
|
2459
|
+
}
|
2460
|
+
}
|
2461
|
+
} else if (fix === "file:add-metadata") {
|
2462
|
+
patch$1.push({
|
2463
|
+
op: "add",
|
2464
|
+
path: patch.sourceToPatchPath(sourcePath).concat("metadata"),
|
2465
|
+
value: {
|
2466
|
+
sha256: fileMetadata.sha256,
|
2467
|
+
...(fileMetadata.mimeType ? {
|
2468
|
+
mimeType: fileMetadata.mimeType
|
2469
|
+
} : {})
|
2470
|
+
}
|
2471
|
+
});
|
2472
|
+
}
|
2382
2473
|
}
|
2383
2474
|
}
|
2384
2475
|
if (!validationError.fixes || validationError.fixes.length === 0) {
|
@@ -8,7 +8,7 @@ import path__default from 'path';
|
|
8
8
|
import fs, { promises } from 'fs';
|
9
9
|
import { transform } from 'sucrase';
|
10
10
|
import z, { z as z$1 } from 'zod';
|
11
|
-
import { VAL_ENABLE_COOKIE_NAME, VAL_STATE_COOKIE as VAL_STATE_COOKIE$1, VAL_SESSION_COOKIE as VAL_SESSION_COOKIE$1,
|
11
|
+
import { VAL_ENABLE_COOKIE_NAME, VAL_STATE_COOKIE as VAL_STATE_COOKIE$1, VAL_SESSION_COOKIE as VAL_SESSION_COOKIE$1, MIME_TYPES_TO_EXT, filenameToMimeType } from '@valbuild/shared/internal';
|
12
12
|
import crypto from 'crypto';
|
13
13
|
import { createUIRequestHandler } from '@valbuild/ui/server';
|
14
14
|
import sizeOf from 'image-size';
|
@@ -290,7 +290,6 @@ const printer = ts.createPrinter({
|
|
290
290
|
newLine: newLine
|
291
291
|
// neverAsciiEscape: true,
|
292
292
|
});
|
293
|
-
|
294
293
|
function replaceNodeValue(document, node, value) {
|
295
294
|
const replacementText = printer.printNode(ts.EmitHint.Unspecified, toExpression(value), document);
|
296
295
|
const span = ts.createTextSpanFromBounds(node.getStart(document, false), node.end);
|
@@ -633,7 +632,6 @@ const patchValFile = async (id, valConfigPath, patch, sourceFileHandler, runtime
|
|
633
632
|
sourceFileHandler.writeSourceFile(newSourceFile.value);
|
634
633
|
// console.timeEnd("patchValFile" + timeId);
|
635
634
|
};
|
636
|
-
|
637
635
|
function convertDataUrlToBase64(dataUrl) {
|
638
636
|
const base64 = dataUrl.slice(dataUrl.indexOf(",") + 1);
|
639
637
|
return Buffer.from(base64, "base64");
|
@@ -858,7 +856,6 @@ class ValModuleLoader {
|
|
858
856
|
}
|
859
857
|
}
|
860
858
|
}
|
861
|
-
|
862
859
|
return compiledCode;
|
863
860
|
}
|
864
861
|
resolveModulePath(containingFilePath, requestedModuleName) {
|
@@ -1188,7 +1185,7 @@ class LocalValServer {
|
|
1188
1185
|
if (treePath && !path__default.join(dir, file).replace(rootDir, "").startsWith(treePath)) {
|
1189
1186
|
continue;
|
1190
1187
|
}
|
1191
|
-
moduleIds.push(path__default.join(dir, file).replace(rootDir, "").replace(".val.js", "").replace(".val.ts", ""));
|
1188
|
+
moduleIds.push(path__default.join(dir, file).replace(rootDir, "").replace(".val.js", "").replace(".val.ts", "").split(path__default.sep).join("/"));
|
1192
1189
|
}
|
1193
1190
|
}
|
1194
1191
|
};
|
@@ -1278,7 +1275,6 @@ class LocalValServer {
|
|
1278
1275
|
json: {} // no patch ids created
|
1279
1276
|
};
|
1280
1277
|
}
|
1281
|
-
|
1282
1278
|
badRequest() {
|
1283
1279
|
return {
|
1284
1280
|
status: 400,
|
@@ -1352,7 +1348,6 @@ function decodeJwt(token, secretKey) {
|
|
1352
1348
|
function getExpire() {
|
1353
1349
|
return Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 4; // 4 days
|
1354
1350
|
}
|
1355
|
-
|
1356
1351
|
const JwtHeaderSchema = z$1.object({
|
1357
1352
|
alg: z$1.literal("HS256"),
|
1358
1353
|
typ: z$1.literal("JWT")
|
@@ -1392,12 +1387,12 @@ class ProxyValServer {
|
|
1392
1387
|
"Content-Type": fetchRes.headers.get("Content-Type") || "",
|
1393
1388
|
"Content-Length": fetchRes.headers.get("Content-Length") || "0"
|
1394
1389
|
},
|
1395
|
-
|
1390
|
+
json: fetchRes.body
|
1396
1391
|
};
|
1397
1392
|
} else {
|
1398
1393
|
return {
|
1399
1394
|
status: 500,
|
1400
|
-
|
1395
|
+
json: {
|
1401
1396
|
message: "No body in response"
|
1402
1397
|
}
|
1403
1398
|
};
|
@@ -1405,7 +1400,7 @@ class ProxyValServer {
|
|
1405
1400
|
} else {
|
1406
1401
|
return {
|
1407
1402
|
status: fetchRes.status,
|
1408
|
-
|
1403
|
+
json: {
|
1409
1404
|
message: "Failed to get files"
|
1410
1405
|
}
|
1411
1406
|
};
|
@@ -1438,7 +1433,6 @@ class ProxyValServer {
|
|
1438
1433
|
}
|
1439
1434
|
}
|
1440
1435
|
},
|
1441
|
-
|
1442
1436
|
status: 302,
|
1443
1437
|
redirectTo: appAuthorizeUrl
|
1444
1438
|
};
|
@@ -1512,6 +1506,7 @@ class ProxyValServer {
|
|
1512
1506
|
[VAL_STATE_COOKIE$1]: {
|
1513
1507
|
value: null
|
1514
1508
|
},
|
1509
|
+
[VAL_ENABLE_COOKIE_NAME]: ENABLE_COOKIE_VALUE,
|
1515
1510
|
[VAL_SESSION_COOKIE$1]: {
|
1516
1511
|
value: cookie,
|
1517
1512
|
options: {
|
@@ -1523,7 +1518,6 @@ class ProxyValServer {
|
|
1523
1518
|
}
|
1524
1519
|
}
|
1525
1520
|
},
|
1526
|
-
|
1527
1521
|
redirectTo: callbackReqSuccess.redirect_uri || "/"
|
1528
1522
|
};
|
1529
1523
|
}
|
@@ -1566,7 +1560,7 @@ class ProxyValServer {
|
|
1566
1560
|
console.error(`Failed while processing: ${errorMessageType}`, err);
|
1567
1561
|
return {
|
1568
1562
|
status: 500,
|
1569
|
-
|
1563
|
+
json: {
|
1570
1564
|
message: err.message
|
1571
1565
|
}
|
1572
1566
|
};
|
@@ -1598,8 +1592,9 @@ class ProxyValServer {
|
|
1598
1592
|
} else {
|
1599
1593
|
return {
|
1600
1594
|
status: fetchRes.status,
|
1601
|
-
|
1602
|
-
message: "Failed to
|
1595
|
+
json: {
|
1596
|
+
message: "Failed to authorize",
|
1597
|
+
...(await fetchRes.json())
|
1603
1598
|
}
|
1604
1599
|
};
|
1605
1600
|
}
|
@@ -1616,7 +1611,7 @@ class ProxyValServer {
|
|
1616
1611
|
if (!commit) {
|
1617
1612
|
return {
|
1618
1613
|
status: 400,
|
1619
|
-
|
1614
|
+
json: {
|
1620
1615
|
message: "Could not detect the git commit. Check if env is missing VAL_GIT_COMMIT."
|
1621
1616
|
}
|
1622
1617
|
};
|
@@ -1660,7 +1655,7 @@ class ProxyValServer {
|
|
1660
1655
|
} catch (err) {
|
1661
1656
|
return {
|
1662
1657
|
status: 500,
|
1663
|
-
|
1658
|
+
json: {
|
1664
1659
|
message: "Failed to fetch: check network connection"
|
1665
1660
|
}
|
1666
1661
|
};
|
@@ -1675,7 +1670,7 @@ class ProxyValServer {
|
|
1675
1670
|
if (!commit) {
|
1676
1671
|
return {
|
1677
1672
|
status: 400,
|
1678
|
-
|
1673
|
+
json: {
|
1679
1674
|
message: "Could not detect the git commit. Check if env is missing VAL_GIT_COMMIT."
|
1680
1675
|
}
|
1681
1676
|
};
|
@@ -1696,7 +1691,7 @@ class ProxyValServer {
|
|
1696
1691
|
} else {
|
1697
1692
|
return {
|
1698
1693
|
status: fetchRes.status,
|
1699
|
-
|
1694
|
+
json: {
|
1700
1695
|
message: "Failed to get patches"
|
1701
1696
|
}
|
1702
1697
|
};
|
@@ -1724,7 +1719,7 @@ class ProxyValServer {
|
|
1724
1719
|
if (!patchJSON.success) {
|
1725
1720
|
return {
|
1726
1721
|
status: 400,
|
1727
|
-
|
1722
|
+
json: {
|
1728
1723
|
message: "Invalid patch",
|
1729
1724
|
details: patchJSON.error.issues
|
1730
1725
|
}
|
@@ -2243,7 +2238,17 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
|
|
2243
2238
|
const filename = path__default.join(config.projectRoot, maybeRef);
|
2244
2239
|
const buffer = fs.readFileSync(filename);
|
2245
2240
|
const imageSize = sizeOf(buffer);
|
2246
|
-
|
2241
|
+
let mimeType = null;
|
2242
|
+
if (imageSize.type) {
|
2243
|
+
const possibleMimeType = `image/${imageSize.type}`;
|
2244
|
+
if (MIME_TYPES_TO_EXT[possibleMimeType]) {
|
2245
|
+
mimeType = possibleMimeType;
|
2246
|
+
}
|
2247
|
+
const filenameBasedLookup = filenameToMimeType(filename);
|
2248
|
+
if (filenameBasedLookup) {
|
2249
|
+
mimeType = filenameBasedLookup;
|
2250
|
+
}
|
2251
|
+
}
|
2247
2252
|
if (!mimeType) {
|
2248
2253
|
throw Error("Cannot determine mimetype of image");
|
2249
2254
|
}
|
@@ -2264,6 +2269,26 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
|
|
2264
2269
|
mimeType
|
2265
2270
|
};
|
2266
2271
|
}
|
2272
|
+
async function getFileMetadata() {
|
2273
|
+
const maybeRef = validationError.value && typeof validationError.value === "object" && FILE_REF_PROP in validationError.value && typeof validationError.value[FILE_REF_PROP] === "string" ? validationError.value[FILE_REF_PROP] : undefined;
|
2274
|
+
if (!maybeRef) {
|
2275
|
+
// TODO:
|
2276
|
+
throw Error("Cannot fix image without a file reference");
|
2277
|
+
}
|
2278
|
+
const filename = path__default.join(config.projectRoot, maybeRef);
|
2279
|
+
const buffer = fs.readFileSync(filename);
|
2280
|
+
let mimeType = filenameToMimeType(filename);
|
2281
|
+
if (!mimeType) {
|
2282
|
+
mimeType = "application/octet-stream";
|
2283
|
+
}
|
2284
|
+
const sha256 = Internal.getSHA256Hash(textEncoder.encode(
|
2285
|
+
// TODO: we should probably store the mimetype in the metadata and reuse it here
|
2286
|
+
`data:${mimeType};base64,${buffer.toString("base64")}`));
|
2287
|
+
return {
|
2288
|
+
sha256,
|
2289
|
+
mimeType
|
2290
|
+
};
|
2291
|
+
}
|
2267
2292
|
const remainingErrors = [];
|
2268
2293
|
const patch = [];
|
2269
2294
|
for (const fix of validationError.fixes || []) {
|
@@ -2349,6 +2374,72 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
|
|
2349
2374
|
}
|
2350
2375
|
});
|
2351
2376
|
}
|
2377
|
+
} else if (fix === "file:add-metadata" || fix === "file:check-metadata") {
|
2378
|
+
const fileMetadata = await getFileMetadata();
|
2379
|
+
if (fileMetadata.sha256 === undefined) {
|
2380
|
+
remainingErrors.push({
|
2381
|
+
...validationError,
|
2382
|
+
message: "Failed to get image metadata",
|
2383
|
+
fixes: undefined
|
2384
|
+
});
|
2385
|
+
} else if (fix === "file:check-metadata") {
|
2386
|
+
const currentValue = validationError.value;
|
2387
|
+
const metadataIsCorrect =
|
2388
|
+
// metadata is a prop that is an object
|
2389
|
+
typeof currentValue === "object" && currentValue && "metadata" in currentValue && currentValue.metadata && typeof currentValue.metadata === "object" &&
|
2390
|
+
// sha256 is correct
|
2391
|
+
"sha256" in currentValue.metadata && currentValue.metadata.sha256 === fileMetadata.sha256 &&
|
2392
|
+
// mimeType is correct
|
2393
|
+
"mimeType" in currentValue.metadata && currentValue.metadata.mimeType === fileMetadata.mimeType;
|
2394
|
+
|
2395
|
+
// skips if the metadata is already correct
|
2396
|
+
if (!metadataIsCorrect) {
|
2397
|
+
if (apply) {
|
2398
|
+
patch.push({
|
2399
|
+
op: "replace",
|
2400
|
+
path: sourceToPatchPath(sourcePath).concat("metadata"),
|
2401
|
+
value: {
|
2402
|
+
sha256: fileMetadata.sha256,
|
2403
|
+
...(fileMetadata.mimeType ? {
|
2404
|
+
mimeType: fileMetadata.mimeType
|
2405
|
+
} : {})
|
2406
|
+
}
|
2407
|
+
});
|
2408
|
+
} else {
|
2409
|
+
if (typeof currentValue === "object" && currentValue && "metadata" in currentValue && currentValue.metadata && typeof currentValue.metadata === "object") {
|
2410
|
+
if (!("sha256" in currentValue.metadata) || currentValue.metadata.sha256 !== fileMetadata.sha256) {
|
2411
|
+
remainingErrors.push({
|
2412
|
+
message: "File metadata sha256 is incorrect! Found: " + ("sha256" in currentValue.metadata ? currentValue.metadata.sha256 : "<empty>") + ". Expected: " + fileMetadata.sha256 + ".",
|
2413
|
+
fixes: undefined
|
2414
|
+
});
|
2415
|
+
}
|
2416
|
+
if (!("mimeType" in currentValue.metadata) || currentValue.metadata.mimeType !== fileMetadata.mimeType) {
|
2417
|
+
remainingErrors.push({
|
2418
|
+
message: "File metadata mimeType is incorrect! Found: " + ("mimeType" in currentValue.metadata ? currentValue.metadata.mimeType : "<empty>") + ". Expected: " + fileMetadata.mimeType,
|
2419
|
+
fixes: undefined
|
2420
|
+
});
|
2421
|
+
}
|
2422
|
+
} else {
|
2423
|
+
remainingErrors.push({
|
2424
|
+
...validationError,
|
2425
|
+
message: "Image metadata is not an object!",
|
2426
|
+
fixes: undefined
|
2427
|
+
});
|
2428
|
+
}
|
2429
|
+
}
|
2430
|
+
}
|
2431
|
+
} else if (fix === "file:add-metadata") {
|
2432
|
+
patch.push({
|
2433
|
+
op: "add",
|
2434
|
+
path: sourceToPatchPath(sourcePath).concat("metadata"),
|
2435
|
+
value: {
|
2436
|
+
sha256: fileMetadata.sha256,
|
2437
|
+
...(fileMetadata.mimeType ? {
|
2438
|
+
mimeType: fileMetadata.mimeType
|
2439
|
+
} : {})
|
2440
|
+
}
|
2441
|
+
});
|
2442
|
+
}
|
2352
2443
|
}
|
2353
2444
|
}
|
2354
2445
|
if (!validationError.fixes || validationError.fixes.length === 0) {
|
package/package.json
CHANGED
@@ -12,7 +12,7 @@
|
|
12
12
|
"./package.json": "./package.json"
|
13
13
|
},
|
14
14
|
"types": "dist/valbuild-server.cjs.d.ts",
|
15
|
-
"version": "0.
|
15
|
+
"version": "0.50.0",
|
16
16
|
"scripts": {
|
17
17
|
"typecheck": "tsc --noEmit",
|
18
18
|
"test": "jest",
|
@@ -24,9 +24,9 @@
|
|
24
24
|
"concurrently": "^7.6.0"
|
25
25
|
},
|
26
26
|
"dependencies": {
|
27
|
-
"@valbuild/core": "~0.
|
28
|
-
"@valbuild/shared": "~0.
|
29
|
-
"@valbuild/ui": "~0.
|
27
|
+
"@valbuild/core": "~0.50.0",
|
28
|
+
"@valbuild/shared": "~0.50.0",
|
29
|
+
"@valbuild/ui": "~0.50.0",
|
30
30
|
"express": "^4.18.2",
|
31
31
|
"image-size": "^1.0.2",
|
32
32
|
"queue": "^6.0.2",
|