@valbuild/server 0.16.2 → 0.16.4
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 +2 -0
- package/dist/declarations/src/ValServer.d.ts +4 -0
- package/dist/declarations/src/jwt.d.ts +7 -1
- package/dist/declarations/src/patchValFile.d.ts +1 -1
- package/dist/valbuild-server.cjs.dev.js +124 -70
- package/dist/valbuild-server.cjs.prod.js +124 -70
- package/dist/valbuild-server.esm.js +125 -71
- package/package.json +1 -1
- package/src/LocalValServer.ts +50 -2
- package/src/ProxyValServer.ts +29 -1
- package/src/ValServer.ts +7 -0
- package/src/createRequestHandler.ts +2 -0
- package/src/jwt.ts +12 -2
- package/src/patchValFile.ts +8 -1
|
@@ -7,7 +7,9 @@ export type LocalValServerOptions = {
|
|
|
7
7
|
export declare class LocalValServer implements ValServer {
|
|
8
8
|
readonly options: LocalValServerOptions;
|
|
9
9
|
constructor(options: LocalValServerOptions);
|
|
10
|
+
getAllModules(req: express.Request, res: express.Response): Promise<void>;
|
|
10
11
|
session(_req: express.Request, res: express.Response): Promise<void>;
|
|
12
|
+
enable(req: express.Request, res: express.Response): Promise<void>;
|
|
11
13
|
getIds(req: express.Request<{
|
|
12
14
|
0: string;
|
|
13
15
|
}>, res: express.Response): Promise<void>;
|
|
@@ -7,8 +7,12 @@ export interface ValServer {
|
|
|
7
7
|
getIds(req: express.Request<{
|
|
8
8
|
0: string;
|
|
9
9
|
}>, res: express.Response): Promise<void>;
|
|
10
|
+
getAllModules(req: express.Request<{
|
|
11
|
+
0: string;
|
|
12
|
+
}>, res: express.Response): Promise<void>;
|
|
10
13
|
patchIds(req: express.Request<{
|
|
11
14
|
0: string;
|
|
12
15
|
}>, res: express.Response): Promise<void>;
|
|
13
16
|
commit(req: express.Request, res: express.Response): Promise<void>;
|
|
17
|
+
enable(req: express.Request, res: express.Response): Promise<void>;
|
|
14
18
|
}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type JwtPayload = {
|
|
2
|
+
sub: string;
|
|
3
|
+
exp: number;
|
|
4
|
+
org: string;
|
|
5
|
+
project: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function decodeJwt(token: string, secretKey?: string): JwtPayload | null;
|
|
2
8
|
export declare function getExpire(): number;
|
|
3
9
|
export declare function encodeJwt(payload: object, sessionKey: string): string;
|
|
@@ -6,4 +6,4 @@ import { QuickJSRuntime } from "quickjs-emscripten";
|
|
|
6
6
|
import ts from "typescript";
|
|
7
7
|
import { SerializedModuleContent } from "./SerializedModuleContent.js";
|
|
8
8
|
export declare const patchValFile: (id: string, valConfigPath: string, patch: Patch, sourceFileHandler: ValSourceFileHandler, runtime: QuickJSRuntime) => Promise<SerializedModuleContent>;
|
|
9
|
-
export declare const patchSourceFile: (sourceFile: ts.SourceFile, patch: Patch) => result.Result<ts.SourceFile, ValSyntaxErrorTree | PatchError>;
|
|
9
|
+
export declare const patchSourceFile: (sourceFile: ts.SourceFile | string, patch: Patch) => result.Result<ts.SourceFile, ValSyntaxErrorTree | PatchError>;
|
|
@@ -686,6 +686,9 @@ function convertDataUrlToBase64(dataUrl) {
|
|
|
686
686
|
return Buffer.from(base64, "base64");
|
|
687
687
|
}
|
|
688
688
|
const patchSourceFile = (sourceFile, patch$1) => {
|
|
689
|
+
if (typeof sourceFile === "string") {
|
|
690
|
+
return patch.applyPatch(ts__default["default"].createSourceFile("<val>", sourceFile, ts__default["default"].ScriptTarget.ES2015), ops, patch$1);
|
|
691
|
+
}
|
|
689
692
|
return patch.applyPatch(sourceFile, ops, patch$1);
|
|
690
693
|
};
|
|
691
694
|
|
|
@@ -949,14 +952,20 @@ function createRequestHandler(valServer) {
|
|
|
949
952
|
router.get("/callback", valServer.callback.bind(valServer));
|
|
950
953
|
router.get("/logout", valServer.logout.bind(valServer));
|
|
951
954
|
router.get("/ids/*", valServer.getIds.bind(valServer));
|
|
955
|
+
router.get("/ids", valServer.getAllModules.bind(valServer));
|
|
952
956
|
router.patch("/ids/*", express__default["default"].json({
|
|
953
957
|
type: "application/json-patch+json",
|
|
954
958
|
limit: "10mb"
|
|
955
959
|
}), valServer.patchIds.bind(valServer));
|
|
956
960
|
router.post("/commit", valServer.commit.bind(valServer));
|
|
961
|
+
router.get("/enable", valServer.enable.bind(valServer));
|
|
957
962
|
return router;
|
|
958
963
|
}
|
|
959
964
|
|
|
965
|
+
function getPathFromParams(params) {
|
|
966
|
+
return `/${params[0]}`;
|
|
967
|
+
}
|
|
968
|
+
|
|
960
969
|
const JSONValueT = z__default["default"].lazy(() => z__default["default"].union([z__default["default"].string(), z__default["default"].number(), z__default["default"].boolean(), z__default["default"].null(), z__default["default"].array(JSONValueT), z__default["default"].record(JSONValueT)]));
|
|
961
970
|
|
|
962
971
|
/**
|
|
@@ -994,75 +1003,6 @@ const OperationJSONT = z__default["default"].discriminatedUnion("op", [z__defaul
|
|
|
994
1003
|
}).strict()]);
|
|
995
1004
|
const PatchJSON = z__default["default"].array(OperationJSONT);
|
|
996
1005
|
|
|
997
|
-
function getPathFromParams(params) {
|
|
998
|
-
return `/${params[0]}`;
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
class LocalValServer {
|
|
1002
|
-
constructor(options) {
|
|
1003
|
-
this.options = options;
|
|
1004
|
-
}
|
|
1005
|
-
async session(_req, res) {
|
|
1006
|
-
res.json({
|
|
1007
|
-
mode: "local"
|
|
1008
|
-
});
|
|
1009
|
-
}
|
|
1010
|
-
async getIds(req, res) {
|
|
1011
|
-
try {
|
|
1012
|
-
console.log(req.params);
|
|
1013
|
-
const path = getPathFromParams(req.params);
|
|
1014
|
-
const [moduleId, modulePath] = core.Internal.splitModuleIdAndModulePath(path);
|
|
1015
|
-
const valModule = await this.options.service.get(moduleId, modulePath);
|
|
1016
|
-
res.json(valModule);
|
|
1017
|
-
} catch (err) {
|
|
1018
|
-
console.error(err);
|
|
1019
|
-
res.sendStatus(500);
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
async patchIds(req, res) {
|
|
1023
|
-
// First validate that the body has the right structure
|
|
1024
|
-
const patchJSON = PatchJSON.safeParse(req.body);
|
|
1025
|
-
if (!patchJSON.success) {
|
|
1026
|
-
res.status(401).json(patchJSON.error.issues);
|
|
1027
|
-
return;
|
|
1028
|
-
}
|
|
1029
|
-
// Then parse/validate
|
|
1030
|
-
const patch$1 = patch.parsePatch(patchJSON.data);
|
|
1031
|
-
if (fp.result.isErr(patch$1)) {
|
|
1032
|
-
res.status(401).json(patch$1.error);
|
|
1033
|
-
return;
|
|
1034
|
-
}
|
|
1035
|
-
const id = getPathFromParams(req.params);
|
|
1036
|
-
try {
|
|
1037
|
-
const valModule = await this.options.service.patch(id, patch$1.value);
|
|
1038
|
-
res.json(valModule);
|
|
1039
|
-
} catch (err) {
|
|
1040
|
-
if (err instanceof patch.PatchError) {
|
|
1041
|
-
res.status(401).send(err.message);
|
|
1042
|
-
} else {
|
|
1043
|
-
console.error(err);
|
|
1044
|
-
res.status(500).send(err instanceof Error ? err.message : "Unknown error");
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
async badRequest(req, res) {
|
|
1049
|
-
console.debug("Local server does handle this request", req.url);
|
|
1050
|
-
res.sendStatus(400);
|
|
1051
|
-
}
|
|
1052
|
-
commit(req, res) {
|
|
1053
|
-
return this.badRequest(req, res);
|
|
1054
|
-
}
|
|
1055
|
-
authorize(req, res) {
|
|
1056
|
-
return this.badRequest(req, res);
|
|
1057
|
-
}
|
|
1058
|
-
callback(req, res) {
|
|
1059
|
-
return this.badRequest(req, res);
|
|
1060
|
-
}
|
|
1061
|
-
logout(req, res) {
|
|
1062
|
-
return this.badRequest(req, res);
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
1006
|
function decodeJwt(token, secretKey) {
|
|
1067
1007
|
const [headerBase64, payloadBase64, signatureBase64, ...rest] = token.split(".");
|
|
1068
1008
|
if (!headerBase64 || !payloadBase64 || !signatureBase64 || rest.length > 0) {
|
|
@@ -1124,10 +1064,17 @@ function encodeJwt(payload, sessionKey) {
|
|
|
1124
1064
|
|
|
1125
1065
|
const VAL_SESSION_COOKIE = "val_session";
|
|
1126
1066
|
const VAL_STATE_COOKIE = "val_state";
|
|
1067
|
+
const VAL_ENABLED_COOKIE = core.Internal.VAL_ENABLE_COOKIE_NAME;
|
|
1127
1068
|
class ProxyValServer {
|
|
1128
1069
|
constructor(options) {
|
|
1129
1070
|
this.options = options;
|
|
1130
1071
|
}
|
|
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
|
+
}
|
|
1131
1078
|
async authorize(req, res) {
|
|
1132
1079
|
const {
|
|
1133
1080
|
redirect_to
|
|
@@ -1148,6 +1095,9 @@ class ProxyValServer {
|
|
|
1148
1095
|
expires: new Date(Date.now() + 1000 * 60 * 60) // 1 hour
|
|
1149
1096
|
}).redirect(appAuthorizeUrl);
|
|
1150
1097
|
}
|
|
1098
|
+
async enable(req, res) {
|
|
1099
|
+
return enable(req, res);
|
|
1100
|
+
}
|
|
1151
1101
|
async callback(req, res) {
|
|
1152
1102
|
const {
|
|
1153
1103
|
success: callbackReqSuccess,
|
|
@@ -1193,7 +1143,6 @@ class ProxyValServer {
|
|
|
1193
1143
|
}
|
|
1194
1144
|
}
|
|
1195
1145
|
async session(req, res) {
|
|
1196
|
-
console.log("hit session");
|
|
1197
1146
|
return this.withAuth(req, res, async data => {
|
|
1198
1147
|
const url = new URL(`/api/val/${this.options.valName}/auth/session`, this.options.valBuildUrl);
|
|
1199
1148
|
const fetchRes = await fetch(url, {
|
|
@@ -1435,6 +1384,19 @@ function getStateFromCookie(stateCookie) {
|
|
|
1435
1384
|
};
|
|
1436
1385
|
}
|
|
1437
1386
|
}
|
|
1387
|
+
async function enable(req, res) {
|
|
1388
|
+
const {
|
|
1389
|
+
redirect_to
|
|
1390
|
+
} = req.query;
|
|
1391
|
+
if (typeof redirect_to === "string" || typeof redirect_to === "undefined") {
|
|
1392
|
+
res.cookie(VAL_ENABLED_COOKIE, "true", {
|
|
1393
|
+
httpOnly: false,
|
|
1394
|
+
sameSite: "lax"
|
|
1395
|
+
}).redirect(redirect_to || "/");
|
|
1396
|
+
} else {
|
|
1397
|
+
res.sendStatus(400);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1438
1400
|
function createStateCookie(state) {
|
|
1439
1401
|
return Buffer.from(JSON.stringify(state), "utf8").toString("base64");
|
|
1440
1402
|
}
|
|
@@ -1452,6 +1414,98 @@ const IntegratedServerJwtPayload = z.z.object({
|
|
|
1452
1414
|
project: z.z.string()
|
|
1453
1415
|
});
|
|
1454
1416
|
|
|
1417
|
+
class LocalValServer {
|
|
1418
|
+
constructor(options) {
|
|
1419
|
+
this.options = options;
|
|
1420
|
+
}
|
|
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
|
+
async session(_req, res) {
|
|
1446
|
+
res.json({
|
|
1447
|
+
mode: "local"
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
async enable(req, res) {
|
|
1451
|
+
return enable(req, res);
|
|
1452
|
+
}
|
|
1453
|
+
async getIds(req, res) {
|
|
1454
|
+
try {
|
|
1455
|
+
console.log(req.params);
|
|
1456
|
+
const path = getPathFromParams(req.params);
|
|
1457
|
+
const [moduleId, modulePath] = core.Internal.splitModuleIdAndModulePath(path);
|
|
1458
|
+
const valModule = await this.options.service.get(moduleId, modulePath);
|
|
1459
|
+
res.json(valModule);
|
|
1460
|
+
} catch (err) {
|
|
1461
|
+
console.error(err);
|
|
1462
|
+
res.sendStatus(500);
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
async patchIds(req, res) {
|
|
1466
|
+
// First validate that the body has the right structure
|
|
1467
|
+
const patchJSON = PatchJSON.safeParse(req.body);
|
|
1468
|
+
if (!patchJSON.success) {
|
|
1469
|
+
res.status(401).json(patchJSON.error.issues);
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
// Then parse/validate
|
|
1473
|
+
const patch$1 = patch.parsePatch(patchJSON.data);
|
|
1474
|
+
if (fp.result.isErr(patch$1)) {
|
|
1475
|
+
res.status(401).json(patch$1.error);
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
1478
|
+
const id = getPathFromParams(req.params);
|
|
1479
|
+
try {
|
|
1480
|
+
const valModule = await this.options.service.patch(id, patch$1.value);
|
|
1481
|
+
res.json(valModule);
|
|
1482
|
+
} catch (err) {
|
|
1483
|
+
if (err instanceof patch.PatchError) {
|
|
1484
|
+
res.status(401).send(err.message);
|
|
1485
|
+
} else {
|
|
1486
|
+
console.error(err);
|
|
1487
|
+
res.status(500).send(err instanceof Error ? err.message : "Unknown error");
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
async badRequest(req, res) {
|
|
1492
|
+
console.debug("Local server does handle this request", req.url);
|
|
1493
|
+
res.sendStatus(400);
|
|
1494
|
+
}
|
|
1495
|
+
commit(req, res) {
|
|
1496
|
+
return this.badRequest(req, res);
|
|
1497
|
+
}
|
|
1498
|
+
authorize(req, res) {
|
|
1499
|
+
return this.badRequest(req, res);
|
|
1500
|
+
}
|
|
1501
|
+
callback(req, res) {
|
|
1502
|
+
return this.badRequest(req, res);
|
|
1503
|
+
}
|
|
1504
|
+
logout(req, res) {
|
|
1505
|
+
return this.badRequest(req, res);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1455
1509
|
async function _createRequestListener(route, opts) {
|
|
1456
1510
|
const serverOpts = await initHandlerOptions(route, opts);
|
|
1457
1511
|
let valServer;
|
|
@@ -686,6 +686,9 @@ function convertDataUrlToBase64(dataUrl) {
|
|
|
686
686
|
return Buffer.from(base64, "base64");
|
|
687
687
|
}
|
|
688
688
|
const patchSourceFile = (sourceFile, patch$1) => {
|
|
689
|
+
if (typeof sourceFile === "string") {
|
|
690
|
+
return patch.applyPatch(ts__default["default"].createSourceFile("<val>", sourceFile, ts__default["default"].ScriptTarget.ES2015), ops, patch$1);
|
|
691
|
+
}
|
|
689
692
|
return patch.applyPatch(sourceFile, ops, patch$1);
|
|
690
693
|
};
|
|
691
694
|
|
|
@@ -949,14 +952,20 @@ function createRequestHandler(valServer) {
|
|
|
949
952
|
router.get("/callback", valServer.callback.bind(valServer));
|
|
950
953
|
router.get("/logout", valServer.logout.bind(valServer));
|
|
951
954
|
router.get("/ids/*", valServer.getIds.bind(valServer));
|
|
955
|
+
router.get("/ids", valServer.getAllModules.bind(valServer));
|
|
952
956
|
router.patch("/ids/*", express__default["default"].json({
|
|
953
957
|
type: "application/json-patch+json",
|
|
954
958
|
limit: "10mb"
|
|
955
959
|
}), valServer.patchIds.bind(valServer));
|
|
956
960
|
router.post("/commit", valServer.commit.bind(valServer));
|
|
961
|
+
router.get("/enable", valServer.enable.bind(valServer));
|
|
957
962
|
return router;
|
|
958
963
|
}
|
|
959
964
|
|
|
965
|
+
function getPathFromParams(params) {
|
|
966
|
+
return `/${params[0]}`;
|
|
967
|
+
}
|
|
968
|
+
|
|
960
969
|
const JSONValueT = z__default["default"].lazy(() => z__default["default"].union([z__default["default"].string(), z__default["default"].number(), z__default["default"].boolean(), z__default["default"].null(), z__default["default"].array(JSONValueT), z__default["default"].record(JSONValueT)]));
|
|
961
970
|
|
|
962
971
|
/**
|
|
@@ -994,75 +1003,6 @@ const OperationJSONT = z__default["default"].discriminatedUnion("op", [z__defaul
|
|
|
994
1003
|
}).strict()]);
|
|
995
1004
|
const PatchJSON = z__default["default"].array(OperationJSONT);
|
|
996
1005
|
|
|
997
|
-
function getPathFromParams(params) {
|
|
998
|
-
return `/${params[0]}`;
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
class LocalValServer {
|
|
1002
|
-
constructor(options) {
|
|
1003
|
-
this.options = options;
|
|
1004
|
-
}
|
|
1005
|
-
async session(_req, res) {
|
|
1006
|
-
res.json({
|
|
1007
|
-
mode: "local"
|
|
1008
|
-
});
|
|
1009
|
-
}
|
|
1010
|
-
async getIds(req, res) {
|
|
1011
|
-
try {
|
|
1012
|
-
console.log(req.params);
|
|
1013
|
-
const path = getPathFromParams(req.params);
|
|
1014
|
-
const [moduleId, modulePath] = core.Internal.splitModuleIdAndModulePath(path);
|
|
1015
|
-
const valModule = await this.options.service.get(moduleId, modulePath);
|
|
1016
|
-
res.json(valModule);
|
|
1017
|
-
} catch (err) {
|
|
1018
|
-
console.error(err);
|
|
1019
|
-
res.sendStatus(500);
|
|
1020
|
-
}
|
|
1021
|
-
}
|
|
1022
|
-
async patchIds(req, res) {
|
|
1023
|
-
// First validate that the body has the right structure
|
|
1024
|
-
const patchJSON = PatchJSON.safeParse(req.body);
|
|
1025
|
-
if (!patchJSON.success) {
|
|
1026
|
-
res.status(401).json(patchJSON.error.issues);
|
|
1027
|
-
return;
|
|
1028
|
-
}
|
|
1029
|
-
// Then parse/validate
|
|
1030
|
-
const patch$1 = patch.parsePatch(patchJSON.data);
|
|
1031
|
-
if (fp.result.isErr(patch$1)) {
|
|
1032
|
-
res.status(401).json(patch$1.error);
|
|
1033
|
-
return;
|
|
1034
|
-
}
|
|
1035
|
-
const id = getPathFromParams(req.params);
|
|
1036
|
-
try {
|
|
1037
|
-
const valModule = await this.options.service.patch(id, patch$1.value);
|
|
1038
|
-
res.json(valModule);
|
|
1039
|
-
} catch (err) {
|
|
1040
|
-
if (err instanceof patch.PatchError) {
|
|
1041
|
-
res.status(401).send(err.message);
|
|
1042
|
-
} else {
|
|
1043
|
-
console.error(err);
|
|
1044
|
-
res.status(500).send(err instanceof Error ? err.message : "Unknown error");
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
async badRequest(req, res) {
|
|
1049
|
-
console.debug("Local server does handle this request", req.url);
|
|
1050
|
-
res.sendStatus(400);
|
|
1051
|
-
}
|
|
1052
|
-
commit(req, res) {
|
|
1053
|
-
return this.badRequest(req, res);
|
|
1054
|
-
}
|
|
1055
|
-
authorize(req, res) {
|
|
1056
|
-
return this.badRequest(req, res);
|
|
1057
|
-
}
|
|
1058
|
-
callback(req, res) {
|
|
1059
|
-
return this.badRequest(req, res);
|
|
1060
|
-
}
|
|
1061
|
-
logout(req, res) {
|
|
1062
|
-
return this.badRequest(req, res);
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
1006
|
function decodeJwt(token, secretKey) {
|
|
1067
1007
|
const [headerBase64, payloadBase64, signatureBase64, ...rest] = token.split(".");
|
|
1068
1008
|
if (!headerBase64 || !payloadBase64 || !signatureBase64 || rest.length > 0) {
|
|
@@ -1124,10 +1064,17 @@ function encodeJwt(payload, sessionKey) {
|
|
|
1124
1064
|
|
|
1125
1065
|
const VAL_SESSION_COOKIE = "val_session";
|
|
1126
1066
|
const VAL_STATE_COOKIE = "val_state";
|
|
1067
|
+
const VAL_ENABLED_COOKIE = core.Internal.VAL_ENABLE_COOKIE_NAME;
|
|
1127
1068
|
class ProxyValServer {
|
|
1128
1069
|
constructor(options) {
|
|
1129
1070
|
this.options = options;
|
|
1130
1071
|
}
|
|
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
|
+
}
|
|
1131
1078
|
async authorize(req, res) {
|
|
1132
1079
|
const {
|
|
1133
1080
|
redirect_to
|
|
@@ -1148,6 +1095,9 @@ class ProxyValServer {
|
|
|
1148
1095
|
expires: new Date(Date.now() + 1000 * 60 * 60) // 1 hour
|
|
1149
1096
|
}).redirect(appAuthorizeUrl);
|
|
1150
1097
|
}
|
|
1098
|
+
async enable(req, res) {
|
|
1099
|
+
return enable(req, res);
|
|
1100
|
+
}
|
|
1151
1101
|
async callback(req, res) {
|
|
1152
1102
|
const {
|
|
1153
1103
|
success: callbackReqSuccess,
|
|
@@ -1193,7 +1143,6 @@ class ProxyValServer {
|
|
|
1193
1143
|
}
|
|
1194
1144
|
}
|
|
1195
1145
|
async session(req, res) {
|
|
1196
|
-
console.log("hit session");
|
|
1197
1146
|
return this.withAuth(req, res, async data => {
|
|
1198
1147
|
const url = new URL(`/api/val/${this.options.valName}/auth/session`, this.options.valBuildUrl);
|
|
1199
1148
|
const fetchRes = await fetch(url, {
|
|
@@ -1435,6 +1384,19 @@ function getStateFromCookie(stateCookie) {
|
|
|
1435
1384
|
};
|
|
1436
1385
|
}
|
|
1437
1386
|
}
|
|
1387
|
+
async function enable(req, res) {
|
|
1388
|
+
const {
|
|
1389
|
+
redirect_to
|
|
1390
|
+
} = req.query;
|
|
1391
|
+
if (typeof redirect_to === "string" || typeof redirect_to === "undefined") {
|
|
1392
|
+
res.cookie(VAL_ENABLED_COOKIE, "true", {
|
|
1393
|
+
httpOnly: false,
|
|
1394
|
+
sameSite: "lax"
|
|
1395
|
+
}).redirect(redirect_to || "/");
|
|
1396
|
+
} else {
|
|
1397
|
+
res.sendStatus(400);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1438
1400
|
function createStateCookie(state) {
|
|
1439
1401
|
return Buffer.from(JSON.stringify(state), "utf8").toString("base64");
|
|
1440
1402
|
}
|
|
@@ -1452,6 +1414,98 @@ const IntegratedServerJwtPayload = z.z.object({
|
|
|
1452
1414
|
project: z.z.string()
|
|
1453
1415
|
});
|
|
1454
1416
|
|
|
1417
|
+
class LocalValServer {
|
|
1418
|
+
constructor(options) {
|
|
1419
|
+
this.options = options;
|
|
1420
|
+
}
|
|
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
|
+
async session(_req, res) {
|
|
1446
|
+
res.json({
|
|
1447
|
+
mode: "local"
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
async enable(req, res) {
|
|
1451
|
+
return enable(req, res);
|
|
1452
|
+
}
|
|
1453
|
+
async getIds(req, res) {
|
|
1454
|
+
try {
|
|
1455
|
+
console.log(req.params);
|
|
1456
|
+
const path = getPathFromParams(req.params);
|
|
1457
|
+
const [moduleId, modulePath] = core.Internal.splitModuleIdAndModulePath(path);
|
|
1458
|
+
const valModule = await this.options.service.get(moduleId, modulePath);
|
|
1459
|
+
res.json(valModule);
|
|
1460
|
+
} catch (err) {
|
|
1461
|
+
console.error(err);
|
|
1462
|
+
res.sendStatus(500);
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
async patchIds(req, res) {
|
|
1466
|
+
// First validate that the body has the right structure
|
|
1467
|
+
const patchJSON = PatchJSON.safeParse(req.body);
|
|
1468
|
+
if (!patchJSON.success) {
|
|
1469
|
+
res.status(401).json(patchJSON.error.issues);
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
// Then parse/validate
|
|
1473
|
+
const patch$1 = patch.parsePatch(patchJSON.data);
|
|
1474
|
+
if (fp.result.isErr(patch$1)) {
|
|
1475
|
+
res.status(401).json(patch$1.error);
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
1478
|
+
const id = getPathFromParams(req.params);
|
|
1479
|
+
try {
|
|
1480
|
+
const valModule = await this.options.service.patch(id, patch$1.value);
|
|
1481
|
+
res.json(valModule);
|
|
1482
|
+
} catch (err) {
|
|
1483
|
+
if (err instanceof patch.PatchError) {
|
|
1484
|
+
res.status(401).send(err.message);
|
|
1485
|
+
} else {
|
|
1486
|
+
console.error(err);
|
|
1487
|
+
res.status(500).send(err instanceof Error ? err.message : "Unknown error");
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
async badRequest(req, res) {
|
|
1492
|
+
console.debug("Local server does handle this request", req.url);
|
|
1493
|
+
res.sendStatus(400);
|
|
1494
|
+
}
|
|
1495
|
+
commit(req, res) {
|
|
1496
|
+
return this.badRequest(req, res);
|
|
1497
|
+
}
|
|
1498
|
+
authorize(req, res) {
|
|
1499
|
+
return this.badRequest(req, res);
|
|
1500
|
+
}
|
|
1501
|
+
callback(req, res) {
|
|
1502
|
+
return this.badRequest(req, res);
|
|
1503
|
+
}
|
|
1504
|
+
logout(req, res) {
|
|
1505
|
+
return this.badRequest(req, res);
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1455
1509
|
async function _createRequestListener(route, opts) {
|
|
1456
1510
|
const serverOpts = await initHandlerOptions(route, opts);
|
|
1457
1511
|
let valServer;
|
|
@@ -4,7 +4,7 @@ import { result, pipe } from '@valbuild/core/fp';
|
|
|
4
4
|
import { FILE_REF_PROP, derefPatch, Internal, Schema } from '@valbuild/core';
|
|
5
5
|
import { deepEqual, isNotRoot, PatchError, parseAndValidateArrayIndex, applyPatch, parsePatch, sourceToPatchPath } from '@valbuild/core/patch';
|
|
6
6
|
import path from 'path';
|
|
7
|
-
import fs from 'fs';
|
|
7
|
+
import fs, { promises } from 'fs';
|
|
8
8
|
import express, { Router } from 'express';
|
|
9
9
|
import { createRequestHandler as createRequestHandler$1 } from '@valbuild/ui/server';
|
|
10
10
|
import z, { z as z$1 } from 'zod';
|
|
@@ -672,6 +672,9 @@ function convertDataUrlToBase64(dataUrl) {
|
|
|
672
672
|
return Buffer.from(base64, "base64");
|
|
673
673
|
}
|
|
674
674
|
const patchSourceFile = (sourceFile, patch) => {
|
|
675
|
+
if (typeof sourceFile === "string") {
|
|
676
|
+
return applyPatch(ts.createSourceFile("<val>", sourceFile, ts.ScriptTarget.ES2015), ops, patch);
|
|
677
|
+
}
|
|
675
678
|
return applyPatch(sourceFile, ops, patch);
|
|
676
679
|
};
|
|
677
680
|
|
|
@@ -935,14 +938,20 @@ function createRequestHandler(valServer) {
|
|
|
935
938
|
router.get("/callback", valServer.callback.bind(valServer));
|
|
936
939
|
router.get("/logout", valServer.logout.bind(valServer));
|
|
937
940
|
router.get("/ids/*", valServer.getIds.bind(valServer));
|
|
941
|
+
router.get("/ids", valServer.getAllModules.bind(valServer));
|
|
938
942
|
router.patch("/ids/*", express.json({
|
|
939
943
|
type: "application/json-patch+json",
|
|
940
944
|
limit: "10mb"
|
|
941
945
|
}), valServer.patchIds.bind(valServer));
|
|
942
946
|
router.post("/commit", valServer.commit.bind(valServer));
|
|
947
|
+
router.get("/enable", valServer.enable.bind(valServer));
|
|
943
948
|
return router;
|
|
944
949
|
}
|
|
945
950
|
|
|
951
|
+
function getPathFromParams(params) {
|
|
952
|
+
return `/${params[0]}`;
|
|
953
|
+
}
|
|
954
|
+
|
|
946
955
|
const JSONValueT = z.lazy(() => z.union([z.string(), z.number(), z.boolean(), z.null(), z.array(JSONValueT), z.record(JSONValueT)]));
|
|
947
956
|
|
|
948
957
|
/**
|
|
@@ -980,75 +989,6 @@ const OperationJSONT = z.discriminatedUnion("op", [z.object({
|
|
|
980
989
|
}).strict()]);
|
|
981
990
|
const PatchJSON = z.array(OperationJSONT);
|
|
982
991
|
|
|
983
|
-
function getPathFromParams(params) {
|
|
984
|
-
return `/${params[0]}`;
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
class LocalValServer {
|
|
988
|
-
constructor(options) {
|
|
989
|
-
this.options = options;
|
|
990
|
-
}
|
|
991
|
-
async session(_req, res) {
|
|
992
|
-
res.json({
|
|
993
|
-
mode: "local"
|
|
994
|
-
});
|
|
995
|
-
}
|
|
996
|
-
async getIds(req, res) {
|
|
997
|
-
try {
|
|
998
|
-
console.log(req.params);
|
|
999
|
-
const path = getPathFromParams(req.params);
|
|
1000
|
-
const [moduleId, modulePath] = Internal.splitModuleIdAndModulePath(path);
|
|
1001
|
-
const valModule = await this.options.service.get(moduleId, modulePath);
|
|
1002
|
-
res.json(valModule);
|
|
1003
|
-
} catch (err) {
|
|
1004
|
-
console.error(err);
|
|
1005
|
-
res.sendStatus(500);
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
async patchIds(req, res) {
|
|
1009
|
-
// First validate that the body has the right structure
|
|
1010
|
-
const patchJSON = PatchJSON.safeParse(req.body);
|
|
1011
|
-
if (!patchJSON.success) {
|
|
1012
|
-
res.status(401).json(patchJSON.error.issues);
|
|
1013
|
-
return;
|
|
1014
|
-
}
|
|
1015
|
-
// Then parse/validate
|
|
1016
|
-
const patch = parsePatch(patchJSON.data);
|
|
1017
|
-
if (result.isErr(patch)) {
|
|
1018
|
-
res.status(401).json(patch.error);
|
|
1019
|
-
return;
|
|
1020
|
-
}
|
|
1021
|
-
const id = getPathFromParams(req.params);
|
|
1022
|
-
try {
|
|
1023
|
-
const valModule = await this.options.service.patch(id, patch.value);
|
|
1024
|
-
res.json(valModule);
|
|
1025
|
-
} catch (err) {
|
|
1026
|
-
if (err instanceof PatchError) {
|
|
1027
|
-
res.status(401).send(err.message);
|
|
1028
|
-
} else {
|
|
1029
|
-
console.error(err);
|
|
1030
|
-
res.status(500).send(err instanceof Error ? err.message : "Unknown error");
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
async badRequest(req, res) {
|
|
1035
|
-
console.debug("Local server does handle this request", req.url);
|
|
1036
|
-
res.sendStatus(400);
|
|
1037
|
-
}
|
|
1038
|
-
commit(req, res) {
|
|
1039
|
-
return this.badRequest(req, res);
|
|
1040
|
-
}
|
|
1041
|
-
authorize(req, res) {
|
|
1042
|
-
return this.badRequest(req, res);
|
|
1043
|
-
}
|
|
1044
|
-
callback(req, res) {
|
|
1045
|
-
return this.badRequest(req, res);
|
|
1046
|
-
}
|
|
1047
|
-
logout(req, res) {
|
|
1048
|
-
return this.badRequest(req, res);
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
992
|
function decodeJwt(token, secretKey) {
|
|
1053
993
|
const [headerBase64, payloadBase64, signatureBase64, ...rest] = token.split(".");
|
|
1054
994
|
if (!headerBase64 || !payloadBase64 || !signatureBase64 || rest.length > 0) {
|
|
@@ -1110,10 +1050,17 @@ function encodeJwt(payload, sessionKey) {
|
|
|
1110
1050
|
|
|
1111
1051
|
const VAL_SESSION_COOKIE = "val_session";
|
|
1112
1052
|
const VAL_STATE_COOKIE = "val_state";
|
|
1053
|
+
const VAL_ENABLED_COOKIE = Internal.VAL_ENABLE_COOKIE_NAME;
|
|
1113
1054
|
class ProxyValServer {
|
|
1114
1055
|
constructor(options) {
|
|
1115
1056
|
this.options = options;
|
|
1116
1057
|
}
|
|
1058
|
+
|
|
1059
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1060
|
+
getAllModules(_req, _res) {
|
|
1061
|
+
// TODO:
|
|
1062
|
+
throw new Error("Method not implemented.");
|
|
1063
|
+
}
|
|
1117
1064
|
async authorize(req, res) {
|
|
1118
1065
|
const {
|
|
1119
1066
|
redirect_to
|
|
@@ -1134,6 +1081,9 @@ class ProxyValServer {
|
|
|
1134
1081
|
expires: new Date(Date.now() + 1000 * 60 * 60) // 1 hour
|
|
1135
1082
|
}).redirect(appAuthorizeUrl);
|
|
1136
1083
|
}
|
|
1084
|
+
async enable(req, res) {
|
|
1085
|
+
return enable(req, res);
|
|
1086
|
+
}
|
|
1137
1087
|
async callback(req, res) {
|
|
1138
1088
|
const {
|
|
1139
1089
|
success: callbackReqSuccess,
|
|
@@ -1179,7 +1129,6 @@ class ProxyValServer {
|
|
|
1179
1129
|
}
|
|
1180
1130
|
}
|
|
1181
1131
|
async session(req, res) {
|
|
1182
|
-
console.log("hit session");
|
|
1183
1132
|
return this.withAuth(req, res, async data => {
|
|
1184
1133
|
const url = new URL(`/api/val/${this.options.valName}/auth/session`, this.options.valBuildUrl);
|
|
1185
1134
|
const fetchRes = await fetch(url, {
|
|
@@ -1421,6 +1370,19 @@ function getStateFromCookie(stateCookie) {
|
|
|
1421
1370
|
};
|
|
1422
1371
|
}
|
|
1423
1372
|
}
|
|
1373
|
+
async function enable(req, res) {
|
|
1374
|
+
const {
|
|
1375
|
+
redirect_to
|
|
1376
|
+
} = req.query;
|
|
1377
|
+
if (typeof redirect_to === "string" || typeof redirect_to === "undefined") {
|
|
1378
|
+
res.cookie(VAL_ENABLED_COOKIE, "true", {
|
|
1379
|
+
httpOnly: false,
|
|
1380
|
+
sameSite: "lax"
|
|
1381
|
+
}).redirect(redirect_to || "/");
|
|
1382
|
+
} else {
|
|
1383
|
+
res.sendStatus(400);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1424
1386
|
function createStateCookie(state) {
|
|
1425
1387
|
return Buffer.from(JSON.stringify(state), "utf8").toString("base64");
|
|
1426
1388
|
}
|
|
@@ -1438,6 +1400,98 @@ const IntegratedServerJwtPayload = z$1.object({
|
|
|
1438
1400
|
project: z$1.string()
|
|
1439
1401
|
});
|
|
1440
1402
|
|
|
1403
|
+
class LocalValServer {
|
|
1404
|
+
constructor(options) {
|
|
1405
|
+
this.options = options;
|
|
1406
|
+
}
|
|
1407
|
+
getAllModules(req, res) {
|
|
1408
|
+
// TODO: this barely works,
|
|
1409
|
+
const rootDir = process.cwd();
|
|
1410
|
+
const moduleIds = [];
|
|
1411
|
+
// iterate over all .val files in the root directory
|
|
1412
|
+
const walk = async dir => {
|
|
1413
|
+
const files = await promises.readdir(dir);
|
|
1414
|
+
for (const file of files) {
|
|
1415
|
+
if ((await promises.stat(path.join(dir, file))).isDirectory()) {
|
|
1416
|
+
if (file === "node_modules") continue;
|
|
1417
|
+
await walk(path.join(dir, file));
|
|
1418
|
+
} else {
|
|
1419
|
+
if (file.endsWith(".val.js") || file.endsWith(".val.ts")) {
|
|
1420
|
+
moduleIds.push(path.join(dir, file).replace(rootDir, "").replace(".val.js", "").replace(".val.ts", ""));
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
};
|
|
1425
|
+
return walk(rootDir).then(async () => {
|
|
1426
|
+
res.send(JSON.stringify(await Promise.all(moduleIds.map(async moduleId => {
|
|
1427
|
+
return await this.options.service.get(moduleId, "");
|
|
1428
|
+
}))));
|
|
1429
|
+
});
|
|
1430
|
+
}
|
|
1431
|
+
async session(_req, res) {
|
|
1432
|
+
res.json({
|
|
1433
|
+
mode: "local"
|
|
1434
|
+
});
|
|
1435
|
+
}
|
|
1436
|
+
async enable(req, res) {
|
|
1437
|
+
return enable(req, res);
|
|
1438
|
+
}
|
|
1439
|
+
async getIds(req, res) {
|
|
1440
|
+
try {
|
|
1441
|
+
console.log(req.params);
|
|
1442
|
+
const path = getPathFromParams(req.params);
|
|
1443
|
+
const [moduleId, modulePath] = Internal.splitModuleIdAndModulePath(path);
|
|
1444
|
+
const valModule = await this.options.service.get(moduleId, modulePath);
|
|
1445
|
+
res.json(valModule);
|
|
1446
|
+
} catch (err) {
|
|
1447
|
+
console.error(err);
|
|
1448
|
+
res.sendStatus(500);
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
async patchIds(req, res) {
|
|
1452
|
+
// First validate that the body has the right structure
|
|
1453
|
+
const patchJSON = PatchJSON.safeParse(req.body);
|
|
1454
|
+
if (!patchJSON.success) {
|
|
1455
|
+
res.status(401).json(patchJSON.error.issues);
|
|
1456
|
+
return;
|
|
1457
|
+
}
|
|
1458
|
+
// Then parse/validate
|
|
1459
|
+
const patch = parsePatch(patchJSON.data);
|
|
1460
|
+
if (result.isErr(patch)) {
|
|
1461
|
+
res.status(401).json(patch.error);
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
const id = getPathFromParams(req.params);
|
|
1465
|
+
try {
|
|
1466
|
+
const valModule = await this.options.service.patch(id, patch.value);
|
|
1467
|
+
res.json(valModule);
|
|
1468
|
+
} catch (err) {
|
|
1469
|
+
if (err instanceof PatchError) {
|
|
1470
|
+
res.status(401).send(err.message);
|
|
1471
|
+
} else {
|
|
1472
|
+
console.error(err);
|
|
1473
|
+
res.status(500).send(err instanceof Error ? err.message : "Unknown error");
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
async badRequest(req, res) {
|
|
1478
|
+
console.debug("Local server does handle this request", req.url);
|
|
1479
|
+
res.sendStatus(400);
|
|
1480
|
+
}
|
|
1481
|
+
commit(req, res) {
|
|
1482
|
+
return this.badRequest(req, res);
|
|
1483
|
+
}
|
|
1484
|
+
authorize(req, res) {
|
|
1485
|
+
return this.badRequest(req, res);
|
|
1486
|
+
}
|
|
1487
|
+
callback(req, res) {
|
|
1488
|
+
return this.badRequest(req, res);
|
|
1489
|
+
}
|
|
1490
|
+
logout(req, res) {
|
|
1491
|
+
return this.badRequest(req, res);
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1441
1495
|
async function _createRequestListener(route, opts) {
|
|
1442
1496
|
const serverOpts = await initHandlerOptions(route, opts);
|
|
1443
1497
|
let valServer;
|
package/package.json
CHANGED
package/src/LocalValServer.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import express from "express";
|
|
2
2
|
import { Service } from "./Service";
|
|
3
|
-
import { PatchJSON } from "./patch/validation";
|
|
4
3
|
import { result } from "@valbuild/core/fp";
|
|
5
4
|
import { parsePatch, PatchError } from "@valbuild/core/patch";
|
|
6
5
|
import { getPathFromParams } from "./expressHelpers";
|
|
6
|
+
import { PatchJSON } from "./patch/validation";
|
|
7
7
|
import { ValServer } from "./ValServer";
|
|
8
|
-
import { Internal } from "@valbuild/core";
|
|
8
|
+
import { Internal, ModuleId, ModulePath } from "@valbuild/core";
|
|
9
|
+
import { enable } from "./ProxyValServer";
|
|
10
|
+
import { promises as fs } from "fs";
|
|
11
|
+
import path from "path";
|
|
9
12
|
|
|
10
13
|
export type LocalValServerOptions = {
|
|
11
14
|
service: Service;
|
|
@@ -13,6 +16,46 @@ export type LocalValServerOptions = {
|
|
|
13
16
|
|
|
14
17
|
export class LocalValServer implements ValServer {
|
|
15
18
|
constructor(readonly options: LocalValServerOptions) {}
|
|
19
|
+
getAllModules(req: express.Request, res: express.Response): Promise<void> {
|
|
20
|
+
// TODO: this barely works,
|
|
21
|
+
const rootDir = process.cwd();
|
|
22
|
+
const moduleIds: string[] = [];
|
|
23
|
+
// iterate over all .val files in the root directory
|
|
24
|
+
const walk = async (dir: string) => {
|
|
25
|
+
const files = await fs.readdir(dir);
|
|
26
|
+
for (const file of files) {
|
|
27
|
+
if ((await fs.stat(path.join(dir, file))).isDirectory()) {
|
|
28
|
+
if (file === "node_modules") continue;
|
|
29
|
+
await walk(path.join(dir, file));
|
|
30
|
+
} else {
|
|
31
|
+
if (file.endsWith(".val.js") || file.endsWith(".val.ts")) {
|
|
32
|
+
moduleIds.push(
|
|
33
|
+
path
|
|
34
|
+
.join(dir, file)
|
|
35
|
+
.replace(rootDir, "")
|
|
36
|
+
.replace(".val.js", "")
|
|
37
|
+
.replace(".val.ts", "")
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return walk(rootDir).then(async () => {
|
|
45
|
+
res.send(
|
|
46
|
+
JSON.stringify(
|
|
47
|
+
await Promise.all(
|
|
48
|
+
moduleIds.map(async (moduleId) => {
|
|
49
|
+
return await this.options.service.get(
|
|
50
|
+
moduleId as ModuleId,
|
|
51
|
+
"" as ModulePath
|
|
52
|
+
);
|
|
53
|
+
})
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
16
59
|
|
|
17
60
|
async session(_req: express.Request, res: express.Response): Promise<void> {
|
|
18
61
|
res.json({
|
|
@@ -20,6 +63,10 @@ export class LocalValServer implements ValServer {
|
|
|
20
63
|
});
|
|
21
64
|
}
|
|
22
65
|
|
|
66
|
+
async enable(req: express.Request, res: express.Response): Promise<void> {
|
|
67
|
+
return enable(req, res);
|
|
68
|
+
}
|
|
69
|
+
|
|
23
70
|
async getIds(
|
|
24
71
|
req: express.Request<{ 0: string }>,
|
|
25
72
|
res: express.Response
|
|
@@ -28,6 +75,7 @@ export class LocalValServer implements ValServer {
|
|
|
28
75
|
console.log(req.params);
|
|
29
76
|
const path = getPathFromParams(req.params);
|
|
30
77
|
const [moduleId, modulePath] = Internal.splitModuleIdAndModulePath(path);
|
|
78
|
+
|
|
31
79
|
const valModule = await this.options.service.get(moduleId, modulePath);
|
|
32
80
|
|
|
33
81
|
res.json(valModule);
|
package/src/ProxyValServer.ts
CHANGED
|
@@ -7,9 +7,11 @@ import { getPathFromParams } from "./expressHelpers";
|
|
|
7
7
|
import { ValServer } from "./ValServer";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { parsePatch } from "@valbuild/core/patch";
|
|
10
|
+
import { Internal } from "@valbuild/core";
|
|
10
11
|
|
|
11
12
|
const VAL_SESSION_COOKIE = "val_session";
|
|
12
13
|
const VAL_STATE_COOKIE = "val_state";
|
|
14
|
+
const VAL_ENABLED_COOKIE = Internal.VAL_ENABLE_COOKIE_NAME;
|
|
13
15
|
|
|
14
16
|
export type ProxyValServerOptions = {
|
|
15
17
|
apiKey: string;
|
|
@@ -24,6 +26,12 @@ export type ProxyValServerOptions = {
|
|
|
24
26
|
export class ProxyValServer implements ValServer {
|
|
25
27
|
constructor(readonly options: ProxyValServerOptions) {}
|
|
26
28
|
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
30
|
+
getAllModules(_req: express.Request, _res: express.Response): Promise<void> {
|
|
31
|
+
// TODO:
|
|
32
|
+
throw new Error("Method not implemented.");
|
|
33
|
+
}
|
|
34
|
+
|
|
27
35
|
async authorize(req: express.Request, res: express.Response): Promise<void> {
|
|
28
36
|
const { redirect_to } = req.query;
|
|
29
37
|
if (typeof redirect_to !== "string") {
|
|
@@ -47,6 +55,10 @@ export class ProxyValServer implements ValServer {
|
|
|
47
55
|
.redirect(appAuthorizeUrl);
|
|
48
56
|
}
|
|
49
57
|
|
|
58
|
+
async enable(req: express.Request, res: express.Response): Promise<void> {
|
|
59
|
+
return enable(req, res);
|
|
60
|
+
}
|
|
61
|
+
|
|
50
62
|
async callback(req: express.Request, res: express.Response): Promise<void> {
|
|
51
63
|
const { success: callbackReqSuccess, error: callbackReqError } =
|
|
52
64
|
verifyCallbackReq(req.cookies[VAL_STATE_COOKIE], req.query);
|
|
@@ -113,7 +125,6 @@ export class ProxyValServer implements ValServer {
|
|
|
113
125
|
}
|
|
114
126
|
|
|
115
127
|
async session(req: express.Request, res: express.Response): Promise<void> {
|
|
116
|
-
console.log("hit session");
|
|
117
128
|
return this.withAuth(req, res, async (data) => {
|
|
118
129
|
const url = new URL(
|
|
119
130
|
`/api/val/${this.options.valName}/auth/session`,
|
|
@@ -387,6 +398,23 @@ function getStateFromCookie(stateCookie: string):
|
|
|
387
398
|
}
|
|
388
399
|
}
|
|
389
400
|
|
|
401
|
+
export async function enable(
|
|
402
|
+
req: express.Request,
|
|
403
|
+
res: express.Response
|
|
404
|
+
): Promise<void> {
|
|
405
|
+
const { redirect_to } = req.query;
|
|
406
|
+
if (typeof redirect_to === "string" || typeof redirect_to === "undefined") {
|
|
407
|
+
res
|
|
408
|
+
.cookie(VAL_ENABLED_COOKIE, "true", {
|
|
409
|
+
httpOnly: false,
|
|
410
|
+
sameSite: "lax",
|
|
411
|
+
})
|
|
412
|
+
.redirect(redirect_to || "/");
|
|
413
|
+
} else {
|
|
414
|
+
res.sendStatus(400);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
390
418
|
function createStateCookie(state: StateCookie): string {
|
|
391
419
|
return Buffer.from(JSON.stringify(state), "utf8").toString("base64");
|
|
392
420
|
}
|
package/src/ValServer.ts
CHANGED
|
@@ -14,10 +14,17 @@ export interface ValServer {
|
|
|
14
14
|
res: express.Response
|
|
15
15
|
): Promise<void>;
|
|
16
16
|
|
|
17
|
+
getAllModules(
|
|
18
|
+
req: express.Request<{ 0: string }>,
|
|
19
|
+
res: express.Response
|
|
20
|
+
): Promise<void>;
|
|
21
|
+
|
|
17
22
|
patchIds(
|
|
18
23
|
req: express.Request<{ 0: string }>,
|
|
19
24
|
res: express.Response
|
|
20
25
|
): Promise<void>;
|
|
21
26
|
|
|
22
27
|
commit(req: express.Request, res: express.Response): Promise<void>;
|
|
28
|
+
|
|
29
|
+
enable(req: express.Request, res: express.Response): Promise<void>;
|
|
23
30
|
}
|
|
@@ -11,6 +11,7 @@ export function createRequestHandler(valServer: ValServer): RequestHandler {
|
|
|
11
11
|
router.get("/callback", valServer.callback.bind(valServer));
|
|
12
12
|
router.get("/logout", valServer.logout.bind(valServer));
|
|
13
13
|
router.get<{ 0: string }>("/ids/*", valServer.getIds.bind(valServer));
|
|
14
|
+
router.get("/ids", valServer.getAllModules.bind(valServer));
|
|
14
15
|
router.patch<{ 0: string }>(
|
|
15
16
|
"/ids/*",
|
|
16
17
|
express.json({
|
|
@@ -20,5 +21,6 @@ export function createRequestHandler(valServer: ValServer): RequestHandler {
|
|
|
20
21
|
valServer.patchIds.bind(valServer)
|
|
21
22
|
);
|
|
22
23
|
router.post("/commit", valServer.commit.bind(valServer));
|
|
24
|
+
router.get("/enable", valServer.enable.bind(valServer));
|
|
23
25
|
return router;
|
|
24
26
|
}
|
package/src/jwt.ts
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import crypto from "crypto";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
|
-
export
|
|
4
|
+
export type JwtPayload = {
|
|
5
|
+
sub: string;
|
|
6
|
+
exp: number;
|
|
7
|
+
org: string;
|
|
8
|
+
project: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function decodeJwt(
|
|
12
|
+
token: string,
|
|
13
|
+
secretKey?: string
|
|
14
|
+
): JwtPayload | null {
|
|
5
15
|
const [headerBase64, payloadBase64, signatureBase64, ...rest] =
|
|
6
16
|
token.split(".");
|
|
7
17
|
if (!headerBase64 || !payloadBase64 || !signatureBase64 || rest.length > 0) {
|
|
@@ -47,7 +57,7 @@ export function decodeJwt(token: string, secretKey?: string): unknown | null {
|
|
|
47
57
|
try {
|
|
48
58
|
const parsedPayload = JSON.parse(
|
|
49
59
|
Buffer.from(payloadBase64, "base64").toString("utf8")
|
|
50
|
-
) as
|
|
60
|
+
) as JwtPayload;
|
|
51
61
|
return parsedPayload;
|
|
52
62
|
} catch (err) {
|
|
53
63
|
console.debug("Invalid JWT: could not parse payload", err);
|
package/src/patchValFile.ts
CHANGED
|
@@ -95,8 +95,15 @@ function convertDataUrlToBase64(dataUrl: string): Buffer {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
export const patchSourceFile = (
|
|
98
|
-
sourceFile: ts.SourceFile,
|
|
98
|
+
sourceFile: ts.SourceFile | string,
|
|
99
99
|
patch: Patch
|
|
100
100
|
): result.Result<ts.SourceFile, ValSyntaxErrorTree | PatchError> => {
|
|
101
|
+
if (typeof sourceFile === "string") {
|
|
102
|
+
return applyPatch(
|
|
103
|
+
ts.createSourceFile("<val>", sourceFile, ts.ScriptTarget.ES2015),
|
|
104
|
+
ops,
|
|
105
|
+
patch
|
|
106
|
+
);
|
|
107
|
+
}
|
|
101
108
|
return applyPatch(sourceFile, ops, patch);
|
|
102
109
|
};
|