@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.
@@ -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 declare function decodeJwt(token: string, secretKey?: string): unknown | null;
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
@@ -12,7 +12,7 @@
12
12
  "./package.json": "./package.json"
13
13
  },
14
14
  "types": "dist/valbuild-server.cjs.d.ts",
15
- "version": "0.16.2",
15
+ "version": "0.16.4",
16
16
  "scripts": {
17
17
  "typecheck": "tsc --noEmit",
18
18
  "test": "jest",
@@ -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);
@@ -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 function decodeJwt(token: string, secretKey?: string): unknown | null {
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 unknown;
60
+ ) as JwtPayload;
51
61
  return parsedPayload;
52
62
  } catch (err) {
53
63
  console.debug("Invalid JWT: could not parse payload", err);
@@ -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
  };