@valbuild/server 0.16.4 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/declarations/src/LocalValServer.d.ts +7 -5
- package/dist/declarations/src/ValServer.d.ts +3 -7
- package/dist/declarations/src/hosting.d.ts +34 -0
- package/dist/declarations/src/index.d.ts +1 -1
- package/dist/valbuild-server.cjs.dev.js +249 -95
- package/dist/valbuild-server.cjs.prod.js +249 -95
- package/dist/valbuild-server.esm.js +232 -96
- package/package.json +3 -3
- package/src/LocalValServer.ts +82 -60
- package/src/ProxyValServer.ts +66 -36
- package/src/Service.ts +4 -3
- package/src/ValQuickJSRuntime.ts +18 -0
- package/src/ValServer.ts +4 -11
- package/src/createRequestHandler.ts +6 -6
- package/src/hosting.ts +122 -1
- package/src/index.ts +1 -1
- package/src/patch/ts/ops.test.ts +0 -1
- package/src/readValFile.ts +2 -2
@@ -3,17 +3,19 @@ import { Service } from "./Service.js";
|
|
3
3
|
import { ValServer } from "./ValServer.js";
|
4
4
|
export type LocalValServerOptions = {
|
5
5
|
service: Service;
|
6
|
+
git: {
|
7
|
+
commit?: string;
|
8
|
+
branch?: string;
|
9
|
+
};
|
6
10
|
};
|
7
11
|
export declare class LocalValServer implements ValServer {
|
8
12
|
readonly options: LocalValServerOptions;
|
9
13
|
constructor(options: LocalValServerOptions);
|
10
|
-
getAllModules(req: express.Request, res: express.Response): Promise<void>;
|
11
14
|
session(_req: express.Request, res: express.Response): Promise<void>;
|
15
|
+
getTree(req: express.Request, res: express.Response): Promise<void>;
|
12
16
|
enable(req: express.Request, res: express.Response): Promise<void>;
|
13
|
-
|
14
|
-
|
15
|
-
}>, res: express.Response): Promise<void>;
|
16
|
-
patchIds(req: express.Request<{
|
17
|
+
disable(req: express.Request, res: express.Response): Promise<void>;
|
18
|
+
postPatches(req: express.Request<{
|
17
19
|
0: string;
|
18
20
|
}>, res: express.Response): Promise<void>;
|
19
21
|
private badRequest;
|
@@ -4,15 +4,11 @@ export interface ValServer {
|
|
4
4
|
callback(req: express.Request, res: express.Response): Promise<void>;
|
5
5
|
logout(req: express.Request, res: express.Response): Promise<void>;
|
6
6
|
session(req: express.Request, res: express.Response): Promise<void>;
|
7
|
-
|
8
|
-
0: string;
|
9
|
-
}>, res: express.Response): Promise<void>;
|
10
|
-
getAllModules(req: express.Request<{
|
11
|
-
0: string;
|
12
|
-
}>, res: express.Response): Promise<void>;
|
13
|
-
patchIds(req: express.Request<{
|
7
|
+
postPatches(req: express.Request<{
|
14
8
|
0: string;
|
15
9
|
}>, res: express.Response): Promise<void>;
|
16
10
|
commit(req: express.Request, res: express.Response): Promise<void>;
|
17
11
|
enable(req: express.Request, res: express.Response): Promise<void>;
|
12
|
+
disable(req: express.Request, res: express.Response): Promise<void>;
|
13
|
+
getTree(req: express.Request, res: express.Response): Promise<void>;
|
18
14
|
}
|
@@ -66,6 +66,16 @@ type ValServerOverrides = Partial<{
|
|
66
66
|
* @example "https://app.val.build"
|
67
67
|
*/
|
68
68
|
valBuildUrl: string;
|
69
|
+
/**
|
70
|
+
* The base url of Val content.
|
71
|
+
*
|
72
|
+
* Typically this should not be set.
|
73
|
+
*
|
74
|
+
* Can also be overridden using the VAL_CONTENT_URL env var.
|
75
|
+
*
|
76
|
+
* @example "https://content.val.build"
|
77
|
+
*/
|
78
|
+
valContentUrl: string;
|
69
79
|
/**
|
70
80
|
* The full name of this Val project.
|
71
81
|
*
|
@@ -74,6 +84,30 @@ type ValServerOverrides = Partial<{
|
|
74
84
|
* @example "myorg/my-project"
|
75
85
|
*/
|
76
86
|
valName: string;
|
87
|
+
/**
|
88
|
+
* After Val is enabled, redirect to this url.
|
89
|
+
*
|
90
|
+
* May be used to setup a custom flow after enabling Val.
|
91
|
+
*
|
92
|
+
*This can be set using the VAL_ENABLE_REDIRECT_URL env var.
|
93
|
+
*
|
94
|
+
* @example "/api/draft/enable"
|
95
|
+
*/
|
96
|
+
valEnableRedirectUrl?: string;
|
97
|
+
/**
|
98
|
+
* After Val is disabled, redirect to this url.
|
99
|
+
*
|
100
|
+
* May be used to setup a custom flow after disabling Val.
|
101
|
+
*
|
102
|
+
* This can be set using the VAL_DISABLE_REDIRECT_URL env var.
|
103
|
+
*
|
104
|
+
* @example "/api/draft/enable"
|
105
|
+
*/
|
106
|
+
valDisableRedirectUrl?: string;
|
107
|
+
}>;
|
108
|
+
export declare function safeReadGit(cwd: string): Promise<{
|
109
|
+
commit?: string;
|
110
|
+
branch?: string;
|
77
111
|
}>;
|
78
112
|
export declare function createRequestListener(route: string, opts: Opts): RequestListener;
|
79
113
|
export {};
|
@@ -1,7 +1,7 @@
|
|
1
1
|
export type { ServiceOptions } from "./Service.js";
|
2
2
|
export { createService, Service } from "./Service.js";
|
3
3
|
export { createRequestHandler } from "./createRequestHandler.js";
|
4
|
-
export { createRequestListener } from "./hosting.js";
|
4
|
+
export { createRequestListener, safeReadGit } from "./hosting.js";
|
5
5
|
export { ValModuleLoader } from "./ValModuleLoader.js";
|
6
6
|
export { getCompilerOptions } from "./getCompilerOptions.js";
|
7
7
|
export { ValSourceFileHandler } from "./ValSourceFileHandler.js";
|
@@ -17,8 +17,26 @@ var sizeOf = require('image-size');
|
|
17
17
|
|
18
18
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
19
19
|
|
20
|
+
function _interopNamespace(e) {
|
21
|
+
if (e && e.__esModule) return e;
|
22
|
+
var n = Object.create(null);
|
23
|
+
if (e) {
|
24
|
+
Object.keys(e).forEach(function (k) {
|
25
|
+
if (k !== 'default') {
|
26
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
27
|
+
Object.defineProperty(n, k, d.get ? d : {
|
28
|
+
enumerable: true,
|
29
|
+
get: function () { return e[k]; }
|
30
|
+
});
|
31
|
+
}
|
32
|
+
});
|
33
|
+
}
|
34
|
+
n["default"] = e;
|
35
|
+
return Object.freeze(n);
|
36
|
+
}
|
37
|
+
|
20
38
|
var ts__default = /*#__PURE__*/_interopDefault(ts);
|
21
|
-
var
|
39
|
+
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
22
40
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
23
41
|
var express__default = /*#__PURE__*/_interopDefault(express);
|
24
42
|
var z__default = /*#__PURE__*/_interopDefault(z);
|
@@ -572,16 +590,16 @@ import { Internal } from "@valbuild/core";
|
|
572
590
|
globalThis.valModule = {
|
573
591
|
id: valModule?.default && Internal.getValPath(valModule?.default),
|
574
592
|
schema: valModule?.default && Internal.getSchema(valModule?.default)?.serialize(),
|
575
|
-
source: valModule?.default && Internal.
|
593
|
+
source: valModule?.default && Internal.getSource(valModule?.default),
|
576
594
|
validation: valModule?.default && Internal.getSchema(valModule?.default)?.validate(
|
577
595
|
valModule?.default && Internal.getValPath(valModule?.default) || "/",
|
578
|
-
valModule?.default && Internal.
|
596
|
+
valModule?.default && Internal.getSource(valModule?.default)
|
579
597
|
)
|
580
598
|
};
|
581
599
|
`;
|
582
600
|
const result = context.evalCode(code,
|
583
601
|
// Synthetic module name
|
584
|
-
|
602
|
+
path__namespace["default"].join(path__namespace["default"].dirname(valConfigPath), "<val>"));
|
585
603
|
const fatalErrors = [];
|
586
604
|
if (result.error) {
|
587
605
|
const error = result.error.consume(context.dump);
|
@@ -693,8 +711,8 @@ const patchSourceFile = (sourceFile, patch$1) => {
|
|
693
711
|
};
|
694
712
|
|
695
713
|
const getCompilerOptions = (rootDir, parseConfigHost) => {
|
696
|
-
const tsConfigPath =
|
697
|
-
const jsConfigPath =
|
714
|
+
const tsConfigPath = path__namespace["default"].resolve(rootDir, "tsconfig.json");
|
715
|
+
const jsConfigPath = path__namespace["default"].resolve(rootDir, "jsconfig.json");
|
698
716
|
let configFilePath;
|
699
717
|
if (parseConfigHost.fileExists(jsConfigPath)) {
|
700
718
|
configFilePath = jsConfigPath;
|
@@ -744,7 +762,7 @@ class ValSourceFileHandler {
|
|
744
762
|
this.host.writeFile(filePath, content, encoding);
|
745
763
|
}
|
746
764
|
resolveSourceModulePath(containingFilePath, requestedModuleName) {
|
747
|
-
const resolutionRes = ts__default["default"].resolveModuleName(requestedModuleName,
|
765
|
+
const resolutionRes = ts__default["default"].resolveModuleName(requestedModuleName, path__namespace["default"].isAbsolute(containingFilePath) ? containingFilePath : path__namespace["default"].resolve(this.projectRoot, containingFilePath), this.compilerOptions, this.host, undefined, undefined, ts__default["default"].ModuleKind.ESNext);
|
748
766
|
const resolvedModule = resolutionRes.resolvedModule;
|
749
767
|
if (!resolvedModule) {
|
750
768
|
throw Error(`Could not resolve module "${requestedModuleName}", base: "${containingFilePath}": No resolved modules returned: ${JSON.stringify(resolutionRes)}`);
|
@@ -864,6 +882,16 @@ async function newValQuickJSRuntime(quickJSModule, moduleLoader, {
|
|
864
882
|
value: "export const useVal = () => { throw Error(`Cannot use 'useVal' in this type of file`) }; export const fetchVal = () => { throw Error(`Cannot use 'fetchVal' in this type of file`) }; export const autoTagJSX = () => { /* ignore */ };"
|
865
883
|
};
|
866
884
|
}
|
885
|
+
if (modulePath.startsWith("next")) {
|
886
|
+
return {
|
887
|
+
value: "export default new Proxy({}, { get() { return () => { throw new Error(`Cannot import 'next' in this file`) } } } )"
|
888
|
+
};
|
889
|
+
}
|
890
|
+
if (modulePath.startsWith("react")) {
|
891
|
+
return {
|
892
|
+
value: "export default new Proxy({}, { get() { return () => { throw new Error(`Cannot import 'react' in this file`) } } } )"
|
893
|
+
};
|
894
|
+
}
|
867
895
|
return {
|
868
896
|
value: moduleLoader.getModule(modulePath)
|
869
897
|
};
|
@@ -884,6 +912,16 @@ async function newValQuickJSRuntime(quickJSModule, moduleLoader, {
|
|
884
912
|
value: requestedName
|
885
913
|
};
|
886
914
|
}
|
915
|
+
if (requestedName.startsWith("next")) {
|
916
|
+
return {
|
917
|
+
value: requestedName
|
918
|
+
};
|
919
|
+
}
|
920
|
+
if (requestedName.startsWith("react")) {
|
921
|
+
return {
|
922
|
+
value: requestedName
|
923
|
+
};
|
924
|
+
}
|
887
925
|
const modulePath = moduleLoader.resolveModulePath(baseModuleName, requestedName);
|
888
926
|
return {
|
889
927
|
value: modulePath
|
@@ -920,7 +958,7 @@ class Service {
|
|
920
958
|
const valModule = await readValFile(moduleId, this.valConfigPath, this.runtime);
|
921
959
|
if (valModule.source && valModule.schema) {
|
922
960
|
const resolved = core.Internal.resolvePath(modulePath, valModule.source, valModule.schema);
|
923
|
-
const sourcePath = [moduleId, resolved.path].join(".");
|
961
|
+
const sourcePath = resolved.path ? [moduleId, resolved.path].join(".") : moduleId;
|
924
962
|
return {
|
925
963
|
path: sourcePath,
|
926
964
|
schema: resolved.schema instanceof core.Schema ? resolved.schema.serialize() : resolved.schema,
|
@@ -951,14 +989,14 @@ function createRequestHandler(valServer) {
|
|
951
989
|
router.get("/authorize", valServer.authorize.bind(valServer));
|
952
990
|
router.get("/callback", valServer.callback.bind(valServer));
|
953
991
|
router.get("/logout", valServer.logout.bind(valServer));
|
954
|
-
router.
|
955
|
-
|
956
|
-
router.patch("/ids/*", express__default["default"].json({
|
957
|
-
type: "application/json-patch+json",
|
992
|
+
router.post("/patches/*", express__default["default"].json({
|
993
|
+
type: "application/json",
|
958
994
|
limit: "10mb"
|
959
|
-
}), valServer.
|
995
|
+
}), valServer.postPatches.bind(valServer));
|
960
996
|
router.post("/commit", valServer.commit.bind(valServer));
|
961
997
|
router.get("/enable", valServer.enable.bind(valServer));
|
998
|
+
router.get("/disable", valServer.disable.bind(valServer));
|
999
|
+
router.get("/tree/*", valServer.getTree.bind(valServer));
|
962
1000
|
return router;
|
963
1001
|
}
|
964
1002
|
|
@@ -1062,19 +1100,13 @@ function encodeJwt(payload, sessionKey) {
|
|
1062
1100
|
return `${jwtHeaderBase64}.${payloadBase64}.${crypto__default["default"].createHmac("sha256", sessionKey).update(`${jwtHeaderBase64}.${payloadBase64}`).digest("base64")}`;
|
1063
1101
|
}
|
1064
1102
|
|
1065
|
-
const VAL_SESSION_COOKIE =
|
1066
|
-
const VAL_STATE_COOKIE =
|
1103
|
+
const VAL_SESSION_COOKIE = core.Internal.VAL_SESSION_COOKIE;
|
1104
|
+
const VAL_STATE_COOKIE = core.Internal.VAL_STATE_COOKIE;
|
1067
1105
|
const VAL_ENABLED_COOKIE = core.Internal.VAL_ENABLE_COOKIE_NAME;
|
1068
1106
|
class ProxyValServer {
|
1069
1107
|
constructor(options) {
|
1070
1108
|
this.options = options;
|
1071
1109
|
}
|
1072
|
-
|
1073
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
1074
|
-
getAllModules(_req, _res) {
|
1075
|
-
// TODO:
|
1076
|
-
throw new Error("Method not implemented.");
|
1077
|
-
}
|
1078
1110
|
async authorize(req, res) {
|
1079
1111
|
const {
|
1080
1112
|
redirect_to
|
@@ -1096,7 +1128,10 @@ class ProxyValServer {
|
|
1096
1128
|
}).redirect(appAuthorizeUrl);
|
1097
1129
|
}
|
1098
1130
|
async enable(req, res) {
|
1099
|
-
return enable(req, res);
|
1131
|
+
return enable(req, res, this.options.valEnableRedirectUrl);
|
1132
|
+
}
|
1133
|
+
async disable(req, res) {
|
1134
|
+
return disable(req, res, this.options.valEnableRedirectUrl);
|
1100
1135
|
}
|
1101
1136
|
async callback(req, res) {
|
1102
1137
|
const {
|
@@ -1158,30 +1193,38 @@ class ProxyValServer {
|
|
1158
1193
|
}
|
1159
1194
|
});
|
1160
1195
|
}
|
1161
|
-
async
|
1162
|
-
return this.withAuth(req, res, async
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
} else {
|
1173
|
-
res.sendStatus(fetchRes.status);
|
1174
|
-
}
|
1175
|
-
}).catch(e => {
|
1176
|
-
res.status(500).send({
|
1177
|
-
error: {
|
1178
|
-
message: e === null || e === void 0 ? void 0 : e.message,
|
1179
|
-
status: 500
|
1180
|
-
}
|
1196
|
+
async getTree(req, res) {
|
1197
|
+
return this.withAuth(req, res, async data => {
|
1198
|
+
const {
|
1199
|
+
patch,
|
1200
|
+
schema,
|
1201
|
+
source
|
1202
|
+
} = req.query;
|
1203
|
+
const params = new URLSearchParams({
|
1204
|
+
patch: (patch === "true").toString(),
|
1205
|
+
schema: (schema === "true").toString(),
|
1206
|
+
source: (source === "true").toString()
|
1181
1207
|
});
|
1208
|
+
const url = new URL(`/v1/tree/${this.options.valName}/heads/${this.options.gitBranch}/${req.params["0"]}/?${params}`, this.options.valContentUrl);
|
1209
|
+
const json = await fetch(url, {
|
1210
|
+
headers: this.getAuthHeaders(data.token, "application/json")
|
1211
|
+
}).then(res => res.json());
|
1212
|
+
res.send(json);
|
1182
1213
|
});
|
1183
1214
|
}
|
1184
|
-
async
|
1215
|
+
async postPatches(req, res) {
|
1216
|
+
const {
|
1217
|
+
commit
|
1218
|
+
} = req.query;
|
1219
|
+
if (typeof commit !== "string" || typeof commit === "undefined") {
|
1220
|
+
res.status(401).json({
|
1221
|
+
error: "Missing or invalid commit query param"
|
1222
|
+
});
|
1223
|
+
return;
|
1224
|
+
}
|
1225
|
+
const params = new URLSearchParams({
|
1226
|
+
commit
|
1227
|
+
});
|
1185
1228
|
this.withAuth(req, res, async ({
|
1186
1229
|
token
|
1187
1230
|
}) => {
|
@@ -1197,12 +1240,11 @@ class ProxyValServer {
|
|
1197
1240
|
res.status(401).json(patch$1.error);
|
1198
1241
|
return;
|
1199
1242
|
}
|
1200
|
-
const
|
1201
|
-
const url = new URL(`/api/val/modules/${encodeURIComponent(this.options.gitCommit)}${id}`, this.options.valBuildUrl);
|
1243
|
+
const url = new URL(`/v1/tree/${this.options.valName}/heads/${this.options.gitBranch}/${req.params["0"]}/?${params}`, this.options.valContentUrl);
|
1202
1244
|
// Proxy patch to val.build
|
1203
1245
|
const fetchRes = await fetch(url, {
|
1204
|
-
method: "
|
1205
|
-
headers: this.getAuthHeaders(token, "application/json
|
1246
|
+
method: "POST",
|
1247
|
+
headers: this.getAuthHeaders(token, "application/json"),
|
1206
1248
|
body: JSON.stringify(patch$1)
|
1207
1249
|
});
|
1208
1250
|
if (fetchRes.ok) {
|
@@ -1384,15 +1426,36 @@ function getStateFromCookie(stateCookie) {
|
|
1384
1426
|
};
|
1385
1427
|
}
|
1386
1428
|
}
|
1387
|
-
async function enable(req, res) {
|
1429
|
+
async function enable(req, res, redirectUrl) {
|
1388
1430
|
const {
|
1389
1431
|
redirect_to
|
1390
1432
|
} = req.query;
|
1391
1433
|
if (typeof redirect_to === "string" || typeof redirect_to === "undefined") {
|
1434
|
+
let redirectUrlToUse = redirect_to || "/";
|
1435
|
+
if (redirectUrl) {
|
1436
|
+
redirectUrlToUse = redirectUrl + "?redirect_to=" + encodeURIComponent(redirectUrlToUse);
|
1437
|
+
}
|
1392
1438
|
res.cookie(VAL_ENABLED_COOKIE, "true", {
|
1393
1439
|
httpOnly: false,
|
1394
1440
|
sameSite: "lax"
|
1395
|
-
}).redirect(
|
1441
|
+
}).redirect(redirectUrlToUse);
|
1442
|
+
} else {
|
1443
|
+
res.sendStatus(400);
|
1444
|
+
}
|
1445
|
+
}
|
1446
|
+
async function disable(req, res, redirectUrl) {
|
1447
|
+
const {
|
1448
|
+
redirect_to
|
1449
|
+
} = req.query;
|
1450
|
+
if (typeof redirect_to === "string" || typeof redirect_to === "undefined") {
|
1451
|
+
let redirectUrlToUse = redirect_to || "/";
|
1452
|
+
if (redirectUrl) {
|
1453
|
+
redirectUrlToUse = redirectUrl + "?redirect_to=" + encodeURIComponent(redirectUrlToUse);
|
1454
|
+
}
|
1455
|
+
res.cookie(VAL_ENABLED_COOKIE, "false", {
|
1456
|
+
httpOnly: false,
|
1457
|
+
sameSite: "lax"
|
1458
|
+
}).redirect(redirectUrlToUse);
|
1396
1459
|
} else {
|
1397
1460
|
res.sendStatus(400);
|
1398
1461
|
}
|
@@ -1418,53 +1481,75 @@ class LocalValServer {
|
|
1418
1481
|
constructor(options) {
|
1419
1482
|
this.options = options;
|
1420
1483
|
}
|
1421
|
-
getAllModules(req, res) {
|
1422
|
-
// TODO: this barely works,
|
1423
|
-
const rootDir = process.cwd();
|
1424
|
-
const moduleIds = [];
|
1425
|
-
// iterate over all .val files in the root directory
|
1426
|
-
const walk = async dir => {
|
1427
|
-
const files = await fs.promises.readdir(dir);
|
1428
|
-
for (const file of files) {
|
1429
|
-
if ((await fs.promises.stat(path__default["default"].join(dir, file))).isDirectory()) {
|
1430
|
-
if (file === "node_modules") continue;
|
1431
|
-
await walk(path__default["default"].join(dir, file));
|
1432
|
-
} else {
|
1433
|
-
if (file.endsWith(".val.js") || file.endsWith(".val.ts")) {
|
1434
|
-
moduleIds.push(path__default["default"].join(dir, file).replace(rootDir, "").replace(".val.js", "").replace(".val.ts", ""));
|
1435
|
-
}
|
1436
|
-
}
|
1437
|
-
}
|
1438
|
-
};
|
1439
|
-
return walk(rootDir).then(async () => {
|
1440
|
-
res.send(JSON.stringify(await Promise.all(moduleIds.map(async moduleId => {
|
1441
|
-
return await this.options.service.get(moduleId, "");
|
1442
|
-
}))));
|
1443
|
-
});
|
1444
|
-
}
|
1445
1484
|
async session(_req, res) {
|
1446
1485
|
res.json({
|
1447
1486
|
mode: "local"
|
1448
1487
|
});
|
1449
1488
|
}
|
1450
|
-
async
|
1451
|
-
return enable(req, res);
|
1452
|
-
}
|
1453
|
-
async getIds(req, res) {
|
1489
|
+
async getTree(req, res) {
|
1454
1490
|
try {
|
1455
|
-
|
1456
|
-
const
|
1457
|
-
const
|
1458
|
-
const
|
1459
|
-
|
1491
|
+
// TODO: use the params: patch, schema, source
|
1492
|
+
const treePath = req.params["0"].replace("~", "");
|
1493
|
+
const rootDir = process.cwd();
|
1494
|
+
const moduleIds = [];
|
1495
|
+
// iterate over all .val files in the root directory
|
1496
|
+
const walk = async dir => {
|
1497
|
+
const files = await fs.promises.readdir(dir);
|
1498
|
+
for (const file of files) {
|
1499
|
+
if ((await fs.promises.stat(path__namespace["default"].join(dir, file))).isDirectory()) {
|
1500
|
+
if (file === "node_modules") continue;
|
1501
|
+
await walk(path__namespace["default"].join(dir, file));
|
1502
|
+
} else {
|
1503
|
+
const isValFile = file.endsWith(".val.js") || file.endsWith(".val.ts");
|
1504
|
+
if (!isValFile) {
|
1505
|
+
continue;
|
1506
|
+
}
|
1507
|
+
if (treePath && !path__namespace["default"].join(dir, file).replace(rootDir, "").startsWith(treePath)) {
|
1508
|
+
continue;
|
1509
|
+
}
|
1510
|
+
moduleIds.push(path__namespace["default"].join(dir, file).replace(rootDir, "").replace(".val.js", "").replace(".val.ts", ""));
|
1511
|
+
}
|
1512
|
+
}
|
1513
|
+
};
|
1514
|
+
const serializedModuleContent = await walk(rootDir).then(async () => {
|
1515
|
+
return Promise.all(moduleIds.map(async moduleId => {
|
1516
|
+
return await this.options.service.get(moduleId, "");
|
1517
|
+
}));
|
1518
|
+
});
|
1519
|
+
|
1520
|
+
//
|
1521
|
+
const modules = Object.fromEntries(serializedModuleContent.map(serializedModuleContent => {
|
1522
|
+
const module = {
|
1523
|
+
schema: serializedModuleContent.schema,
|
1524
|
+
source: serializedModuleContent.source
|
1525
|
+
};
|
1526
|
+
return [serializedModuleContent.path, module];
|
1527
|
+
}));
|
1528
|
+
const apiTreeResponse = {
|
1529
|
+
modules,
|
1530
|
+
git: this.options.git
|
1531
|
+
};
|
1532
|
+
return walk(rootDir).then(async () => {
|
1533
|
+
res.send(JSON.stringify(apiTreeResponse));
|
1534
|
+
});
|
1460
1535
|
} catch (err) {
|
1461
1536
|
console.error(err);
|
1462
1537
|
res.sendStatus(500);
|
1463
1538
|
}
|
1464
1539
|
}
|
1465
|
-
async
|
1540
|
+
async enable(req, res) {
|
1541
|
+
return enable(req, res);
|
1542
|
+
}
|
1543
|
+
async disable(req, res) {
|
1544
|
+
return disable(req, res);
|
1545
|
+
}
|
1546
|
+
async postPatches(req, res) {
|
1547
|
+
var _getPathFromParams;
|
1548
|
+
const id = (_getPathFromParams = getPathFromParams(req.params)) === null || _getPathFromParams === void 0 ? void 0 : _getPathFromParams.replace("/~", "");
|
1549
|
+
|
1466
1550
|
// First validate that the body has the right structure
|
1467
1551
|
const patchJSON = PatchJSON.safeParse(req.body);
|
1552
|
+
console.log("patch id", id, patchJSON);
|
1468
1553
|
if (!patchJSON.success) {
|
1469
1554
|
res.status(401).json(patchJSON.error.issues);
|
1470
1555
|
return;
|
@@ -1475,16 +1560,19 @@ class LocalValServer {
|
|
1475
1560
|
res.status(401).json(patch$1.error);
|
1476
1561
|
return;
|
1477
1562
|
}
|
1478
|
-
const id = getPathFromParams(req.params);
|
1479
1563
|
try {
|
1480
|
-
|
1481
|
-
res.json(
|
1564
|
+
await this.options.service.patch(id, patch$1.value);
|
1565
|
+
res.json({});
|
1482
1566
|
} catch (err) {
|
1483
1567
|
if (err instanceof patch.PatchError) {
|
1484
|
-
res.status(
|
1568
|
+
res.status(400).send({
|
1569
|
+
message: err.message
|
1570
|
+
});
|
1485
1571
|
} else {
|
1486
1572
|
console.error(err);
|
1487
|
-
res.status(500).send(
|
1573
|
+
res.status(500).send({
|
1574
|
+
message: err instanceof Error ? err.message : "Unknown error"
|
1575
|
+
});
|
1488
1576
|
}
|
1489
1577
|
}
|
1490
1578
|
}
|
@@ -1526,6 +1614,7 @@ async function initHandlerOptions(route, opts) {
|
|
1526
1614
|
if (!maybeApiKey || !maybeValSecret) {
|
1527
1615
|
throw new Error("VAL_API_KEY and VAL_SECRET env vars must both be set in proxy mode");
|
1528
1616
|
}
|
1617
|
+
const valContentUrl = opts.valContentUrl || process.env.VAL_CONTENT_URL || "https://content.val.build";
|
1529
1618
|
const maybeGitCommit = opts.gitCommit || process.env.VAL_GIT_COMMIT;
|
1530
1619
|
if (!maybeGitCommit) {
|
1531
1620
|
throw new Error("VAL_GIT_COMMIT env var must be set in proxy mode");
|
@@ -1544,18 +1633,82 @@ async function initHandlerOptions(route, opts) {
|
|
1544
1633
|
apiKey: maybeApiKey,
|
1545
1634
|
valSecret: maybeValSecret,
|
1546
1635
|
valBuildUrl,
|
1636
|
+
valContentUrl,
|
1547
1637
|
gitCommit: maybeGitCommit,
|
1548
1638
|
gitBranch: maybeGitBranch,
|
1549
|
-
valName: maybeValName
|
1639
|
+
valName: maybeValName,
|
1640
|
+
valEnableRedirectUrl: opts.valEnableRedirectUrl || process.env.VAL_ENABLE_REDIRECT_URL,
|
1641
|
+
valDisableRedirectUrl: opts.valDisableRedirectUrl || process.env.VAL_DISABLE_REDIRECT_URL
|
1550
1642
|
};
|
1551
1643
|
} else {
|
1552
|
-
const
|
1644
|
+
const cwd = process.cwd();
|
1645
|
+
const service = await createService(cwd, opts);
|
1646
|
+
const git = await safeReadGit(cwd);
|
1553
1647
|
return {
|
1554
1648
|
mode: "local",
|
1555
|
-
service
|
1649
|
+
service,
|
1650
|
+
git: {
|
1651
|
+
commit: process.env.VAL_GIT_COMMIT || git.commit,
|
1652
|
+
branch: process.env.VAL_GIT_BRANCH || git.branch
|
1653
|
+
}
|
1556
1654
|
};
|
1557
1655
|
}
|
1558
1656
|
}
|
1657
|
+
async function safeReadGit(cwd) {
|
1658
|
+
async function findGitHead(currentDir, depth) {
|
1659
|
+
const gitHeadPath = path__namespace.join(currentDir, ".git", "HEAD");
|
1660
|
+
if (depth > 1000) {
|
1661
|
+
console.error(`Reached max depth while scanning for .git folder. Current working dir: ${cwd}.`);
|
1662
|
+
return {
|
1663
|
+
commit: undefined,
|
1664
|
+
branch: undefined
|
1665
|
+
};
|
1666
|
+
}
|
1667
|
+
try {
|
1668
|
+
const headContents = await fs.promises.readFile(gitHeadPath, "utf-8");
|
1669
|
+
const match = headContents.match(/^ref: refs\/heads\/(.+)/);
|
1670
|
+
if (match) {
|
1671
|
+
const branchName = match[1];
|
1672
|
+
return {
|
1673
|
+
branch: branchName,
|
1674
|
+
commit: await readCommit(currentDir, branchName)
|
1675
|
+
};
|
1676
|
+
} else {
|
1677
|
+
return {
|
1678
|
+
commit: undefined,
|
1679
|
+
branch: undefined
|
1680
|
+
};
|
1681
|
+
}
|
1682
|
+
} catch (error) {
|
1683
|
+
const parentDir = path__namespace.dirname(currentDir);
|
1684
|
+
|
1685
|
+
// We've reached the root directory
|
1686
|
+
if (parentDir === currentDir) {
|
1687
|
+
return {
|
1688
|
+
commit: undefined,
|
1689
|
+
branch: undefined
|
1690
|
+
};
|
1691
|
+
}
|
1692
|
+
return findGitHead(parentDir, depth + 1);
|
1693
|
+
}
|
1694
|
+
}
|
1695
|
+
try {
|
1696
|
+
return findGitHead(cwd, 0);
|
1697
|
+
} catch (err) {
|
1698
|
+
console.error("Error while reading .git", err);
|
1699
|
+
return {
|
1700
|
+
commit: undefined,
|
1701
|
+
branch: undefined
|
1702
|
+
};
|
1703
|
+
}
|
1704
|
+
}
|
1705
|
+
async function readCommit(gitDir, branchName) {
|
1706
|
+
try {
|
1707
|
+
return (await fs.promises.readFile(path__namespace.join(gitDir, ".git", "refs", "heads", branchName), "utf-8")).trim();
|
1708
|
+
} catch (err) {
|
1709
|
+
return undefined;
|
1710
|
+
}
|
1711
|
+
}
|
1559
1712
|
|
1560
1713
|
// TODO: rename to createValApiHandlers?
|
1561
1714
|
function createRequestListener(route, opts) {
|
@@ -1593,10 +1746,10 @@ class ValFSHost {
|
|
1593
1746
|
return this.currentDirectory;
|
1594
1747
|
}
|
1595
1748
|
getCanonicalFileName(fileName) {
|
1596
|
-
if (
|
1597
|
-
return
|
1749
|
+
if (path__namespace["default"].isAbsolute(fileName)) {
|
1750
|
+
return path__namespace["default"].normalize(fileName);
|
1598
1751
|
}
|
1599
|
-
return
|
1752
|
+
return path__namespace["default"].resolve(this.getCurrentDirectory(), fileName);
|
1600
1753
|
}
|
1601
1754
|
fileExists(fileName) {
|
1602
1755
|
return this.valFS.fileExists(fileName);
|
@@ -1617,7 +1770,7 @@ async function createFixPatch(config, apply, sourcePath, validationError) {
|
|
1617
1770
|
// TODO:
|
1618
1771
|
throw Error("Cannot fix image without a file reference");
|
1619
1772
|
}
|
1620
|
-
const localFile =
|
1773
|
+
const localFile = path__namespace["default"].join(config.projectRoot, maybeRef);
|
1621
1774
|
const buffer = fs__default["default"].readFileSync(localFile);
|
1622
1775
|
const sha256 = await getSHA256Hash(buffer);
|
1623
1776
|
const imageSize = sizeOf__default["default"](buffer);
|
@@ -1734,3 +1887,4 @@ exports.formatSyntaxErrorTree = formatSyntaxErrorTree;
|
|
1734
1887
|
exports.getCompilerOptions = getCompilerOptions;
|
1735
1888
|
exports.getExpire = getExpire;
|
1736
1889
|
exports.patchSourceFile = patchSourceFile;
|
1890
|
+
exports.safeReadGit = safeReadGit;
|