@elek-io/core 0.11.0 → 0.12.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.
@@ -8,7 +8,16 @@ var __export = (target, all) => {
8
8
  import Fs7 from "fs-extra";
9
9
 
10
10
  // package.json
11
- var version = "0.11.0";
11
+ var version = "0.12.0";
12
+
13
+ // src/api/index.ts
14
+ import { serve } from "@hono/node-server";
15
+ import { swaggerUI } from "@hono/swagger-ui";
16
+ import { OpenAPIHono as OpenAPIHono2 } from "@hono/zod-openapi";
17
+ import { cors } from "hono/cors";
18
+
19
+ // src/api/v1/projects.ts
20
+ import { createRoute, OpenAPIHono, z as z13 } from "@hono/zod-openapi";
12
21
 
13
22
  // src/schema/assetSchema.ts
14
23
  import z4 from "zod";
@@ -743,7 +752,7 @@ var constructorElekIoCoreSchema = elekIoCoreOptionsSchema.partial({
743
752
  }).optional();
744
753
 
745
754
  // src/schema/projectSchema.ts
746
- import { z as z10 } from "zod";
755
+ import { z as z10 } from "@hono/zod-openapi";
747
756
  var projectStatusSchema = z10.enum(["foo", "bar", "todo"]);
748
757
  var projectSettingsSchema = z10.object({
749
758
  language: z10.object({
@@ -771,17 +780,16 @@ var projectFileSchema = baseFileSchema.extend({
771
780
  settings: projectSettingsSchema
772
781
  });
773
782
  var projectSchema = projectFileSchema.extend({
774
- remoteOriginUrl: z10.string().nullable(),
775
- /**
776
- * Commit history of this Project
777
- */
778
- history: z10.array(gitCommitSchema),
779
- /**
780
- * Full commit history of this Project
781
- * including all Assets, Collections, Entries and other files
782
- */
783
- fullHistory: z10.array(gitCommitSchema)
784
- });
783
+ remoteOriginUrl: z10.string().nullable().openapi({
784
+ description: "URL of the remote Git repository"
785
+ }),
786
+ history: z10.array(gitCommitSchema).openapi({
787
+ description: "Commit history of this Project"
788
+ }),
789
+ fullHistory: z10.array(gitCommitSchema).openapi({
790
+ description: "Full commit history of this Project including all Assets, Collections, Entries and other files"
791
+ })
792
+ }).openapi("Project");
785
793
  var outdatedProjectSchema = projectFileSchema.pick({
786
794
  id: true,
787
795
  name: true,
@@ -881,10 +889,24 @@ var serviceTypeSchema = z11.enum([
881
889
  "Entry",
882
890
  "Value"
883
891
  ]);
892
+ function paginatedListOf(schema) {
893
+ return z11.object({
894
+ total: z11.number(),
895
+ limit: z11.number(),
896
+ offset: z11.number(),
897
+ list: z11.array(schema)
898
+ });
899
+ }
884
900
  var listSchema = z11.object({
885
901
  projectId: uuidSchema,
886
- limit: z11.number().optional(),
887
- offset: z11.number().optional()
902
+ limit: z11.number().optional().openapi({
903
+ default: 15,
904
+ description: "The maximum number of items to return"
905
+ }),
906
+ offset: z11.number().optional().openapi({
907
+ default: 0,
908
+ description: "The number of items to skip before starting to collect the result set"
909
+ })
888
910
  });
889
911
  var listCollectionsSchema = listSchema;
890
912
  var listEntriesSchema = listSchema.extend({
@@ -904,6 +926,16 @@ var UserTypeSchema = z12.enum(["local", "cloud"]);
904
926
  var baseUserSchema = gitSignatureSchema.extend({
905
927
  userType: UserTypeSchema,
906
928
  language: supportedLanguageSchema,
929
+ localApi: z12.object({
930
+ /**
931
+ * If set to true the local API is started whenever Core is initialized
932
+ */
933
+ isEnabled: z12.boolean(),
934
+ /**
935
+ * The port the local API uses
936
+ */
937
+ port: z12.number()
938
+ }),
907
939
  window: z12.object({
908
940
  width: z12.number(),
909
941
  height: z12.number(),
@@ -924,6 +956,204 @@ var userFileSchema = z12.union([localUserSchema, cloudUserSchema]);
924
956
  var userSchema = userFileSchema;
925
957
  var setUserSchema = userSchema;
926
958
 
959
+ // src/api/v1/projects.ts
960
+ var ProjectsApiV1 = class {
961
+ api;
962
+ projectService;
963
+ constructor(projectService) {
964
+ this.projectService = projectService;
965
+ this.api = new OpenAPIHono();
966
+ this.registerRoutes();
967
+ }
968
+ registerRoutes() {
969
+ this.api.openapi(countProjectsRoute, async (context) => {
970
+ const count = await this.projectService.count();
971
+ return context.json(count, 200);
972
+ });
973
+ this.api.openapi(listProjectsRoute, async (context) => {
974
+ const { limit, offset } = context.req.valid("query");
975
+ const projects = await this.projectService.list({ limit, offset });
976
+ return context.json(projects, 200);
977
+ });
978
+ this.api.openapi(readProjectRoute, async (context) => {
979
+ const { id } = context.req.valid("param");
980
+ const project = await this.projectService.read({ id });
981
+ return context.json(project, 200);
982
+ });
983
+ }
984
+ };
985
+ var countProjectsRoute = createRoute({
986
+ tags: ["Projects"],
987
+ description: "Counts all Projects you currently have access to",
988
+ method: "get",
989
+ path: "/count",
990
+ operationId: "countProjects",
991
+ responses: {
992
+ 200: {
993
+ content: {
994
+ "application/json": {
995
+ schema: z13.number()
996
+ }
997
+ },
998
+ description: "The number of Projects you have acces to"
999
+ }
1000
+ }
1001
+ });
1002
+ var listProjectsRoute = createRoute({
1003
+ tags: ["Projects"],
1004
+ description: "Lists all Projects you currently have access to",
1005
+ method: "get",
1006
+ path: "/",
1007
+ operationId: "listProjects",
1008
+ request: {
1009
+ query: listProjectsSchema
1010
+ },
1011
+ responses: {
1012
+ 200: {
1013
+ content: {
1014
+ "application/json": {
1015
+ schema: paginatedListOf(projectSchema)
1016
+ }
1017
+ },
1018
+ description: "A list of Projects you have access to"
1019
+ }
1020
+ }
1021
+ });
1022
+ var readProjectRoute = createRoute({
1023
+ tags: ["Projects"],
1024
+ description: "Retrieve a Project by ID",
1025
+ method: "get",
1026
+ path: "/{id}",
1027
+ operationId: "readProject",
1028
+ request: {
1029
+ params: z13.object({
1030
+ id: uuidSchema.openapi({
1031
+ param: {
1032
+ name: "id",
1033
+ in: "path"
1034
+ }
1035
+ })
1036
+ })
1037
+ },
1038
+ responses: {
1039
+ 200: {
1040
+ content: {
1041
+ "application/json": {
1042
+ schema: projectSchema
1043
+ }
1044
+ },
1045
+ description: "The requested Project"
1046
+ },
1047
+ 404: {
1048
+ description: "The requested Project does not exist or you have no right to access it"
1049
+ }
1050
+ }
1051
+ });
1052
+
1053
+ // src/api/index.ts
1054
+ var LocalApi = class {
1055
+ logService;
1056
+ projectService;
1057
+ api;
1058
+ server = null;
1059
+ constructor(logService, projectService) {
1060
+ this.logService = logService;
1061
+ this.projectService = projectService;
1062
+ this.api = new OpenAPIHono2();
1063
+ this.api.use(
1064
+ cors({
1065
+ origin: ["http://localhost"]
1066
+ })
1067
+ );
1068
+ this.registerRoutes();
1069
+ this.api.doc("/openapi.json", {
1070
+ openapi: "3.0.0",
1071
+ info: {
1072
+ version: "0.1.0",
1073
+ title: "elek.io Project API",
1074
+ description: "This API allows reading data from elek.io Projects"
1075
+ },
1076
+ servers: [
1077
+ {
1078
+ url: "http://localhost:{port}/v1/",
1079
+ description: "Local development API",
1080
+ variables: {
1081
+ port: {
1082
+ default: 31310,
1083
+ description: "The port specified in elek.io Clients user configuration"
1084
+ }
1085
+ }
1086
+ },
1087
+ {
1088
+ url: "https://api.elek.io/v1/",
1089
+ description: "Public production API",
1090
+ variables: {}
1091
+ }
1092
+ ],
1093
+ tags: [
1094
+ {
1095
+ name: "Projects",
1096
+ description: "Retrieve information about Projects",
1097
+ externalDocs: { url: "https://elek.io/docs/projects" }
1098
+ },
1099
+ {
1100
+ name: "Collections",
1101
+ description: "Retrieve information about Collections",
1102
+ externalDocs: { url: "https://elek.io/docs/collections" }
1103
+ },
1104
+ {
1105
+ name: "Entries",
1106
+ description: "Retrieve information about Entries",
1107
+ externalDocs: { url: "https://elek.io/docs/entries" }
1108
+ },
1109
+ {
1110
+ name: "Assets",
1111
+ description: "Retrieve information about Assets",
1112
+ externalDocs: { url: "https://elek.io/docs/assets" }
1113
+ }
1114
+ ]
1115
+ });
1116
+ this.api.get("/ui", swaggerUI({ url: "/openapi.json" }));
1117
+ }
1118
+ /**
1119
+ * Starts the local API on given port
1120
+ */
1121
+ start(port) {
1122
+ this.server = serve(
1123
+ {
1124
+ fetch: this.api.fetch,
1125
+ port
1126
+ },
1127
+ (info) => {
1128
+ this.logService.info(
1129
+ `Started local API on ${info.address}:${info.port} (${info.family})`
1130
+ );
1131
+ }
1132
+ );
1133
+ }
1134
+ /**
1135
+ * Stops the local API
1136
+ */
1137
+ stop() {
1138
+ this.server?.close(() => {
1139
+ this.logService.info("Stopped local API");
1140
+ });
1141
+ }
1142
+ /**
1143
+ * Returns true if the local API is running
1144
+ */
1145
+ isRunning() {
1146
+ if (this.server?.listening) {
1147
+ return true;
1148
+ }
1149
+ return false;
1150
+ }
1151
+ registerRoutes() {
1152
+ const projectsV1 = new ProjectsApiV1(this.projectService);
1153
+ this.api.route("/v1/projects", projectsV1.api);
1154
+ }
1155
+ };
1156
+
927
1157
  // src/error/GitError.ts
928
1158
  var GitError = class extends Error {
929
1159
  constructor(message) {
@@ -1027,8 +1257,8 @@ var pathTo = {
1027
1257
  asset: (projectId, id, extension) => {
1028
1258
  return Path.join(pathTo.lfs(projectId), `${id}.${extension}`);
1029
1259
  },
1030
- tmpAsset: (id, extension) => {
1031
- return Path.join(pathTo.tmp, `${id}.${extension}`);
1260
+ tmpAsset: (id, commitHash, extension) => {
1261
+ return Path.join(pathTo.tmp, `${id}.${commitHash}.${extension}`);
1032
1262
  }
1033
1263
  };
1034
1264
  function notEmpty(value) {
@@ -1107,6 +1337,7 @@ var AbstractCrudService = class {
1107
1337
  throw new RequiredParameterMissingError("projectId");
1108
1338
  }
1109
1339
  return this.getFileReferences(pathTo.lfs(projectId));
1340
+ // LFS folder is correct, since we want the extension of the file itself, not the AssetFile (.json)
1110
1341
  case objectTypeSchema.Enum.project:
1111
1342
  return this.getFolderReferences(pathTo.projects);
1112
1343
  case objectTypeSchema.Enum.collection:
@@ -1279,11 +1510,11 @@ var AssetService = class extends AbstractCrudService {
1279
1510
  "binary"
1280
1511
  );
1281
1512
  await Fs2.writeFile(
1282
- pathTo.tmpAsset(assetFile.id, assetFile.extension),
1513
+ pathTo.tmpAsset(assetFile.id, props.commitHash, assetFile.extension),
1283
1514
  assetBlob,
1284
1515
  "binary"
1285
1516
  );
1286
- return this.toAsset(props.projectId, assetFile, true);
1517
+ return this.toAsset(props.projectId, assetFile, props.commitHash);
1287
1518
  }
1288
1519
  }
1289
1520
  /**
@@ -1407,8 +1638,8 @@ var AssetService = class extends AbstractCrudService {
1407
1638
  * @param projectId The project's ID
1408
1639
  * @param assetFile The AssetFile to convert
1409
1640
  */
1410
- async toAsset(projectId, assetFile, isFromHistory = false) {
1411
- const assetPath = isFromHistory === false ? pathTo.asset(projectId, assetFile.id, assetFile.extension) : pathTo.tmpAsset(assetFile.id, assetFile.extension);
1641
+ async toAsset(projectId, assetFile, commitHash) {
1642
+ const assetPath = commitHash ? pathTo.tmpAsset(assetFile.id, commitHash, assetFile.extension) : pathTo.asset(projectId, assetFile.id, assetFile.extension);
1412
1643
  const history = await this.gitService.log(pathTo.project(projectId), {
1413
1644
  filePath: pathTo.assetFile(projectId, assetFile.id)
1414
1645
  });
@@ -1914,6 +2145,11 @@ var EntryService = class extends AbstractCrudService {
1914
2145
  collectionId: props.collectionId,
1915
2146
  id: props.valueContentReference.id
1916
2147
  });
2148
+ // case objectTypeSchema.Enum.sharedValue:
2149
+ // return this.resolveValueContentReferenceToSharedValue({
2150
+ // projectId: props.projectId,
2151
+ // valueContentReferenceToSharedValue: props.valueContentReference,
2152
+ // });
1917
2153
  default:
1918
2154
  throw new Error(
1919
2155
  // @ts-ignore
@@ -3437,7 +3673,7 @@ var UserService = class {
3437
3673
  return await this.jsonFileService.read(pathTo.userFile, userFileSchema);
3438
3674
  } catch (error) {
3439
3675
  this.logService.info("No User found");
3440
- return void 0;
3676
+ return null;
3441
3677
  }
3442
3678
  }
3443
3679
  /**
@@ -3471,6 +3707,7 @@ var ElekIoCore = class {
3471
3707
  projectService;
3472
3708
  collectionService;
3473
3709
  entryService;
3710
+ localApi;
3474
3711
  constructor(props) {
3475
3712
  this.coreVersion = version;
3476
3713
  const parsedProps = constructorElekIoCoreSchema.parse(props);
@@ -3521,6 +3758,7 @@ var ElekIoCore = class {
3521
3758
  this.collectionService,
3522
3759
  this.entryService
3523
3760
  );
3761
+ this.localApi = new LocalApi(this.logService, this.projectService);
3524
3762
  this.logService.info(`Initializing elek.io Core ${this.coreVersion}`, {
3525
3763
  options: this.options
3526
3764
  });
@@ -3576,6 +3814,13 @@ var ElekIoCore = class {
3576
3814
  get entries() {
3577
3815
  return this.entryService;
3578
3816
  }
3817
+ /**
3818
+ * Allows starting and stopping a REST API
3819
+ * to allow developers to read local Project data
3820
+ */
3821
+ get api() {
3822
+ return this.localApi;
3823
+ }
3579
3824
  };
3580
3825
  export {
3581
3826
  BooleanFieldDefinitionBaseSchema,
@@ -3655,6 +3900,7 @@ export {
3655
3900
  numberFieldDefinitionSchema,
3656
3901
  objectTypeSchema,
3657
3902
  outdatedProjectSchema,
3903
+ paginatedListOf,
3658
3904
  projectBranchSchema,
3659
3905
  projectExportSchema,
3660
3906
  projectFileSchema,