@elek-io/core 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,29 +5,9 @@ var __export = (target, all) => {
5
5
  };
6
6
 
7
7
  // src/index.ts
8
- import {
9
- constructorElekIoCoreSchema
10
- } from "@elek-io/shared";
11
8
  import Fs7 from "fs-extra";
12
9
 
13
10
  // src/service/AssetService.ts
14
- import {
15
- assetFileSchema,
16
- assetSchema,
17
- countAssetsSchema,
18
- createAssetSchema,
19
- currentTimestamp,
20
- deleteAssetSchema,
21
- listAssetsSchema,
22
- objectTypeSchema as objectTypeSchema2,
23
- readAssetSchema,
24
- serviceTypeSchema as serviceTypeSchema3,
25
- supportedAssetExtensionSchema,
26
- supportedAssetMimeTypeSchema,
27
- supportedAssetTypeSchema,
28
- updateAssetSchema,
29
- uuid as uuid2
30
- } from "@elek-io/shared";
31
11
  import Fs3 from "fs-extra";
32
12
  import IsSvg from "is-svg";
33
13
 
@@ -39,10 +19,332 @@ var RequiredParameterMissingError = class extends Error {
39
19
  }
40
20
  };
41
21
 
22
+ // src/schema/assetSchema.ts
23
+ import z3 from "zod";
24
+
25
+ // src/schema/baseSchema.ts
26
+ import z from "zod";
27
+ var environmentSchema = z.enum(["production", "development", "test"]);
28
+ var supportedLanguageSchema = z.enum([
29
+ /**
30
+ * Bulgarian
31
+ */
32
+ "bg",
33
+ //
34
+ "cs",
35
+ // Czech
36
+ "da",
37
+ // Danish
38
+ "de",
39
+ // German
40
+ "el",
41
+ // Greek
42
+ "en",
43
+ // (US) English
44
+ "es",
45
+ // Spanish
46
+ "et",
47
+ // Estonian
48
+ "fi",
49
+ // Finnish
50
+ "fr",
51
+ // French
52
+ "hu",
53
+ // Hungarian
54
+ "it",
55
+ // Italian
56
+ "ja",
57
+ // Japanese
58
+ "lt",
59
+ // Lithuanian
60
+ "lv",
61
+ // Latvian
62
+ "nl",
63
+ // Dutch
64
+ "pl",
65
+ // Polish
66
+ "pt",
67
+ // Portuguese
68
+ "ro",
69
+ // Romanian
70
+ "ru",
71
+ // Russian
72
+ "sk",
73
+ // Slovak
74
+ "sl",
75
+ // Slovenian
76
+ "sv",
77
+ // Swedish
78
+ "zh"
79
+ // (Simplified) Chinese
80
+ ]);
81
+ var supportedIconSchema = z.enum(["home", "plus", "foobar"]);
82
+ var supportedAssetMimeTypeSchema = z.enum([
83
+ "image/avif",
84
+ "image/gif",
85
+ "image/jpeg",
86
+ "image/png",
87
+ "image/svg+xml",
88
+ "image/webp",
89
+ "application/pdf",
90
+ "application/zip",
91
+ "video/mp4",
92
+ "video/webm",
93
+ "audio/webm",
94
+ "audio/flac"
95
+ ]);
96
+ var supportedAssetExtensionSchema = z.enum([
97
+ "avif",
98
+ "gif",
99
+ "jpg",
100
+ "jpeg",
101
+ "png",
102
+ "svg",
103
+ "webp",
104
+ "pdf",
105
+ "zip",
106
+ "mp4",
107
+ "webm",
108
+ "flac",
109
+ "json"
110
+ ]);
111
+ var supportedAssetTypeSchema = z.object({
112
+ extension: supportedAssetExtensionSchema,
113
+ mimeType: supportedAssetMimeTypeSchema
114
+ });
115
+ var objectTypeSchema = z.enum([
116
+ "project",
117
+ "asset",
118
+ "collection",
119
+ "entry",
120
+ "value",
121
+ "sharedValue"
122
+ ]);
123
+ var versionSchema = z.string();
124
+ var uuidSchema = z.string().uuid("shared.invalidUuid");
125
+ var translatableStringSchema = z.record(
126
+ supportedLanguageSchema,
127
+ z.string().trim().min(1, "shared.translatableStringRequired")
128
+ );
129
+ var translatableNumberSchema = z.record(
130
+ supportedLanguageSchema,
131
+ z.number({ required_error: "shared.translatableNumberRequired" })
132
+ );
133
+ var translatableBooleanSchema = z.record(
134
+ supportedLanguageSchema,
135
+ z.boolean({ required_error: "shared.translatableBooleanRequired" })
136
+ );
137
+ function translatableArrayOf(schema) {
138
+ return z.record(supportedLanguageSchema, z.array(schema));
139
+ }
140
+
141
+ // src/schema/fileSchema.ts
142
+ import z2 from "zod";
143
+ var baseFileSchema = z2.object({
144
+ /**
145
+ * The ID of the file
146
+ *
147
+ * The ID is part of the files name.
148
+ */
149
+ id: uuidSchema.readonly(),
150
+ /**
151
+ * The timestamp of the file being created is set by the service of "objectType" while creating it
152
+ */
153
+ created: z2.number().readonly(),
154
+ /**
155
+ * The timestamp of the file being updated is set by the service of "objectType" while updating it
156
+ */
157
+ updated: z2.number().nullable()
158
+ });
159
+ var baseFileWithLanguageSchema = baseFileSchema.extend({
160
+ /**
161
+ * The language of the file
162
+ *
163
+ * The language is part of the files name and together with it's ID the only unique identifier.
164
+ * That's why the language cannot be changed after creating the file.
165
+ *
166
+ * @todo Maybe remove the above restriction by implementing logic to handle changing the files language inside all services
167
+ */
168
+ language: supportedLanguageSchema.readonly()
169
+ });
170
+ var fileReferenceSchema = z2.object({
171
+ id: uuidSchema,
172
+ language: supportedLanguageSchema.optional(),
173
+ extension: supportedAssetExtensionSchema.optional()
174
+ });
175
+
176
+ // src/schema/assetSchema.ts
177
+ var assetFileSchema = baseFileWithLanguageSchema.extend({
178
+ objectType: z3.literal(objectTypeSchema.Enum.asset).readonly(),
179
+ name: z3.string(),
180
+ description: z3.string(),
181
+ extension: supportedAssetExtensionSchema.readonly(),
182
+ mimeType: supportedAssetMimeTypeSchema.readonly(),
183
+ /**
184
+ * Total size in bytes
185
+ */
186
+ size: z3.number().readonly()
187
+ });
188
+ var assetSchema = assetFileSchema.extend({
189
+ /**
190
+ * Absolute path on this filesystem
191
+ */
192
+ absolutePath: z3.string().readonly()
193
+ });
194
+ var assetExportSchema = assetSchema.extend({});
195
+ var createAssetSchema = assetFileSchema.pick({
196
+ name: true,
197
+ description: true,
198
+ language: true
199
+ }).extend({
200
+ projectId: uuidSchema.readonly(),
201
+ /**
202
+ * Path of the file to add as a new Asset
203
+ */
204
+ filePath: z3.string().readonly()
205
+ });
206
+ var readAssetSchema = assetFileSchema.pick({
207
+ id: true,
208
+ language: true
209
+ }).extend({
210
+ projectId: uuidSchema.readonly()
211
+ });
212
+ var updateAssetSchema = assetFileSchema.pick({
213
+ id: true,
214
+ name: true,
215
+ description: true,
216
+ language: true
217
+ }).extend({
218
+ projectId: uuidSchema.readonly(),
219
+ /**
220
+ * Path of the new file to update the Asset with
221
+ */
222
+ newFilePath: z3.string().readonly().optional()
223
+ });
224
+ var deleteAssetSchema = assetFileSchema.pick({
225
+ id: true,
226
+ language: true,
227
+ extension: true
228
+ }).extend({
229
+ projectId: uuidSchema.readonly()
230
+ });
231
+ var countAssetsSchema = z3.object({ projectId: uuidSchema.readonly() });
232
+
233
+ // src/schema/serviceSchema.ts
234
+ import { z as z5 } from "zod";
235
+
236
+ // src/schema/gitSchema.ts
237
+ import { z as z4 } from "zod";
238
+ var gitRepositoryPathSchema = z4.string();
239
+ var gitSignatureSchema = z4.object({
240
+ name: z4.string(),
241
+ email: z4.string()
242
+ });
243
+ var gitCommitSchema = z4.object({
244
+ /**
245
+ * SHA-1 hash of the commit
246
+ */
247
+ hash: z4.string(),
248
+ message: z4.string(),
249
+ author: gitSignatureSchema,
250
+ timestamp: z4.number(),
251
+ tag: z4.string().nullable()
252
+ });
253
+ var GitCommitIconNative = /* @__PURE__ */ ((GitCommitIconNative2) => {
254
+ GitCommitIconNative2["INIT"] = ":tada:";
255
+ GitCommitIconNative2["CREATE"] = ":heavy_plus_sign:";
256
+ GitCommitIconNative2["UPDATE"] = ":wrench:";
257
+ GitCommitIconNative2["DELETE"] = ":fire:";
258
+ return GitCommitIconNative2;
259
+ })(GitCommitIconNative || {});
260
+ var gitCommitIconSchema = z4.nativeEnum(GitCommitIconNative);
261
+ var gitInitOptionsSchema = z4.object({
262
+ /**
263
+ * Use the specified name for the initial branch in the newly created repository. If not specified, fall back to the default name (currently master, but this is subject to change in the future; the name can be customized via the init.defaultBranch configuration variable).
264
+ */
265
+ initialBranch: z4.string()
266
+ });
267
+ var gitCloneOptionsSchema = z4.object({
268
+ /**
269
+ * Create a shallow clone with a history truncated to the specified number of commits. Implies --single-branch unless --no-single-branch is given to fetch the histories near the tips of all branches. If you want to clone submodules shallowly, also pass --shallow-submodules.
270
+ */
271
+ depth: z4.number(),
272
+ /**
273
+ * Clone only the history leading to the tip of a single branch, either specified by the --branch option or the primary branch remote’s HEAD points at. Further fetches into the resulting repository will only update the remote-tracking branch for the branch this option was used for the initial cloning. If the HEAD at the remote did not point at any branch when --single-branch clone was made, no remote-tracking branch is created.
274
+ */
275
+ singleBranch: z4.boolean(),
276
+ /**
277
+ * Instead of pointing the newly created HEAD to the branch pointed to by the cloned repository’s HEAD, point to <name> branch instead. In a non-bare repository, this is the branch that will be checked out. --branch can also take tags and detaches the HEAD at that commit in the resulting repository.
278
+ */
279
+ branch: z4.string()
280
+ });
281
+ var gitSwitchOptionsSchema = z4.object({
282
+ /**
283
+ * If true, creates a new local branch and then switches to it
284
+ *
285
+ * @see https://git-scm.com/docs/git-switch#Documentation/git-switch.txt---createltnew-branchgt
286
+ */
287
+ isNew: z4.boolean().optional()
288
+ });
289
+ var gitLogOptionsSchema = z4.object({
290
+ /**
291
+ * Limit the result to given number of commits
292
+ */
293
+ limit: z4.number().optional(),
294
+ /**
295
+ * Only list commits that are between given SHAs or tag names
296
+ *
297
+ * Note that the commits of from and to are not included in the result
298
+ */
299
+ between: z4.object({
300
+ /**
301
+ * From the oldest commit
302
+ */
303
+ from: z4.string(),
304
+ /**
305
+ * To the newest commit
306
+ *
307
+ * Defaults to the current HEAD
308
+ */
309
+ to: z4.string().optional()
310
+ })
311
+ });
312
+
313
+ // src/schema/serviceSchema.ts
314
+ var serviceTypeSchema = z5.enum([
315
+ "Git",
316
+ "GitTag",
317
+ "User",
318
+ "Project",
319
+ "Asset",
320
+ "JsonFile",
321
+ "Search",
322
+ "Collection",
323
+ "Entry",
324
+ "Value"
325
+ ]);
326
+ var listSchema = z5.object({
327
+ projectId: uuidSchema,
328
+ limit: z5.number().optional(),
329
+ offset: z5.number().optional()
330
+ });
331
+ var listCollectionsSchema = listSchema;
332
+ var listEntriesSchema = listSchema.extend({
333
+ collectionId: uuidSchema
334
+ });
335
+ var listAssetsSchema = listSchema;
336
+ var listProjectsSchema = listSchema.omit({
337
+ projectId: true
338
+ });
339
+ var listGitTagsSchema = z5.object({
340
+ path: gitRepositoryPathSchema
341
+ });
342
+
42
343
  // src/util/index.ts
43
344
  var util_exports = {};
44
345
  __export(util_exports, {
45
346
  assignDefaultIfMissing: () => assignDefaultIfMissing,
347
+ currentTimestamp: () => currentTimestamp,
46
348
  files: () => files,
47
349
  folders: () => folders,
48
350
  fromPath: () => fromPath,
@@ -52,15 +354,543 @@ __export(util_exports, {
52
354
  notEmpty: () => notEmpty,
53
355
  pathTo: () => pathTo,
54
356
  returnResolved: () => returnResolved,
357
+ slug: () => slug,
55
358
  spawnChildProcess: () => spawnChildProcess,
359
+ uuid: () => uuid,
56
360
  workingDirectory: () => workingDirectory
57
361
  });
58
- import { projectFolderSchema, uuidSchema } from "@elek-io/shared";
59
362
  import { spawn } from "child_process";
60
363
  import Fs from "fs-extra";
61
364
  import { filter, flatten, groupBy, uniq } from "lodash-es";
62
365
  import Os from "os";
63
366
  import Path from "path";
367
+ import slugify from "slugify";
368
+ import { v4 as generateUuid } from "uuid";
369
+
370
+ // src/schema/projectSchema.ts
371
+ import { z as z9 } from "zod";
372
+
373
+ // src/schema/collectionSchema.ts
374
+ import z8 from "zod";
375
+
376
+ // src/schema/entrySchema.ts
377
+ import z7 from "zod";
378
+
379
+ // src/schema/valueSchema.ts
380
+ import z6 from "zod";
381
+ var ValueTypeSchema = z6.enum([
382
+ "string",
383
+ "number",
384
+ "boolean",
385
+ "reference"
386
+ ]);
387
+ var ValueInputTypeSchema = z6.enum([
388
+ // String
389
+ "text",
390
+ "textarea",
391
+ "email",
392
+ // 'password', @todo maybe if there is a usecase
393
+ "url",
394
+ "ip",
395
+ "date",
396
+ "time",
397
+ "datetime",
398
+ "telephone",
399
+ // Number
400
+ "number",
401
+ "range",
402
+ // Boolean
403
+ "toggle",
404
+ // Reference
405
+ "asset",
406
+ "entry"
407
+ // 'sharedValue', // @todo
408
+ ]);
409
+ var ValueInputWidthSchema = z6.enum(["12", "6", "4", "3"]);
410
+ var ValueDefinitionBaseSchema = z6.object({
411
+ id: uuidSchema.readonly(),
412
+ label: translatableStringSchema,
413
+ description: translatableStringSchema,
414
+ isRequired: z6.boolean(),
415
+ isDisabled: z6.boolean(),
416
+ isUnique: z6.boolean(),
417
+ inputWidth: ValueInputWidthSchema
418
+ });
419
+ var StringValueDefinitionBaseSchema = ValueDefinitionBaseSchema.extend(
420
+ {
421
+ valueType: z6.literal(ValueTypeSchema.Enum.string),
422
+ defaultValue: z6.string().nullable()
423
+ }
424
+ );
425
+ var textValueDefinitionSchema = StringValueDefinitionBaseSchema.extend(
426
+ {
427
+ inputType: z6.literal(ValueInputTypeSchema.Enum.text),
428
+ min: z6.number().nullable(),
429
+ max: z6.number().nullable()
430
+ }
431
+ );
432
+ var textareaValueDefinitionSchema = StringValueDefinitionBaseSchema.extend({
433
+ inputType: z6.literal(ValueInputTypeSchema.Enum.textarea),
434
+ min: z6.number().nullable(),
435
+ max: z6.number().nullable()
436
+ });
437
+ var emailValueDefinitionSchema = StringValueDefinitionBaseSchema.extend({
438
+ inputType: z6.literal(ValueInputTypeSchema.Enum.email),
439
+ defaultValue: z6.string().email().nullable()
440
+ });
441
+ var urlValueDefinitionSchema = StringValueDefinitionBaseSchema.extend({
442
+ inputType: z6.literal(ValueInputTypeSchema.Enum.url),
443
+ defaultValue: z6.string().url().nullable()
444
+ });
445
+ var ipValueDefinitionSchema = StringValueDefinitionBaseSchema.extend({
446
+ inputType: z6.literal(ValueInputTypeSchema.Enum.ip),
447
+ defaultValue: z6.string().ip().nullable()
448
+ });
449
+ var dateValueDefinitionSchema = StringValueDefinitionBaseSchema.extend(
450
+ {
451
+ inputType: z6.literal(ValueInputTypeSchema.Enum.date),
452
+ defaultValue: z6.string().date().nullable()
453
+ }
454
+ );
455
+ var timeValueDefinitionSchema = StringValueDefinitionBaseSchema.extend(
456
+ {
457
+ inputType: z6.literal(ValueInputTypeSchema.Enum.time),
458
+ defaultValue: z6.string().time().nullable()
459
+ }
460
+ );
461
+ var datetimeValueDefinitionSchema = StringValueDefinitionBaseSchema.extend({
462
+ inputType: z6.literal(ValueInputTypeSchema.Enum.datetime),
463
+ defaultValue: z6.string().datetime().nullable()
464
+ });
465
+ var telephoneValueDefinitionSchema = StringValueDefinitionBaseSchema.extend({
466
+ inputType: z6.literal(ValueInputTypeSchema.Enum.telephone)
467
+ // defaultValue: z.string().e164(), @todo when zod v4 releases @see https://github.com/colinhacks/zod/pull/3476
468
+ });
469
+ var stringValueDefinitionSchema = z6.union([
470
+ textValueDefinitionSchema,
471
+ textareaValueDefinitionSchema,
472
+ emailValueDefinitionSchema,
473
+ urlValueDefinitionSchema,
474
+ ipValueDefinitionSchema,
475
+ dateValueDefinitionSchema,
476
+ timeValueDefinitionSchema,
477
+ datetimeValueDefinitionSchema,
478
+ telephoneValueDefinitionSchema
479
+ ]);
480
+ var NumberValueDefinitionBaseSchema = ValueDefinitionBaseSchema.extend(
481
+ {
482
+ valueType: z6.literal(ValueTypeSchema.Enum.number),
483
+ min: z6.number().nullable(),
484
+ max: z6.number().nullable(),
485
+ isUnique: z6.literal(false),
486
+ defaultValue: z6.number().nullable()
487
+ }
488
+ );
489
+ var numberValueDefinitionSchema = NumberValueDefinitionBaseSchema.extend({
490
+ inputType: z6.literal(ValueInputTypeSchema.Enum.number)
491
+ });
492
+ var rangeValueDefinitionSchema = NumberValueDefinitionBaseSchema.extend({
493
+ inputType: z6.literal(ValueInputTypeSchema.Enum.range),
494
+ // Overwrite from nullable to required because a range needs min, max and default to work and is required, since it always returns a number
495
+ isRequired: z6.literal(true),
496
+ min: z6.number(),
497
+ max: z6.number(),
498
+ defaultValue: z6.number()
499
+ });
500
+ var BooleanValueDefinitionBaseSchema = ValueDefinitionBaseSchema.extend({
501
+ valueType: z6.literal(ValueTypeSchema.Enum.boolean),
502
+ // Overwrite from nullable to required because a boolean needs a default to work and is required, since it always is either true or false
503
+ isRequired: z6.literal(true),
504
+ defaultValue: z6.boolean(),
505
+ isUnique: z6.literal(false)
506
+ });
507
+ var toggleValueDefinitionSchema = BooleanValueDefinitionBaseSchema.extend({
508
+ inputType: z6.literal(ValueInputTypeSchema.Enum.toggle)
509
+ });
510
+ var ReferenceValueDefinitionBaseSchema = ValueDefinitionBaseSchema.extend({
511
+ valueType: z6.literal(ValueTypeSchema.Enum.reference)
512
+ });
513
+ var assetValueDefinitionSchema = ReferenceValueDefinitionBaseSchema.extend({
514
+ inputType: z6.literal(ValueInputTypeSchema.Enum.asset),
515
+ allowedMimeTypes: z6.array(supportedAssetMimeTypeSchema).min(1),
516
+ min: z6.number().nullable(),
517
+ max: z6.number().nullable()
518
+ });
519
+ var entryValueDefinitionSchema = ReferenceValueDefinitionBaseSchema.extend({
520
+ inputType: z6.literal(ValueInputTypeSchema.Enum.entry),
521
+ ofCollections: z6.array(uuidSchema),
522
+ min: z6.number().nullable(),
523
+ max: z6.number().nullable()
524
+ });
525
+ var valueDefinitionSchema = z6.union([
526
+ stringValueDefinitionSchema,
527
+ numberValueDefinitionSchema,
528
+ rangeValueDefinitionSchema,
529
+ toggleValueDefinitionSchema,
530
+ assetValueDefinitionSchema,
531
+ entryValueDefinitionSchema
532
+ // sharedValueDefinitionSchema,
533
+ ]);
534
+ var valueContentReferenceBase = z6.object({
535
+ id: uuidSchema
536
+ });
537
+ var valueContentReferenceWithLanguageBase = valueContentReferenceBase.extend({
538
+ language: supportedLanguageSchema
539
+ });
540
+ var valueContentReferenceToAssetSchema = valueContentReferenceWithLanguageBase.extend({
541
+ objectType: z6.literal(objectTypeSchema.Enum.asset)
542
+ });
543
+ var valueContentReferenceToCollectionSchema = valueContentReferenceBase.extend({
544
+ objectType: z6.literal(objectTypeSchema.Enum.collection)
545
+ });
546
+ var valueContentReferenceToEntrySchema = valueContentReferenceBase.extend({
547
+ objectType: z6.literal(objectTypeSchema.Enum.entry)
548
+ });
549
+ var valueContentReferenceSchema = z6.union([
550
+ valueContentReferenceToAssetSchema,
551
+ valueContentReferenceToCollectionSchema,
552
+ valueContentReferenceToEntrySchema
553
+ // valueContentReferenceToSharedValueSchema,
554
+ ]);
555
+ var resolvedValueContentReferenceSchema = z6.union([
556
+ assetSchema,
557
+ z6.lazy(() => entrySchema)
558
+ // Circular dependency / recursive type @see https://github.com/colinhacks/zod?tab=readme-ov-file#recursive-types
559
+ // resolvedValueContentReferenceToSharedValueSchema,
560
+ ]);
561
+ var directValueBaseSchema = z6.object({
562
+ objectType: z6.literal(objectTypeSchema.Enum.value).readonly(),
563
+ definitionId: uuidSchema.readonly()
564
+ });
565
+ var directStringValueSchema = directValueBaseSchema.extend({
566
+ valueType: z6.literal(ValueTypeSchema.Enum.string).readonly(),
567
+ content: translatableStringSchema
568
+ });
569
+ var directNumberValueSchema = directValueBaseSchema.extend({
570
+ valueType: z6.literal(ValueTypeSchema.Enum.number).readonly(),
571
+ content: translatableNumberSchema
572
+ });
573
+ var directBooleanValueSchema = directValueBaseSchema.extend({
574
+ valueType: z6.literal(ValueTypeSchema.Enum.boolean).readonly(),
575
+ content: translatableBooleanSchema
576
+ });
577
+ var directValueSchema = z6.union([
578
+ directStringValueSchema,
579
+ directNumberValueSchema,
580
+ directBooleanValueSchema
581
+ ]);
582
+ var referencedValueSchema = z6.object({
583
+ objectType: z6.literal(objectTypeSchema.Enum.value).readonly(),
584
+ definitionId: uuidSchema.readonly(),
585
+ valueType: z6.literal(ValueTypeSchema.Enum.reference).readonly(),
586
+ content: translatableArrayOf(valueContentReferenceSchema)
587
+ });
588
+ var valueSchema = z6.union([directValueSchema, referencedValueSchema]);
589
+ var resolvedReferencedValueSchema = referencedValueSchema.extend({
590
+ content: translatableArrayOf(resolvedValueContentReferenceSchema)
591
+ });
592
+ var resolvedValueSchema = z6.union([
593
+ directValueSchema,
594
+ resolvedReferencedValueSchema
595
+ ]);
596
+ function getValueContentSchemaFromDefinition(definition) {
597
+ switch (definition.valueType) {
598
+ case ValueTypeSchema.Enum.boolean:
599
+ return getBooleanValueContentSchema(definition);
600
+ case ValueTypeSchema.Enum.number:
601
+ return getNumberValueContentSchema(definition);
602
+ case ValueTypeSchema.Enum.string:
603
+ return getStringValueContentSchema(definition);
604
+ case ValueTypeSchema.Enum.reference:
605
+ return getReferenceValueContentSchema(definition);
606
+ default:
607
+ throw new Error(
608
+ // @ts-expect-error
609
+ `Error generating schema for unsupported ValueType "${definition.valueType}"`
610
+ );
611
+ }
612
+ }
613
+ function getBooleanValueContentSchema(definition) {
614
+ return z6.boolean();
615
+ }
616
+ function getNumberValueContentSchema(definition) {
617
+ let schema = z6.number();
618
+ if (definition.min) {
619
+ schema = schema.min(definition.min);
620
+ }
621
+ if (definition.max) {
622
+ schema = schema.max(definition.max);
623
+ }
624
+ if (definition.isRequired === false) {
625
+ return schema.nullable();
626
+ }
627
+ return schema;
628
+ }
629
+ function getStringValueContentSchema(definition) {
630
+ let schema = z6.string().trim();
631
+ if ("min" in definition && definition.min) {
632
+ schema = schema.min(definition.min);
633
+ }
634
+ if ("max" in definition && definition.max) {
635
+ schema = schema.max(definition.max);
636
+ }
637
+ switch (definition.inputType) {
638
+ case ValueInputTypeSchema.Enum.email:
639
+ schema = schema.email();
640
+ break;
641
+ case ValueInputTypeSchema.Enum.url:
642
+ schema = schema.url();
643
+ break;
644
+ case ValueInputTypeSchema.Enum.ip:
645
+ schema = schema.ip();
646
+ break;
647
+ case ValueInputTypeSchema.Enum.date:
648
+ schema = schema.date();
649
+ break;
650
+ case ValueInputTypeSchema.Enum.time:
651
+ schema = schema.time();
652
+ break;
653
+ case ValueInputTypeSchema.Enum.datetime:
654
+ schema = schema.datetime();
655
+ break;
656
+ case ValueInputTypeSchema.Enum.telephone:
657
+ break;
658
+ }
659
+ if (definition.isRequired === false) {
660
+ return schema.nullable();
661
+ }
662
+ return schema.min(1, "shared.stringValueRequired");
663
+ }
664
+ function getReferenceValueContentSchema(definition) {
665
+ let schema;
666
+ switch (definition.inputType) {
667
+ case ValueInputTypeSchema.Enum.asset:
668
+ {
669
+ schema = z6.array(valueContentReferenceToAssetSchema);
670
+ }
671
+ break;
672
+ case ValueInputTypeSchema.Enum.entry:
673
+ {
674
+ schema = z6.array(valueContentReferenceToEntrySchema);
675
+ }
676
+ break;
677
+ }
678
+ if (definition.isRequired) {
679
+ schema = schema.min(1, "shared.referenceRequired");
680
+ }
681
+ if (definition.min) {
682
+ schema = schema.min(definition.min);
683
+ }
684
+ if (definition.max) {
685
+ schema = schema.max(definition.max);
686
+ }
687
+ return schema;
688
+ }
689
+
690
+ // src/schema/entrySchema.ts
691
+ var entryFileSchema = baseFileSchema.extend({
692
+ objectType: z7.literal(objectTypeSchema.Enum.entry).readonly(),
693
+ values: z7.array(valueSchema)
694
+ });
695
+ var entrySchema = entryFileSchema.extend({
696
+ values: z7.array(z7.lazy(() => resolvedValueSchema))
697
+ });
698
+ var entryExportSchema = entrySchema.extend({});
699
+ var createEntrySchema = entryFileSchema.omit({
700
+ id: true,
701
+ objectType: true,
702
+ created: true,
703
+ updated: true
704
+ }).extend({
705
+ projectId: uuidSchema.readonly(),
706
+ collectionId: uuidSchema.readonly(),
707
+ values: z7.array(valueSchema)
708
+ });
709
+ var readEntrySchema = z7.object({
710
+ id: uuidSchema.readonly(),
711
+ projectId: uuidSchema.readonly(),
712
+ collectionId: uuidSchema.readonly()
713
+ });
714
+ var updateEntrySchema = entrySchema.omit({
715
+ objectType: true,
716
+ created: true,
717
+ updated: true
718
+ }).extend({
719
+ projectId: uuidSchema.readonly(),
720
+ collectionId: uuidSchema.readonly()
721
+ });
722
+ var deleteEntrySchema = readEntrySchema.extend({});
723
+ var countEntriesSchema = z7.object({
724
+ projectId: uuidSchema.readonly(),
725
+ collectionId: uuidSchema.readonly()
726
+ });
727
+
728
+ // src/schema/collectionSchema.ts
729
+ var collectionFileSchema = baseFileSchema.extend({
730
+ objectType: z8.literal(objectTypeSchema.Enum.collection).readonly(),
731
+ name: z8.object({
732
+ singular: translatableStringSchema,
733
+ plural: translatableStringSchema
734
+ }),
735
+ slug: z8.object({
736
+ singular: z8.string(),
737
+ plural: z8.string()
738
+ }),
739
+ description: translatableStringSchema,
740
+ icon: supportedIconSchema,
741
+ valueDefinitions: z8.array(valueDefinitionSchema)
742
+ });
743
+ var collectionSchema = collectionFileSchema.extend({});
744
+ var collectionExportSchema = collectionSchema.extend({
745
+ entries: z8.array(entryExportSchema)
746
+ });
747
+ var createCollectionSchema = collectionSchema.omit({
748
+ id: true,
749
+ objectType: true,
750
+ created: true,
751
+ updated: true
752
+ }).extend({
753
+ projectId: uuidSchema.readonly()
754
+ });
755
+ var readCollectionSchema = z8.object({
756
+ id: uuidSchema.readonly(),
757
+ projectId: uuidSchema.readonly()
758
+ });
759
+ var updateCollectionSchema = collectionFileSchema.pick({
760
+ id: true,
761
+ name: true,
762
+ slug: true,
763
+ description: true,
764
+ icon: true,
765
+ valueDefinitions: true
766
+ }).extend({
767
+ projectId: uuidSchema.readonly()
768
+ });
769
+ var deleteCollectionSchema = readCollectionSchema.extend({});
770
+ var countCollectionsSchema = z8.object({
771
+ projectId: uuidSchema.readonly()
772
+ });
773
+
774
+ // src/schema/projectSchema.ts
775
+ var projectStatusSchema = z9.enum(["foo", "bar", "todo"]);
776
+ var projectSettingsSchema = z9.object({
777
+ language: z9.object({
778
+ default: supportedLanguageSchema,
779
+ supported: z9.array(supportedLanguageSchema)
780
+ })
781
+ });
782
+ var projectFolderSchema = z9.enum([
783
+ "assets",
784
+ "collections",
785
+ "shared-values",
786
+ "lfs"
787
+ // 'logs',
788
+ // 'public',
789
+ // 'theme',
790
+ ]);
791
+ var projectFileSchema = baseFileSchema.extend({
792
+ objectType: z9.literal(objectTypeSchema.Enum.project).readonly(),
793
+ coreVersion: versionSchema,
794
+ name: z9.string().trim().min(1, "shared.projectNameRequired"),
795
+ description: z9.string().trim().min(1, "shared.projectDescriptionRequired"),
796
+ version: versionSchema,
797
+ status: projectStatusSchema,
798
+ settings: projectSettingsSchema
799
+ });
800
+ var projectSchema = projectFileSchema.extend({});
801
+ var projectExportSchema = projectSchema.extend({
802
+ assets: z9.array(assetExportSchema),
803
+ collections: z9.array(collectionExportSchema)
804
+ });
805
+ var createProjectSchema = projectSchema.pick({
806
+ name: true,
807
+ description: true,
808
+ settings: true
809
+ }).partial({
810
+ description: true,
811
+ settings: true
812
+ });
813
+ var readProjectSchema = z9.object({
814
+ id: uuidSchema.readonly()
815
+ });
816
+ var updateProjectSchema = projectSchema.pick({
817
+ id: true,
818
+ name: true,
819
+ description: true,
820
+ settings: true
821
+ }).partial({
822
+ name: true,
823
+ description: true,
824
+ settings: true
825
+ });
826
+ var upgradeProjectSchema = z9.object({
827
+ id: uuidSchema.readonly()
828
+ });
829
+ var deleteProjectSchema = readProjectSchema.extend({});
830
+ var projectUpgradeSchema = z9.object({
831
+ /**
832
+ * The Core version the Project will be upgraded to
833
+ */
834
+ to: versionSchema.readonly(),
835
+ /**
836
+ * Function that will be executed in the process of upgrading a Project
837
+ */
838
+ run: z9.function().args(projectFileSchema).returns(z9.promise(z9.void()))
839
+ });
840
+ var cloneProjectSchema = z9.object({
841
+ url: z9.string()
842
+ });
843
+ var listBranchesProjectSchema = z9.object({
844
+ id: uuidSchema.readonly()
845
+ });
846
+ var currentBranchProjectSchema = z9.object({
847
+ id: uuidSchema.readonly()
848
+ });
849
+ var switchBranchProjectSchema = z9.object({
850
+ id: uuidSchema.readonly(),
851
+ branch: z9.string(),
852
+ options: gitSwitchOptionsSchema.optional()
853
+ });
854
+ var getRemoteOriginUrlProjectSchema = z9.object({
855
+ id: uuidSchema.readonly()
856
+ });
857
+ var setRemoteOriginUrlProjectSchema = z9.object({
858
+ id: uuidSchema.readonly(),
859
+ url: z9.string()
860
+ });
861
+ var getChangesProjectSchema = z9.object({
862
+ id: uuidSchema.readonly()
863
+ });
864
+ var synchronizeProjectSchema = z9.object({
865
+ id: uuidSchema.readonly()
866
+ });
867
+ var searchProjectSchema = z9.object({
868
+ id: uuidSchema.readonly(),
869
+ query: z9.string(),
870
+ language: supportedLanguageSchema,
871
+ type: z9.array(objectTypeSchema).optional()
872
+ });
873
+
874
+ // src/util/index.ts
875
+ var Slugify = slugify.default || slugify;
876
+ function uuid() {
877
+ return generateUuid();
878
+ }
879
+ function currentTimestamp() {
880
+ return Math.floor(Date.now() / 1e3);
881
+ }
882
+ function slug(string) {
883
+ return Slugify(string, {
884
+ replacement: "-",
885
+ // replace spaces with replacement character, defaults to `-`
886
+ remove: void 0,
887
+ // remove characters that match regex, defaults to `undefined`
888
+ lower: true,
889
+ // convert to lower case, defaults to `false`
890
+ strict: true
891
+ // strip special characters except replacement, defaults to `false`
892
+ });
893
+ }
64
894
  var workingDirectory = Path.join(Os.homedir(), "elek.io");
65
895
  var pathTo = {
66
896
  tmp: Path.join(workingDirectory, "tmp"),
@@ -230,12 +1060,6 @@ function getDuplicates(arr, key) {
230
1060
  }
231
1061
 
232
1062
  // src/service/AbstractCrudService.ts
233
- import {
234
- fileReferenceSchema,
235
- gitCommitIconSchema,
236
- objectTypeSchema
237
- } from "@elek-io/shared";
238
- import { orderBy, remove } from "lodash-es";
239
1063
  var AbstractCrudService = class {
240
1064
  /**
241
1065
  * Do not instantiate directly as this is an abstract class
@@ -249,53 +1073,6 @@ var AbstractCrudService = class {
249
1073
  delete: `${gitCommitIconSchema.enum.DELETE} Deleted ${this.type}`
250
1074
  };
251
1075
  }
252
- /**
253
- * Returns the filtered, sorted and paginated version of given list
254
- *
255
- * @todo Sorting and filtering requires all models to be loaded
256
- * from disk. This results in a huge memory spike before the
257
- * filtering and pagination takes effect - removing most of it again.
258
- * This approach is still better than returning everything and
259
- * letting the frontend handle it, since the memory usage would then be constant.
260
- * But this still could fill the memory limit of node.js (default 1,4 GB).
261
- *
262
- * @param list Array to filter, sort and paginate
263
- * @param sort Array of sort objects containing information about what to sort and how
264
- * @param filter Filter all object values of `list` by this string
265
- * @param limit Limit the result to this amount. If 0 is given, no limit is applied
266
- * @param offset Start at this index instead of 0
267
- */
268
- async paginate(list, sort = [], filter2 = "", limit = 15, offset = 0) {
269
- let result = list;
270
- const total = list.length;
271
- const normalizedFilter = filter2.trim().toLowerCase();
272
- if (normalizedFilter !== "") {
273
- remove(result, (model) => {
274
- let key;
275
- for (key in model) {
276
- const value = model[key];
277
- if (String(value).toLowerCase().includes(normalizedFilter)) {
278
- return false;
279
- }
280
- }
281
- return true;
282
- });
283
- }
284
- if (sort.length !== 0) {
285
- const keys = sort.map((value) => value.by);
286
- const orders = sort.map((value) => value.order);
287
- result = orderBy(result, keys, orders);
288
- }
289
- if (limit !== 0) {
290
- result = result.slice(offset, offset + limit);
291
- }
292
- return {
293
- total,
294
- limit,
295
- offset,
296
- list: result
297
- };
298
- }
299
1076
  /**
300
1077
  * Returns a list of all file references of given project and type
301
1078
  *
@@ -379,11 +1156,8 @@ var AbstractCrudService = class {
379
1156
  };
380
1157
 
381
1158
  // src/service/GitService.ts
382
- import {
383
- gitCommitSchema,
384
- uuidSchema as uuidSchema2
385
- } from "@elek-io/shared";
386
1159
  import { GitProcess } from "dugite";
1160
+ import { EOL as EOL2 } from "os";
387
1161
  import PQueue from "p-queue";
388
1162
 
389
1163
  // src/error/GitError.ts
@@ -403,16 +1177,32 @@ var NoCurrentUserError = class extends Error {
403
1177
  };
404
1178
 
405
1179
  // src/service/GitTagService.ts
406
- import {
407
- countGitTagsSchema,
408
- createGitTagSchema,
409
- deleteGitTagSchema,
410
- gitTagSchema,
411
- listGitTagsSchema,
412
- readGitTagSchema,
413
- serviceTypeSchema,
414
- uuid
415
- } from "@elek-io/shared";
1180
+ import { EOL } from "os";
1181
+
1182
+ // src/schema/gitTagSchema.ts
1183
+ import { z as z10 } from "zod";
1184
+ var gitTagSchema = z10.object({
1185
+ id: uuidSchema,
1186
+ message: z10.string(),
1187
+ author: gitSignatureSchema,
1188
+ timestamp: z10.number()
1189
+ });
1190
+ var createGitTagSchema = gitTagSchema.pick({
1191
+ message: true
1192
+ }).extend({
1193
+ path: gitRepositoryPathSchema,
1194
+ hash: gitCommitSchema.shape.hash.optional()
1195
+ });
1196
+ var readGitTagSchema = z10.object({
1197
+ path: gitRepositoryPathSchema,
1198
+ id: uuidSchema.readonly()
1199
+ });
1200
+ var deleteGitTagSchema = readGitTagSchema.extend({});
1201
+ var countGitTagsSchema = z10.object({
1202
+ path: gitRepositoryPathSchema
1203
+ });
1204
+
1205
+ // src/service/GitTagService.ts
416
1206
  var GitTagService = class extends AbstractCrudService {
417
1207
  constructor(options, git) {
418
1208
  super(serviceTypeSchema.Enum.GitTag, options);
@@ -438,22 +1228,20 @@ var GitTagService = class extends AbstractCrudService {
438
1228
  /**
439
1229
  * Returns a tag by ID
440
1230
  *
441
- * Internally uses list() with id as pattern.
1231
+ * Internally uses list() but only returns the tag with matching ID.
442
1232
  */
443
1233
  async read(props) {
444
1234
  readGitTagSchema.parse(props);
445
- const tags = await this.list({ path: props.path, filter: props.id });
446
- if (tags.total === 0) {
1235
+ const tags = await this.list({ path: props.path });
1236
+ const tag = tags.list.find((tag2) => {
1237
+ return tag2.id === props.id;
1238
+ });
1239
+ if (!tag) {
447
1240
  throw new GitError(
448
1241
  `Provided tag with UUID "${props.id}" did not match any known tags`
449
1242
  );
450
1243
  }
451
- if (tags.total > 1) {
452
- throw new GitError(
453
- `Provided tag with UUID "${props.id}" matched multiple known tags`
454
- );
455
- }
456
- return tags.list[0];
1244
+ return tag;
457
1245
  }
458
1246
  /**
459
1247
  * Updating a git tag is not supported.
@@ -496,8 +1284,8 @@ var GitTagService = class extends AbstractCrudService {
496
1284
  "--format=%(refname:short)|%(subject)|%(*authorname)|%(*authoremail)|%(*authordate:unix)"
497
1285
  ];
498
1286
  const result = await this.git(props.path, args);
499
- const noEmptyLinesArr = result.stdout.split("\n").filter((line) => {
500
- return line !== "";
1287
+ const noEmptyLinesArr = result.stdout.split(EOL).filter((line) => {
1288
+ return line.trim() !== "";
501
1289
  });
502
1290
  const lineObjArr = noEmptyLinesArr.map((line) => {
503
1291
  const lineArray = line.split("|");
@@ -508,17 +1296,16 @@ var GitTagService = class extends AbstractCrudService {
508
1296
  name: lineArray[2],
509
1297
  email: lineArray[3]
510
1298
  },
511
- timestamp: typeof lineArray[4] === "string" ? parseInt(lineArray[4]) : void 0
1299
+ timestamp: parseInt(lineArray[4])
512
1300
  };
513
1301
  });
514
1302
  const gitTags = lineObjArr.filter(this.isGitTag.bind(this));
515
- return this.paginate(
516
- gitTags,
517
- props?.sort,
518
- props?.filter,
519
- props?.limit,
520
- props?.offset
521
- );
1303
+ return {
1304
+ total: gitTags.length,
1305
+ limit: 0,
1306
+ offset: 0,
1307
+ list: gitTags
1308
+ };
522
1309
  }
523
1310
  /**
524
1311
  * Returns the total number of tags inside given repository
@@ -543,21 +1330,29 @@ var GitTagService = class extends AbstractCrudService {
543
1330
  }
544
1331
  };
545
1332
 
546
- // src/service/UserService.ts
547
- import {
548
- UserTypeSchema,
549
- setUserSchema,
550
- userFileSchema
551
- } from "@elek-io/shared";
1333
+ // src/schema/userSchema.ts
1334
+ import z11 from "zod";
1335
+ var UserTypeSchema = z11.enum(["local", "cloud"]);
1336
+ var baseUserSchema = gitSignatureSchema.extend({
1337
+ userType: UserTypeSchema,
1338
+ language: supportedLanguageSchema
1339
+ });
1340
+ var localUserSchema = baseUserSchema.extend({
1341
+ userType: z11.literal(UserTypeSchema.Enum.local)
1342
+ });
1343
+ var cloudUserSchema = baseUserSchema.extend({
1344
+ userType: z11.literal(UserTypeSchema.Enum.cloud),
1345
+ id: uuidSchema
1346
+ });
1347
+ var userFileSchema = z11.union([localUserSchema, cloudUserSchema]);
1348
+ var userSchema = userFileSchema;
1349
+ var setUserSchema = userSchema;
552
1350
 
553
1351
  // src/service/JsonFileService.ts
554
- import {
555
- serviceTypeSchema as serviceTypeSchema2
556
- } from "@elek-io/shared";
557
1352
  import Fs2 from "fs-extra";
558
1353
  var JsonFileService = class extends AbstractCrudService {
559
1354
  constructor(options) {
560
- super(serviceTypeSchema2.Enum.JsonFile, options);
1355
+ super(serviceTypeSchema.Enum.JsonFile, options);
561
1356
  this.cache = /* @__PURE__ */ new Map();
562
1357
  }
563
1358
  /**
@@ -665,13 +1460,147 @@ var UserService = class {
665
1460
  // src/service/GitService.ts
666
1461
  var GitService2 = class {
667
1462
  constructor(options, userService) {
668
- this.version = void 0;
1463
+ this.branches = {
1464
+ /**
1465
+ * List branches
1466
+ *
1467
+ * @see https://www.git-scm.com/docs/git-branch
1468
+ *
1469
+ * @param path Path to the repository
1470
+ */
1471
+ list: async (path) => {
1472
+ const args = ["branch", "--list", "--all"];
1473
+ const result = await this.git(path, args);
1474
+ const normalizedLinesArr = result.stdout.split(EOL2).filter((line) => {
1475
+ return line.trim() !== "";
1476
+ }).map((line) => {
1477
+ return line.trim().replace("* ", "");
1478
+ });
1479
+ const local = [];
1480
+ const remote = [];
1481
+ normalizedLinesArr.forEach((line) => {
1482
+ if (line.startsWith("remotes/")) {
1483
+ remote.push(line.replace("remotes/", ""));
1484
+ } else {
1485
+ local.push(line);
1486
+ }
1487
+ });
1488
+ return {
1489
+ local,
1490
+ remote
1491
+ };
1492
+ },
1493
+ /**
1494
+ * Returns the name of the current branch. In detached HEAD state, an empty string is returned.
1495
+ *
1496
+ * @see https://www.git-scm.com/docs/git-branch#Documentation/git-branch.txt---show-current
1497
+ *
1498
+ * @param path Path to the repository
1499
+ */
1500
+ current: async (path) => {
1501
+ const args = ["branch", "--show-current"];
1502
+ const result = await this.git(path, args);
1503
+ return result.stdout.trim();
1504
+ },
1505
+ /**
1506
+ * Switch branches
1507
+ *
1508
+ * @see https://git-scm.com/docs/git-switch/
1509
+ *
1510
+ * @param path Path to the repository
1511
+ * @param branch Name of the branch to switch to
1512
+ * @param options Options specific to the switch operation
1513
+ */
1514
+ switch: async (path, branch, options) => {
1515
+ await this.checkBranchOrTagName(path, branch);
1516
+ let args = ["switch"];
1517
+ if (options?.isNew === true) {
1518
+ args = [...args, "--create", branch];
1519
+ } else {
1520
+ args = [...args, branch];
1521
+ }
1522
+ await this.git(path, args);
1523
+ }
1524
+ };
1525
+ this.remotes = {
1526
+ /**
1527
+ * Returns a list of currently tracked remotes
1528
+ *
1529
+ * @see https://git-scm.com/docs/git-remote
1530
+ *
1531
+ * @param path Path to the repository
1532
+ */
1533
+ list: async (path) => {
1534
+ const args = ["remote"];
1535
+ const result = await this.git(path, args);
1536
+ const normalizedLinesArr = result.stdout.split(EOL2).filter((line) => {
1537
+ return line.trim() !== "";
1538
+ });
1539
+ return normalizedLinesArr;
1540
+ },
1541
+ /**
1542
+ * Returns true if the `origin` remote exists, otherwise false
1543
+ *
1544
+ * @param path Path to the repository
1545
+ */
1546
+ hasOrigin: async (path) => {
1547
+ const remotes = await this.remotes.list(path);
1548
+ if (remotes.includes("origin")) {
1549
+ return true;
1550
+ }
1551
+ return false;
1552
+ },
1553
+ /**
1554
+ * Adds the `origin` remote with given URL
1555
+ *
1556
+ * Throws if `origin` remote is added already.
1557
+ *
1558
+ * @see https://git-scm.com/docs/git-remote#Documentation/git-remote.txt-emaddem
1559
+ *
1560
+ * @param path Path to the repository
1561
+ */
1562
+ addOrigin: async (path, url) => {
1563
+ const args = ["remote", "add", "origin", url];
1564
+ await this.git(path, args);
1565
+ },
1566
+ /**
1567
+ * Returns the current `origin` remote URL
1568
+ *
1569
+ * Throws if no `origin` remote is added yet.
1570
+ *
1571
+ * @see https://git-scm.com/docs/git-remote#Documentation/git-remote.txt-emget-urlem
1572
+ *
1573
+ * @param path Path to the repository
1574
+ */
1575
+ getOriginUrl: async (path) => {
1576
+ const args = ["remote", "get-url", "origin"];
1577
+ const result = (await this.git(path, args)).stdout.trim();
1578
+ return result.length === 0 ? null : result;
1579
+ },
1580
+ /**
1581
+ * Sets the current `origin` remote URL
1582
+ *
1583
+ * Throws if no `origin` remote is added yet.
1584
+ *
1585
+ * @see https://git-scm.com/docs/git-remote#Documentation/git-remote.txt-emset-urlem
1586
+ *
1587
+ * @param path Path to the repository
1588
+ */
1589
+ setOriginUrl: async (path, url) => {
1590
+ const args = ["remote", "set-url", "origin", url];
1591
+ await this.git(path, args);
1592
+ }
1593
+ };
1594
+ this.version = null;
1595
+ this.gitPath = null;
669
1596
  this.queue = new PQueue({
670
1597
  concurrency: 1
671
1598
  // No concurrency because git operations are sequencial
672
1599
  });
673
1600
  this.gitTagService = new GitTagService(options, this.git);
674
1601
  this.userService = userService;
1602
+ this.updateVersion();
1603
+ this.updateGitPath();
675
1604
  }
676
1605
  /**
677
1606
  * CRUD methods to work with git tags
@@ -679,13 +1608,6 @@ var GitService2 = class {
679
1608
  get tags() {
680
1609
  return this.gitTagService;
681
1610
  }
682
- /**
683
- * Reads the currently used version of Git
684
- */
685
- async getVersion() {
686
- const result = await this.git("", ["--version"]);
687
- this.version = result.stdout.replace("git version", "").trim();
688
- }
689
1611
  /**
690
1612
  * Create an empty Git repository or reinitialize an existing one
691
1613
  *
@@ -726,7 +1648,7 @@ var GitService2 = class {
726
1648
  if (options?.singleBranch === true) {
727
1649
  args = [...args, "--single-branch"];
728
1650
  }
729
- await this.git(path, [...args, url, "."]);
1651
+ await this.git("", [...args, url, path]);
730
1652
  await this.setLocalConfig(path);
731
1653
  }
732
1654
  /**
@@ -741,25 +1663,6 @@ var GitService2 = class {
741
1663
  const args = ["add", "--", ...files2];
742
1664
  await this.git(path, args);
743
1665
  }
744
- /**
745
- * Switch branches
746
- *
747
- * @see https://git-scm.com/docs/git-switch/
748
- *
749
- * @param path Path to the repository
750
- * @param name Name of the branch to switch to
751
- * @param options Options specific to the switch operation
752
- */
753
- async switch(path, name, options) {
754
- await this.checkBranchOrTagName(path, name);
755
- let args = ["switch"];
756
- if (options?.isNew === true) {
757
- args = [...args, "--create", name];
758
- } else {
759
- args = [...args, name];
760
- }
761
- await this.git(path, args);
762
- }
763
1666
  /**
764
1667
  * Reset current HEAD to the specified state
765
1668
  *
@@ -797,7 +1700,18 @@ var GitService2 = class {
797
1700
  // await this.git(path, args);
798
1701
  // }
799
1702
  /**
800
- * Fetch from and integrate with another repository or a local branch
1703
+ * Download objects and refs from remote `origin`
1704
+ *
1705
+ * @see https://www.git-scm.com/docs/git-fetch
1706
+ *
1707
+ * @param path Path to the repository
1708
+ */
1709
+ async fetch(path) {
1710
+ const args = ["fetch"];
1711
+ await this.git(path, args);
1712
+ }
1713
+ /**
1714
+ * Fetch from and integrate (rebase or merge) with a local branch
801
1715
  *
802
1716
  * @see https://git-scm.com/docs/git-pull
803
1717
  *
@@ -807,6 +1721,23 @@ var GitService2 = class {
807
1721
  const args = ["pull"];
808
1722
  await this.git(path, args);
809
1723
  }
1724
+ /**
1725
+ * Update remote refs along with associated objects to remote `origin`
1726
+ *
1727
+ * @see https://git-scm.com/docs/git-push
1728
+ *
1729
+ * @param path Path to the repository
1730
+ */
1731
+ async push(path, options) {
1732
+ let args = ["push", "origin"];
1733
+ if (options?.all === true) {
1734
+ args = [...args, "--all"];
1735
+ }
1736
+ if (options?.force === true) {
1737
+ args = [...args, "--force"];
1738
+ }
1739
+ await this.git(path, args);
1740
+ }
810
1741
  /**
811
1742
  * Record changes to the repository
812
1743
  *
@@ -843,7 +1774,7 @@ var GitService2 = class {
843
1774
  if (options?.between?.from) {
844
1775
  args = [
845
1776
  ...args,
846
- `${options.between.from}...${options.between.to || "HEAD"}`
1777
+ `${options.between.from}..${options.between.to || "HEAD"}`
847
1778
  ];
848
1779
  }
849
1780
  if (options?.limit) {
@@ -853,8 +1784,8 @@ var GitService2 = class {
853
1784
  ...args,
854
1785
  "--format=%H|%s|%an|%ae|%at|%D"
855
1786
  ]);
856
- const noEmptyLinesArr = result.stdout.split("\n").filter((line) => {
857
- return line !== "";
1787
+ const noEmptyLinesArr = result.stdout.split(EOL2).filter((line) => {
1788
+ return line.trim() !== "";
858
1789
  });
859
1790
  const lineObjArr = noEmptyLinesArr.map((line) => {
860
1791
  const lineArray = line.split("|");
@@ -872,10 +1803,9 @@ var GitService2 = class {
872
1803
  return lineObjArr.filter(this.isGitCommit.bind(this));
873
1804
  }
874
1805
  refNameToTagName(refName) {
875
- let tagName = "";
876
- tagName = refName.replace("tag: ", "");
877
- if (tagName.trim() === "" || uuidSchema2.safeParse(tagName).success === false) {
878
- tagName = void 0;
1806
+ const tagName = refName.replace("tag: ", "").trim();
1807
+ if (tagName === "" || uuidSchema.safeParse(tagName).success === false) {
1808
+ return null;
879
1809
  }
880
1810
  return tagName;
881
1811
  }
@@ -935,6 +1865,26 @@ var GitService2 = class {
935
1865
  updated: meta[1]
936
1866
  };
937
1867
  }
1868
+ /**
1869
+ * Reads the currently used version of Git
1870
+ *
1871
+ * This can help debugging
1872
+ */
1873
+ async updateVersion() {
1874
+ const result = await this.git("", ["--version"]);
1875
+ this.version = result.stdout.replace("git version", "").trim();
1876
+ }
1877
+ /**
1878
+ * Reads the path to the executable of Git that is used
1879
+ *
1880
+ * This can help debugging, since dugite is shipping their own executable
1881
+ * but in some cases resolves another executable
1882
+ * @see https://github.com/desktop/dugite/blob/main/lib/git-environment.ts
1883
+ */
1884
+ async updateGitPath() {
1885
+ const result = await this.git("", ["--exec-path"]);
1886
+ this.gitPath = result.stdout.trim();
1887
+ }
938
1888
  /**
939
1889
  * A reference is used in Git to specify branches and tags.
940
1890
  * This method checks if given name matches the required format
@@ -969,8 +1919,15 @@ var GitService2 = class {
969
1919
  }
970
1920
  const userNameArgs = ["config", "--local", "user.name", user.name];
971
1921
  const userEmailArgs = ["config", "--local", "user.email", user.email];
1922
+ const autoSetupRemoteArgs = [
1923
+ "config",
1924
+ "--local",
1925
+ "push.autoSetupRemote",
1926
+ "true"
1927
+ ];
972
1928
  await this.git(path, userNameArgs);
973
1929
  await this.git(path, userEmailArgs);
1930
+ await this.git(path, autoSetupRemoteArgs);
974
1931
  }
975
1932
  /**
976
1933
  * Type guard for GitCommit
@@ -988,14 +1945,29 @@ var GitService2 = class {
988
1945
  * @param args Arguments to append after the `git` command
989
1946
  */
990
1947
  async git(path, args) {
991
- const result = await this.queue.add(() => GitProcess.exec(args, path));
1948
+ const result = await this.queue.add(
1949
+ () => GitProcess.exec(args, path, {
1950
+ env: {
1951
+ // @todo Nasty stuff - remove after update to dugite with git > v2.45.2 once available
1952
+ // @see https://github.com/git-lfs/git-lfs/issues/5749
1953
+ GIT_CLONE_PROTECTION_ACTIVE: "false"
1954
+ }
1955
+ })
1956
+ );
992
1957
  if (!result) {
993
1958
  throw new GitError(
994
- `Git (${this.version}) command "git ${args.join(
1959
+ `Git ${this.version} (${this.gitPath}) command "git ${args.join(
995
1960
  " "
996
1961
  )}" failed to return a result`
997
1962
  );
998
1963
  }
1964
+ if (result.exitCode !== 0) {
1965
+ throw new GitError(
1966
+ `Git ${this.version} (${this.gitPath}) command "git ${args.join(
1967
+ " "
1968
+ )}" failed with exit code "${result.exitCode}" and message "${result.stderr}"`
1969
+ );
1970
+ }
999
1971
  return result;
1000
1972
  }
1001
1973
  };
@@ -1003,7 +1975,7 @@ var GitService2 = class {
1003
1975
  // src/service/AssetService.ts
1004
1976
  var AssetService = class extends AbstractCrudService {
1005
1977
  constructor(options, jsonFileService, gitService) {
1006
- super(serviceTypeSchema3.Enum.Asset, options);
1978
+ super(serviceTypeSchema.Enum.Asset, options);
1007
1979
  this.jsonFileService = jsonFileService;
1008
1980
  this.gitService = gitService;
1009
1981
  }
@@ -1012,7 +1984,7 @@ var AssetService = class extends AbstractCrudService {
1012
1984
  */
1013
1985
  async create(props) {
1014
1986
  createAssetSchema.parse(props);
1015
- const id = uuid2();
1987
+ const id = uuid();
1016
1988
  const projectPath = pathTo.project(props.projectId);
1017
1989
  const fileType = await this.getSupportedFileTypeOrThrow(props.filePath);
1018
1990
  const size = await this.getAssetSize(props.filePath);
@@ -1032,6 +2004,7 @@ var AssetService = class extends AbstractCrudService {
1032
2004
  objectType: "asset",
1033
2005
  id,
1034
2006
  created: currentTimestamp(),
2007
+ updated: null,
1035
2008
  extension: fileType.extension,
1036
2009
  mimeType: fileType.mimeType,
1037
2010
  size
@@ -1137,12 +2110,15 @@ var AssetService = class extends AbstractCrudService {
1137
2110
  }
1138
2111
  async list(props) {
1139
2112
  listAssetsSchema.parse(props);
2113
+ const offset = props.offset || 0;
2114
+ const limit = props.limit || 15;
1140
2115
  const assetReferences = await this.listReferences(
1141
- objectTypeSchema2.Enum.asset,
2116
+ objectTypeSchema.Enum.asset,
1142
2117
  props.projectId
1143
2118
  );
1144
- const list = await returnResolved(
1145
- assetReferences.map((assetReference) => {
2119
+ const partialAssetReferences = assetReferences.slice(offset, limit);
2120
+ const assets = await returnResolved(
2121
+ partialAssetReferences.map((assetReference) => {
1146
2122
  if (!assetReference.language) {
1147
2123
  throw new RequiredParameterMissingError("language");
1148
2124
  }
@@ -1153,18 +2129,16 @@ var AssetService = class extends AbstractCrudService {
1153
2129
  });
1154
2130
  })
1155
2131
  );
1156
- const paginatedResult = this.paginate(
1157
- list,
1158
- props.sort,
1159
- props.filter,
1160
- props.limit,
1161
- props.offset
1162
- );
1163
- return paginatedResult;
2132
+ return {
2133
+ total: assetReferences.length,
2134
+ limit,
2135
+ offset,
2136
+ list: assets
2137
+ };
1164
2138
  }
1165
2139
  async count(props) {
1166
2140
  countAssetsSchema.parse(props);
1167
- const count = (await this.listReferences(objectTypeSchema2.Enum.asset, props.projectId)).length;
2141
+ const count = (await this.listReferences(objectTypeSchema.Enum.asset, props.projectId)).length;
1168
2142
  return count;
1169
2143
  }
1170
2144
  /**
@@ -1228,24 +2202,10 @@ var AssetService = class extends AbstractCrudService {
1228
2202
  };
1229
2203
 
1230
2204
  // src/service/CollectionService.ts
1231
- import {
1232
- collectionFileSchema,
1233
- countCollectionsSchema,
1234
- createCollectionSchema,
1235
- currentTimestamp as currentTimestamp2,
1236
- deleteCollectionSchema,
1237
- listCollectionsSchema,
1238
- objectTypeSchema as objectTypeSchema3,
1239
- readCollectionSchema,
1240
- serviceTypeSchema as serviceTypeSchema4,
1241
- slug,
1242
- updateCollectionSchema,
1243
- uuid as uuid3
1244
- } from "@elek-io/shared";
1245
2205
  import Fs4 from "fs-extra";
1246
2206
  var CollectionService = class extends AbstractCrudService {
1247
2207
  constructor(options, jsonFileService, gitService) {
1248
- super(serviceTypeSchema4.Enum.Collection, options);
2208
+ super(serviceTypeSchema.Enum.Collection, options);
1249
2209
  this.jsonFileService = jsonFileService;
1250
2210
  this.gitService = gitService;
1251
2211
  }
@@ -1254,13 +2214,10 @@ var CollectionService = class extends AbstractCrudService {
1254
2214
  */
1255
2215
  async create(props) {
1256
2216
  createCollectionSchema.parse(props);
1257
- const id = uuid3();
2217
+ const id = uuid();
1258
2218
  const projectPath = pathTo.project(props.projectId);
1259
2219
  const collectionPath = pathTo.collection(props.projectId, id);
1260
- const collectionFilePath = pathTo.collectionFile(
1261
- props.projectId,
1262
- id
1263
- );
2220
+ const collectionFilePath = pathTo.collectionFile(props.projectId, id);
1264
2221
  const collectionFile = {
1265
2222
  ...props,
1266
2223
  objectType: "collection",
@@ -1269,7 +2226,8 @@ var CollectionService = class extends AbstractCrudService {
1269
2226
  singular: slug(props.slug.singular),
1270
2227
  plural: slug(props.slug.plural)
1271
2228
  },
1272
- created: currentTimestamp2()
2229
+ created: currentTimestamp(),
2230
+ updated: null
1273
2231
  };
1274
2232
  await Fs4.ensureDir(collectionPath);
1275
2233
  await this.jsonFileService.create(
@@ -1313,7 +2271,7 @@ var CollectionService = class extends AbstractCrudService {
1313
2271
  const collectionFile = {
1314
2272
  ...prevCollectionFile,
1315
2273
  ...props,
1316
- updated: currentTimestamp2()
2274
+ updated: currentTimestamp()
1317
2275
  };
1318
2276
  await this.jsonFileService.update(
1319
2277
  collectionFile,
@@ -1332,40 +2290,42 @@ var CollectionService = class extends AbstractCrudService {
1332
2290
  async delete(props) {
1333
2291
  deleteCollectionSchema.parse(props);
1334
2292
  const projectPath = pathTo.project(props.projectId);
1335
- const collectionPath = pathTo.collection(
1336
- props.projectId,
1337
- props.id
1338
- );
2293
+ const collectionPath = pathTo.collection(props.projectId, props.id);
1339
2294
  await Fs4.remove(collectionPath);
1340
2295
  await this.gitService.add(projectPath, [collectionPath]);
1341
2296
  await this.gitService.commit(projectPath, this.gitMessage.delete);
1342
2297
  }
1343
2298
  async list(props) {
1344
2299
  listCollectionsSchema.parse(props);
1345
- const references = await this.listReferences(
1346
- objectTypeSchema3.Enum.collection,
2300
+ const offset = props.offset || 0;
2301
+ const limit = props.limit || 15;
2302
+ const collectionReferences = await this.listReferences(
2303
+ objectTypeSchema.Enum.collection,
1347
2304
  props.projectId
1348
2305
  );
1349
- const list = await returnResolved(
1350
- references.map((reference) => {
2306
+ const partialCollectionReferences = collectionReferences.slice(
2307
+ offset,
2308
+ limit
2309
+ );
2310
+ const collections = await returnResolved(
2311
+ partialCollectionReferences.map((reference) => {
1351
2312
  return this.read({
1352
2313
  projectId: props.projectId,
1353
2314
  id: reference.id
1354
2315
  });
1355
2316
  })
1356
2317
  );
1357
- return this.paginate(
1358
- list,
1359
- props.sort,
1360
- props.filter,
1361
- props.limit,
1362
- props.offset
1363
- );
2318
+ return {
2319
+ total: collectionReferences.length,
2320
+ limit,
2321
+ offset,
2322
+ list: collections
2323
+ };
1364
2324
  }
1365
2325
  async count(props) {
1366
2326
  countCollectionsSchema.parse(props);
1367
2327
  const count = (await this.listReferences(
1368
- objectTypeSchema3.Enum.collection,
2328
+ objectTypeSchema.Enum.collection,
1369
2329
  props.projectId
1370
2330
  )).length;
1371
2331
  return count;
@@ -1379,27 +2339,11 @@ var CollectionService = class extends AbstractCrudService {
1379
2339
  };
1380
2340
 
1381
2341
  // src/service/EntryService.ts
1382
- import {
1383
- ValueTypeSchema,
1384
- countEntriesSchema,
1385
- createEntrySchema,
1386
- currentTimestamp as currentTimestamp3,
1387
- deleteEntrySchema,
1388
- entryFileSchema,
1389
- entrySchema,
1390
- getValueContentSchemaFromDefinition,
1391
- listEntriesSchema,
1392
- objectTypeSchema as objectTypeSchema4,
1393
- readEntrySchema,
1394
- serviceTypeSchema as serviceTypeSchema5,
1395
- updateEntrySchema,
1396
- uuid as uuid4
1397
- } from "@elek-io/shared";
1398
2342
  import Fs5 from "fs-extra";
1399
2343
  var EntryService = class extends AbstractCrudService {
1400
2344
  // private sharedValueService: SharedValueService;
1401
2345
  constructor(options, jsonFileService, gitService, collectionService, assetService) {
1402
- super(serviceTypeSchema5.Enum.Entry, options);
2346
+ super(serviceTypeSchema.Enum.Entry, options);
1403
2347
  this.jsonFileService = jsonFileService;
1404
2348
  this.gitService = gitService;
1405
2349
  this.collectionService = collectionService;
@@ -1410,7 +2354,7 @@ var EntryService = class extends AbstractCrudService {
1410
2354
  */
1411
2355
  async create(props) {
1412
2356
  createEntrySchema.parse(props);
1413
- const id = uuid4();
2357
+ const id = uuid();
1414
2358
  const projectPath = pathTo.project(props.projectId);
1415
2359
  const entryFilePath = pathTo.entryFile(
1416
2360
  props.projectId,
@@ -1425,7 +2369,8 @@ var EntryService = class extends AbstractCrudService {
1425
2369
  objectType: "entry",
1426
2370
  id,
1427
2371
  values: props.values,
1428
- created: currentTimestamp3()
2372
+ created: currentTimestamp(),
2373
+ updated: null
1429
2374
  };
1430
2375
  const entry = await this.toEntry({
1431
2376
  projectId: props.projectId,
@@ -1484,7 +2429,7 @@ var EntryService = class extends AbstractCrudService {
1484
2429
  const entryFile = {
1485
2430
  ...prevEntryFile,
1486
2431
  values: props.values,
1487
- updated: currentTimestamp3()
2432
+ updated: currentTimestamp()
1488
2433
  };
1489
2434
  const entry = await this.toEntry({
1490
2435
  projectId: props.projectId,
@@ -1522,13 +2467,16 @@ var EntryService = class extends AbstractCrudService {
1522
2467
  }
1523
2468
  async list(props) {
1524
2469
  listEntriesSchema.parse(props);
1525
- const references = await this.listReferences(
1526
- objectTypeSchema4.Enum.entry,
2470
+ const offset = props.offset || 0;
2471
+ const limit = props.limit || 15;
2472
+ const entryReferences = await this.listReferences(
2473
+ objectTypeSchema.Enum.entry,
1527
2474
  props.projectId,
1528
2475
  props.collectionId
1529
2476
  );
1530
- const list = await returnResolved(
1531
- references.map((reference) => {
2477
+ const partialEntryReferences = entryReferences.slice(offset, limit);
2478
+ const entries = await returnResolved(
2479
+ partialEntryReferences.map((reference) => {
1532
2480
  return this.read({
1533
2481
  projectId: props.projectId,
1534
2482
  collectionId: props.collectionId,
@@ -1536,18 +2484,17 @@ var EntryService = class extends AbstractCrudService {
1536
2484
  });
1537
2485
  })
1538
2486
  );
1539
- return this.paginate(
1540
- list,
1541
- props.sort,
1542
- props.filter,
1543
- props.limit,
1544
- props.offset
1545
- );
2487
+ return {
2488
+ total: entryReferences.length,
2489
+ limit,
2490
+ offset,
2491
+ list: entries
2492
+ };
1546
2493
  }
1547
2494
  async count(props) {
1548
2495
  countEntriesSchema.parse(props);
1549
2496
  return (await this.listReferences(
1550
- objectTypeSchema4.Enum.entry,
2497
+ objectTypeSchema.Enum.entry,
1551
2498
  props.projectId,
1552
2499
  props.collectionId
1553
2500
  )).length;
@@ -1587,12 +2534,8 @@ var EntryService = class extends AbstractCrudService {
1587
2534
  });
1588
2535
  const schema = getValueContentSchemaFromDefinition(definition);
1589
2536
  try {
1590
- if (value.valueType === "reference") {
1591
- schema.parse(value.content);
1592
- } else {
1593
- for (const [language, content] of Object.entries(value.content)) {
1594
- schema.parse(content);
1595
- }
2537
+ for (const [language, content] of Object.entries(value.content)) {
2538
+ schema.parse(content);
1596
2539
  }
1597
2540
  } catch (error) {
1598
2541
  console.log("Definition:", definition);
@@ -1620,17 +2563,18 @@ var EntryService = class extends AbstractCrudService {
1620
2563
  // });
1621
2564
  // }
1622
2565
  async resolveValueContentReference(props) {
1623
- switch (props.valueContentReference.referenceObjectType) {
1624
- case objectTypeSchema4.Enum.asset:
1625
- return this.resolveValueContentReferenceToAsset({
2566
+ switch (props.valueContentReference.objectType) {
2567
+ case objectTypeSchema.Enum.asset:
2568
+ return await this.assetService.read({
1626
2569
  projectId: props.projectId,
1627
- valueContentReferenceToAsset: props.valueContentReference
2570
+ id: props.valueContentReference.id,
2571
+ language: props.valueContentReference.language
1628
2572
  });
1629
- case objectTypeSchema4.Enum.entry:
1630
- return this.resolveValueContentReferenceToEntry({
2573
+ case objectTypeSchema.Enum.entry:
2574
+ return await this.read({
1631
2575
  projectId: props.projectId,
1632
2576
  collectionId: props.collectionId,
1633
- valueContentReferenceToEntry: props.valueContentReference
2577
+ id: props.valueContentReference.id
1634
2578
  });
1635
2579
  default:
1636
2580
  throw new Error(
@@ -1639,98 +2583,59 @@ var EntryService = class extends AbstractCrudService {
1639
2583
  );
1640
2584
  }
1641
2585
  }
1642
- async resolveValueContentReferenceToAsset(props) {
1643
- const resolvedReferences = await Promise.all(
1644
- props.valueContentReferenceToAsset.references.map(async (reference) => {
1645
- const resolvedAsset = await this.assetService.read({
1646
- projectId: props.projectId,
1647
- id: reference.id,
1648
- language: reference.language
1649
- });
1650
- return resolvedAsset;
1651
- })
1652
- );
1653
- return {
1654
- ...props.valueContentReferenceToAsset,
1655
- references: resolvedReferences
1656
- };
1657
- }
1658
- async resolveValueContentReferenceToEntry(props) {
1659
- const resolvedReferences = await Promise.all(
1660
- props.valueContentReferenceToEntry.references.map(async (reference) => {
1661
- const resolvedEntry = await this.read({
1662
- projectId: props.projectId,
1663
- collectionId: props.collectionId,
1664
- id: reference.id
1665
- });
1666
- return resolvedEntry;
1667
- })
1668
- );
1669
- return {
1670
- ...props.valueContentReferenceToEntry,
1671
- references: resolvedReferences
1672
- };
2586
+ async resolveValueContentReferences(props) {
2587
+ let resolvedContent = {};
2588
+ for (const language in props.valueReference.content) {
2589
+ const referencesOfLanguage = props.valueReference.content[language];
2590
+ if (!referencesOfLanguage) {
2591
+ throw new Error(
2592
+ `Trying to access content references by language "${language}" failed`
2593
+ );
2594
+ }
2595
+ const resolvedReferencesOfLanguage = await Promise.all(
2596
+ referencesOfLanguage.map(async (reference) => {
2597
+ return await this.resolveValueContentReference({
2598
+ projectId: props.projectId,
2599
+ collectionId: props.collectionId,
2600
+ valueContentReference: reference
2601
+ });
2602
+ })
2603
+ );
2604
+ resolvedContent = {
2605
+ ...resolvedContent,
2606
+ [language]: resolvedReferencesOfLanguage
2607
+ };
2608
+ }
2609
+ return resolvedContent;
1673
2610
  }
1674
- // private async resolveValueContentReferenceToSharedValue(props: {
1675
- // projectId: string;
1676
- // valueContentReferenceToSharedValue: ValueContentReferenceToSharedValue;
1677
- // }): Promise<ResolvedValueContentReferenceToSharedValue> {
1678
- // const resolvedSharedValue = await this.sharedValueService.read({
1679
- // projectId: props.projectId,
1680
- // id: props.valueContentReferenceToSharedValue.references.id,
1681
- // language: props.valueContentReferenceToSharedValue.references.language,
1682
- // });
1683
- // return {
1684
- // ...props.valueContentReferenceToSharedValue,
1685
- // references: {
1686
- // ...props.valueContentReferenceToSharedValue.references,
1687
- // resolved: resolvedSharedValue,
1688
- // },
1689
- // };
1690
- // }
1691
2611
  /**
1692
2612
  * Creates an Entry from given EntryFile by resolving it's Values
1693
2613
  */
1694
2614
  async toEntry(props) {
1695
- const entry = {
2615
+ return {
1696
2616
  ...props.entryFile,
2617
+ // @ts-ignore @todo fixme - I have no idea why this happens. The types seem to be compatible to me and they work
1697
2618
  values: await Promise.all(
1698
2619
  props.entryFile.values.map(async (value) => {
1699
2620
  if (value.valueType === ValueTypeSchema.Enum.reference) {
1700
- const resolvedValueContentReference = await this.resolveValueContentReference({
2621
+ const resolvedContentReferences = await this.resolveValueContentReferences({
1701
2622
  projectId: props.projectId,
1702
2623
  collectionId: props.collectionId,
1703
- valueContentReference: value.content
2624
+ valueReference: value
1704
2625
  });
1705
2626
  return {
1706
2627
  ...value,
1707
- content: resolvedValueContentReference
2628
+ content: resolvedContentReferences
1708
2629
  };
1709
2630
  }
1710
2631
  return value;
1711
2632
  })
1712
2633
  )
1713
2634
  };
1714
- return entry;
1715
2635
  }
1716
2636
  };
1717
2637
 
1718
2638
  // src/service/ProjectService.ts
1719
- import {
1720
- createProjectSchema,
1721
- currentTimestamp as currentTimestamp4,
1722
- deleteProjectSchema,
1723
- gitCommitIconSchema as gitCommitIconSchema2,
1724
- listProjectsSchema,
1725
- objectTypeSchema as objectTypeSchema5,
1726
- projectFileSchema,
1727
- projectFolderSchema as projectFolderSchema2,
1728
- readProjectSchema,
1729
- serviceTypeSchema as serviceTypeSchema7,
1730
- updateProjectSchema,
1731
- upgradeProjectSchema,
1732
- uuid as uuid5
1733
- } from "@elek-io/shared";
1734
2639
  import Fs6 from "fs-extra";
1735
2640
  import Os2 from "os";
1736
2641
  import Path2 from "path";
@@ -1744,83 +2649,52 @@ var ProjectUpgradeError = class extends Error {
1744
2649
  }
1745
2650
  };
1746
2651
 
1747
- // src/service/SearchService.ts
1748
- import {
1749
- serviceTypeSchema as serviceTypeSchema6
1750
- } from "@elek-io/shared";
1751
- var SearchService = class extends AbstractCrudService {
1752
- constructor(options, assetService, collectionService) {
1753
- super(serviceTypeSchema6.enum.Search, options);
1754
- this.assetService = assetService;
1755
- this.collectionService = collectionService;
1756
- }
1757
- /**
1758
- * Search all models inside the project for given query
1759
- *
1760
- * @todo Implement SearchOptions parameter
1761
- *
1762
- * @param project Project to search in
1763
- * @param query Query to search for
1764
- */
1765
- async search(projectId, query, objectType) {
1766
- const results = [];
1767
- const normalizedQuery = query.trim();
1768
- if (normalizedQuery === "") {
1769
- return results;
1770
- }
1771
- const paginatedLists = (await Promise.all([this.assetService.list({ projectId, filter: query })])).flat();
1772
- paginatedLists.forEach((paginatedList) => {
1773
- paginatedList.list.flat().forEach((file) => {
1774
- const result = {
1775
- id: file.id,
1776
- language: file.language,
1777
- name: file.name,
1778
- type: file.objectType,
1779
- matches: []
1780
- };
1781
- for (const [key, value] of Object.entries(file)) {
1782
- const valueString = String(value);
1783
- if (valueString.toLowerCase().includes(normalizedQuery.toLowerCase())) {
1784
- const matchStart = valueString.toLowerCase().indexOf(normalizedQuery.toLowerCase());
1785
- const matchEnd = matchStart + normalizedQuery.length;
1786
- result.matches.push({
1787
- key,
1788
- prefix: this.truncate(
1789
- valueString.substring(0, matchStart),
1790
- "start"
1791
- ),
1792
- match: valueString.substring(matchStart, matchEnd),
1793
- suffix: this.truncate(
1794
- valueString.substring(matchEnd, valueString.length),
1795
- "end"
1796
- )
1797
- });
1798
- }
1799
- }
1800
- if (result.matches.length > 0) {
1801
- results.push(result);
1802
- }
1803
- });
1804
- });
1805
- return results;
1806
- }
1807
- truncate(value, at, limit = 15) {
1808
- if (at === "start") {
1809
- return `${value.substring(value.length - limit, value.length)}`;
1810
- } else {
1811
- return `${value.substring(0, limit)}`;
1812
- }
1813
- }
1814
- };
1815
-
1816
2652
  // src/service/ProjectService.ts
1817
2653
  var ProjectService = class extends AbstractCrudService {
1818
- constructor(options, jsonFileService, userService, gitService, searchService, assetService, collectionService, entryService) {
1819
- super(serviceTypeSchema7.Enum.Project, options);
2654
+ constructor(options, jsonFileService, userService, gitService, assetService, collectionService, entryService) {
2655
+ super(serviceTypeSchema.Enum.Project, options);
2656
+ this.branches = {
2657
+ list: async (props) => {
2658
+ listBranchesProjectSchema.parse(props);
2659
+ const projectPath = pathTo.project(props.id);
2660
+ await this.gitService.fetch(projectPath);
2661
+ return await this.gitService.branches.list(projectPath);
2662
+ },
2663
+ current: async (props) => {
2664
+ currentBranchProjectSchema.parse(props);
2665
+ const projectPath = pathTo.project(props.id);
2666
+ return await this.gitService.branches.current(projectPath);
2667
+ },
2668
+ switch: async (props) => {
2669
+ switchBranchProjectSchema.parse(props);
2670
+ const projectPath = pathTo.project(props.id);
2671
+ return await this.gitService.branches.switch(
2672
+ projectPath,
2673
+ props.branch,
2674
+ props.options
2675
+ );
2676
+ }
2677
+ };
2678
+ this.remotes = {
2679
+ getOriginUrl: async (props) => {
2680
+ getRemoteOriginUrlProjectSchema.parse(props);
2681
+ const projectPath = pathTo.project(props.id);
2682
+ return await this.gitService.remotes.getOriginUrl(projectPath);
2683
+ },
2684
+ setOriginUrl: async (props) => {
2685
+ setRemoteOriginUrlProjectSchema.parse(props);
2686
+ const projectPath = pathTo.project(props.id);
2687
+ const hasOrigin = await this.gitService.remotes.hasOrigin(projectPath);
2688
+ if (!hasOrigin) {
2689
+ await this.gitService.remotes.addOrigin(projectPath, props.url);
2690
+ } else {
2691
+ await this.gitService.remotes.setOriginUrl(projectPath, props.url);
2692
+ }
2693
+ }
2694
+ };
1820
2695
  this.jsonFileService = jsonFileService;
1821
2696
  this.userService = userService;
1822
2697
  this.gitService = gitService;
1823
- this.searchService = searchService;
1824
2698
  this.assetService = assetService;
1825
2699
  this.collectionService = collectionService;
1826
2700
  this.entryService = entryService;
@@ -1834,7 +2708,7 @@ var ProjectService = class extends AbstractCrudService {
1834
2708
  if (!user) {
1835
2709
  throw new NoCurrentUserError();
1836
2710
  }
1837
- const id = uuid5();
2711
+ const id = uuid();
1838
2712
  const defaultSettings = {
1839
2713
  language: {
1840
2714
  default: user.language,
@@ -1847,7 +2721,8 @@ var ProjectService = class extends AbstractCrudService {
1847
2721
  id,
1848
2722
  description: props.description || "",
1849
2723
  settings: Object.assign({}, defaultSettings, props.settings),
1850
- created: currentTimestamp4(),
2724
+ created: currentTimestamp(),
2725
+ updated: null,
1851
2726
  coreVersion: this.options.version,
1852
2727
  // @todo should be read from package.json to avoid duplicates
1853
2728
  status: "todo",
@@ -1867,16 +2742,45 @@ var ProjectService = class extends AbstractCrudService {
1867
2742
  await this.gitService.add(projectPath, ["."]);
1868
2743
  await this.gitService.commit(
1869
2744
  projectPath,
1870
- `${gitCommitIconSchema2.enum.INIT} Created this new elek.io project`
2745
+ `${gitCommitIconSchema.enum.INIT} Created this new elek.io project`
1871
2746
  );
1872
- await this.gitService.switch(projectPath, "stage", { isNew: true });
2747
+ await this.gitService.branches.switch(projectPath, "stage", {
2748
+ isNew: true
2749
+ });
1873
2750
  } catch (error) {
1874
2751
  await this.delete({
1875
2752
  id
1876
2753
  });
1877
2754
  throw error;
1878
2755
  }
1879
- return projectFile;
2756
+ return await this.toProject({
2757
+ projectFile
2758
+ });
2759
+ }
2760
+ /**
2761
+ * Clones a Project by URL
2762
+ */
2763
+ async clone(props) {
2764
+ cloneProjectSchema.parse(props);
2765
+ const tmpId = uuid();
2766
+ const tmpProjectPath = Path2.join(pathTo.tmp, tmpId);
2767
+ await this.gitService.clone(props.url, tmpProjectPath);
2768
+ const projectFile = await this.jsonFileService.read(
2769
+ Path2.join(tmpProjectPath, "project.json"),
2770
+ projectFileSchema
2771
+ );
2772
+ const projectPath = pathTo.project(projectFile.id);
2773
+ const alreadyExists = await Fs6.pathExists(projectPath);
2774
+ if (alreadyExists) {
2775
+ throw new Error(
2776
+ `Tried to clone Project "${projectFile.id}" from "${props.url}" - but the Project already exists locally`
2777
+ );
2778
+ }
2779
+ await Fs6.copy(tmpProjectPath, projectPath);
2780
+ await Fs6.remove(tmpProjectPath);
2781
+ return await this.toProject({
2782
+ projectFile
2783
+ });
1880
2784
  }
1881
2785
  /**
1882
2786
  * Returns a Project by ID
@@ -1887,7 +2791,9 @@ var ProjectService = class extends AbstractCrudService {
1887
2791
  pathTo.projectFile(props.id),
1888
2792
  projectFileSchema
1889
2793
  );
1890
- return projectFile;
2794
+ return await this.toProject({
2795
+ projectFile
2796
+ });
1891
2797
  }
1892
2798
  /**
1893
2799
  * Updates given Project
@@ -1900,12 +2806,14 @@ var ProjectService = class extends AbstractCrudService {
1900
2806
  const projectFile = {
1901
2807
  ...prevProjectFile,
1902
2808
  ...props,
1903
- updated: currentTimestamp4()
2809
+ updated: currentTimestamp()
1904
2810
  };
1905
2811
  await this.jsonFileService.update(projectFile, filePath, projectFileSchema);
1906
2812
  await this.gitService.add(projectPath, [filePath]);
1907
2813
  await this.gitService.commit(projectPath, this.gitMessage.update);
1908
- return projectFile;
2814
+ return await this.toProject({
2815
+ projectFile
2816
+ });
1909
2817
  }
1910
2818
  /**
1911
2819
  * Upgrades given Project to the latest version of this client
@@ -1973,6 +2881,39 @@ var ProjectService = class extends AbstractCrudService {
1973
2881
  }
1974
2882
  }
1975
2883
  }
2884
+ /**
2885
+ * Returns the differences of the given Projects current branch
2886
+ * between the local and remote `origin` (commits ahead & behind)
2887
+ *
2888
+ * - `behind` contains a list of commits on the current branch that are available on the remote `origin` but not yet locally
2889
+ * - `ahead` contains a list of commits on the current branch that are available locally but not yet on the remote `origin`
2890
+ */
2891
+ async getChanges(props) {
2892
+ getChangesProjectSchema.parse(props);
2893
+ const projectPath = pathTo.project(props.id);
2894
+ const currentBranch = await this.gitService.branches.current(projectPath);
2895
+ await this.gitService.fetch(projectPath);
2896
+ const behind = await this.gitService.log(projectPath, {
2897
+ between: { from: currentBranch, to: `origin/${currentBranch}` }
2898
+ });
2899
+ const ahead = await this.gitService.log(projectPath, {
2900
+ between: { from: `origin/${currentBranch}`, to: currentBranch }
2901
+ });
2902
+ return {
2903
+ behind,
2904
+ ahead
2905
+ };
2906
+ }
2907
+ /**
2908
+ * Pulls remote changes of `origin` down to the local repository
2909
+ * and then pushes local commits to the upstream branch
2910
+ */
2911
+ async synchronize(props) {
2912
+ synchronizeProjectSchema.parse(props);
2913
+ const projectPath = pathTo.project(props.id);
2914
+ await this.gitService.pull(projectPath);
2915
+ await this.gitService.push(projectPath);
2916
+ }
1976
2917
  /**
1977
2918
  * Deletes given Project
1978
2919
  *
@@ -1988,32 +2929,26 @@ var ProjectService = class extends AbstractCrudService {
1988
2929
  if (props) {
1989
2930
  listProjectsSchema.parse(props);
1990
2931
  }
1991
- const references = await this.listReferences(objectTypeSchema5.Enum.project);
1992
- const list = await returnResolved(
1993
- references.map((reference) => {
2932
+ const offset = props?.offset || 0;
2933
+ const limit = props?.limit || 15;
2934
+ const projectReferences = await this.listReferences(
2935
+ objectTypeSchema.Enum.project
2936
+ );
2937
+ const partialProjectReferences = projectReferences.slice(offset, limit);
2938
+ const projects = await returnResolved(
2939
+ partialProjectReferences.map((reference) => {
1994
2940
  return this.read({ id: reference.id });
1995
2941
  })
1996
2942
  );
1997
- return this.paginate(
1998
- list,
1999
- props?.sort,
2000
- props?.filter,
2001
- props?.limit,
2002
- props?.offset
2003
- );
2943
+ return {
2944
+ total: projectReferences.length,
2945
+ limit,
2946
+ offset,
2947
+ list: projects
2948
+ };
2004
2949
  }
2005
2950
  async count() {
2006
- return (await this.listReferences(objectTypeSchema5.Enum.project)).length;
2007
- }
2008
- /**
2009
- * Search all models inside the project for given query
2010
- *
2011
- * @param projectId Project ID to search in
2012
- * @param query Query to search for
2013
- * @param type (Optional) specify the type to search for
2014
- */
2015
- async search(projectId, query, type) {
2016
- return this.searchService.search(projectId, query, type);
2951
+ return (await this.listReferences(objectTypeSchema.Enum.project)).length;
2017
2952
  }
2018
2953
  /**
2019
2954
  * Checks if given object is of type Project
@@ -2051,13 +2986,21 @@ var ProjectService = class extends AbstractCrudService {
2051
2986
  collections: collectionExport
2052
2987
  };
2053
2988
  }
2989
+ /**
2990
+ * Creates a Project from given ProjectFile by adding git information
2991
+ */
2992
+ async toProject(props) {
2993
+ return {
2994
+ ...props.projectFile
2995
+ };
2996
+ }
2054
2997
  /**
2055
2998
  * Creates the projects folder structure and makes sure to
2056
2999
  * write empty .gitkeep files inside them to ensure they are
2057
3000
  * committed
2058
3001
  */
2059
3002
  async createFolderStructure(path) {
2060
- const folders2 = Object.values(projectFolderSchema2.Values);
3003
+ const folders2 = Object.values(projectFolderSchema.Values);
2061
3004
  await Promise.all(
2062
3005
  folders2.map(async (folder) => {
2063
3006
  await Fs6.mkdirp(Path2.join(path, folder));
@@ -2089,6 +3032,35 @@ var ProjectService = class extends AbstractCrudService {
2089
3032
  }
2090
3033
  };
2091
3034
 
3035
+ // src/schema/coreSchema.ts
3036
+ import { z as z12 } from "zod";
3037
+ var elekIoCoreOptionsSchema = z12.object({
3038
+ /**
3039
+ * The environment elek.io Core is currently running in
3040
+ */
3041
+ environment: environmentSchema,
3042
+ /**
3043
+ * The current version of elek.io Core
3044
+ */
3045
+ version: versionSchema,
3046
+ file: z12.object({
3047
+ json: z12.object({
3048
+ /**
3049
+ * If set, adds indentation with spaces (number) or escape character (string)
3050
+ * and line break characters to saved JSON files on disk, to make them easier to read.
3051
+ * Defaults to 2 spaces of indentation.
3052
+ */
3053
+ indentation: z12.union([z12.number(), z12.string()])
3054
+ })
3055
+ })
3056
+ });
3057
+ var constructorElekIoCoreSchema = elekIoCoreOptionsSchema.omit({
3058
+ version: true
3059
+ }).partial({
3060
+ environment: true,
3061
+ file: true
3062
+ }).optional();
3063
+
2092
3064
  // src/index.ts
2093
3065
  var ElekIoCore = class {
2094
3066
  // private readonly sharedValueService: SharedValueService;
@@ -2125,17 +3097,11 @@ var ElekIoCore = class {
2125
3097
  this.assetService
2126
3098
  // this.sharedValueService
2127
3099
  );
2128
- this.searchService = new SearchService(
2129
- this.options,
2130
- this.assetService,
2131
- this.collectionService
2132
- );
2133
3100
  this.projectService = new ProjectService(
2134
3101
  this.options,
2135
3102
  this.jsonFileService,
2136
3103
  this.userService,
2137
3104
  this.gitService,
2138
- this.searchService,
2139
3105
  this.assetService,
2140
3106
  this.collectionService,
2141
3107
  this.entryService
@@ -2159,7 +3125,13 @@ var ElekIoCore = class {
2159
3125
  return util_exports;
2160
3126
  }
2161
3127
  /**
2162
- *
3128
+ * Exposes git functions
3129
+ */
3130
+ get git() {
3131
+ return this.gitService;
3132
+ }
3133
+ /**
3134
+ * Getter and setter methods for the User currently working with Core
2163
3135
  */
2164
3136
  get user() {
2165
3137
  return this.userService;