@sidekick-coder/zenith-kit 0.0.8 → 0.0.11

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.
@@ -1,9 +1,218 @@
1
+ import { debounce, get, has, set, unset } from "lodash-es";
2
+ import fg from "fast-glob";
3
+ import path, { join } from "path";
4
+ import * as v from "valibot";
5
+ import { format } from "date-fns";
6
+ import qs from "qs";
7
+ import fs from "fs";
8
+ import { spawn } from "child_process";
1
9
  import { exec } from "node:child_process";
2
10
  import { promisify } from "node:util";
3
11
  import { unlink, writeFile } from "node:fs/promises";
4
12
  import { tmpdir } from "node:os";
5
- import { join } from "node:path";
13
+ import { join as join$1 } from "node:path";
6
14
  import { randomUUID } from "node:crypto";
15
+ import { pathToFileURL } from "url";
16
+ import { pathToFileURL as pathToFileURL$1 } from "node:url";
17
+ import fs$1 from "node:fs";
18
+ //#region \0rolldown/runtime.js
19
+ var __defProp = Object.defineProperty;
20
+ var __exportAll = (all, no_symbols) => {
21
+ let target = {};
22
+ for (var name in all) __defProp(target, name, {
23
+ get: all[name],
24
+ enumerable: true
25
+ });
26
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
27
+ return target;
28
+ };
29
+ //#endregion
30
+ //#region src/shared/utils/compose.ts
31
+ /**
32
+ * Composes multiple mixins into a single class that can be extended.
33
+ * Allows for multiple inheritance-like behavior by applying mixins sequentially.
34
+ *
35
+ * @param mixins - Array of mixin functions to compose
36
+ * @returns A class constructor that includes all mixin functionality
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * class User extends compose(Timestamp, SoftDelete) {
41
+ * constructor(public name: string) {
42
+ * super()
43
+ * }
44
+ * }
45
+ * ```
46
+ */
47
+ function compose(...mixins) {
48
+ return mixins.reduce((base, mixin) => mixin(base), class {});
49
+ }
50
+ /**
51
+ * Alternative compose function that starts with a base class
52
+ *
53
+ * @param baseClass - The base class to start with
54
+ * @param mixins - Array of mixin functions to apply
55
+ * @returns A class constructor that extends the base class with all mixin functionality
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * class User extends composeWith(BaseEntity, Timestamp, SoftDelete) {
60
+ * constructor(public name: string) {
61
+ * super()
62
+ * }
63
+ * }
64
+ * ```
65
+ */
66
+ function composeWith(baseClass, ...mixins) {
67
+ return mixins.reduce((base, mixin) => mixin(base), baseClass);
68
+ }
69
+ function mixin(Source) {
70
+ return function(Target) {
71
+ class Mixed extends Target {
72
+ constructor(...args) {
73
+ super(...args);
74
+ const source = new Source(...args);
75
+ Object.assign(this, source);
76
+ }
77
+ }
78
+ for (const key of Reflect.ownKeys(Source.prototype)) if (key !== "constructor") Object.defineProperty(Mixed.prototype, key, Object.getOwnPropertyDescriptor(Source.prototype, key));
79
+ return Mixed;
80
+ };
81
+ }
82
+ //#endregion
83
+ //#region src/shared/utils/tryCatch.ts
84
+ async function tryCatch(tryer) {
85
+ try {
86
+ return [null, await tryer()];
87
+ } catch (error) {
88
+ return [error, null];
89
+ }
90
+ }
91
+ tryCatch.sync = function(tryer) {
92
+ try {
93
+ return [null, tryer()];
94
+ } catch (error) {
95
+ return [error, null];
96
+ }
97
+ };
98
+ //#endregion
99
+ //#region src/shared/utils/createId.ts
100
+ function uuid() {
101
+ if (typeof crypto !== "undefined" && crypto.randomUUID) return crypto.randomUUID();
102
+ if (typeof self !== "undefined" && self.crypto && self.crypto.randomUUID) return self.crypto.randomUUID();
103
+ if (typeof window !== "undefined" && window.crypto && window.crypto.randomUUID) return window.crypto.randomUUID();
104
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
105
+ const r = Math.random() * 16 | 0;
106
+ return (c === "x" ? r : r & 3 | 8).toString(16);
107
+ });
108
+ }
109
+ function createId(prefix = "") {
110
+ return prefix + uuid();
111
+ }
112
+ //#endregion
113
+ //#region src/shared/services/LoggerService.ts
114
+ var LoggerService = class LoggerService {
115
+ info(message, meta) {}
116
+ debug(message, meta) {}
117
+ warn(message, meta) {}
118
+ error(message, meta) {}
119
+ child(options) {
120
+ return new LoggerService();
121
+ }
122
+ };
123
+ //#endregion
124
+ //#region src/shared/services/EmmitterService.ts
125
+ var EmmitterService$1 = class {
126
+ handlers = [];
127
+ debug;
128
+ logger;
129
+ load(options) {
130
+ this.debug = options?.debug || false;
131
+ this.logger = options?.logger || new LoggerService();
132
+ if (this.debug) this.logger.debug("emmitter loaded with debug mode enabled");
133
+ }
134
+ on(event, listener, options) {
135
+ const id = options?.id || createId();
136
+ if (options?.unique) {
137
+ if (this.handlers.some((h) => h.event === event && h.listener === listener || h.id === id)) return;
138
+ }
139
+ const handler = {
140
+ id,
141
+ event,
142
+ listener
143
+ };
144
+ this.handlers.push(handler);
145
+ if (this.debug) this.logger.debug("handler added", handler);
146
+ return handler;
147
+ }
148
+ once(event, listener, options) {
149
+ const wrapper = (args) => {
150
+ listener(args);
151
+ this.off(event, wrapper);
152
+ };
153
+ return this.on(event, wrapper, options);
154
+ }
155
+ onDebounce(event, listener, options) {
156
+ const debounced = debounce(listener, options?.debounce || 300);
157
+ const handler = this.on(event, debounced, options);
158
+ if (handler) handler.originalListener = listener;
159
+ return handler;
160
+ }
161
+ onAnyOf(events, listener, options) {
162
+ const handlers = [];
163
+ for (const event of events) {
164
+ const handler = this.on(event, listener, options);
165
+ if (handler) handlers.push(handler);
166
+ }
167
+ return handlers;
168
+ }
169
+ off(event, listener) {
170
+ this.handlers = this.handlers.filter((h) => {
171
+ if (h.event === event && (h.listener === listener || h.originalListener === listener)) return false;
172
+ return true;
173
+ });
174
+ if (this.debug) this.logger.debug("handler removed", { event });
175
+ }
176
+ emit(event, args) {
177
+ if (this.debug) this.logger.debug("emitting event", {
178
+ event,
179
+ args
180
+ });
181
+ const handlers = this.handlers.filter((h) => h.event === event);
182
+ for (const handler of handlers) tryCatch.sync(() => handler.listener(args));
183
+ }
184
+ async emitAndWait(event, args) {
185
+ const handlers = this.handlers.filter((h) => h.event === event);
186
+ if (this.debug) this.logger.debug("emitting event", {
187
+ handlers: handlers.length,
188
+ event,
189
+ args
190
+ });
191
+ for await (const handler of handlers) await handler.listener(args);
192
+ }
193
+ list() {
194
+ return this.handlers;
195
+ }
196
+ listByEvent(event) {
197
+ return this.handlers.filter((h) => h.event === event);
198
+ }
199
+ remove(payload) {
200
+ const ids = Array.isArray(payload) ? payload : [payload];
201
+ this.handlers = this.handlers.filter((h) => !ids.includes(h.id));
202
+ if (this.debug) this.logger.debug("handlers removed", { ids });
203
+ }
204
+ clear() {
205
+ this.handlers = [];
206
+ if (this.debug) this.logger.debug("all handlers cleared");
207
+ }
208
+ hasHandlers() {
209
+ return this.handlers.length > 0;
210
+ }
211
+ };
212
+ //#endregion
213
+ //#region src/server/services/EmmitterService.ts
214
+ var EmmitterService = class extends EmmitterService$1 {};
215
+ //#endregion
7
216
  //#region src/server/services/GitBranchRepository.ts
8
217
  var GitBranchRepository = class {
9
218
  constructor(gateway) {
@@ -115,20 +324,6 @@ var GitCommitRepository = class {
115
324
  }
116
325
  };
117
326
  //#endregion
118
- //#region src/shared/utils/createId.ts
119
- function uuid() {
120
- if (typeof crypto !== "undefined" && crypto.randomUUID) return crypto.randomUUID();
121
- if (typeof self !== "undefined" && self.crypto && self.crypto.randomUUID) return self.crypto.randomUUID();
122
- if (typeof window !== "undefined" && window.crypto && window.crypto.randomUUID) return window.crypto.randomUUID();
123
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
124
- const r = Math.random() * 16 | 0;
125
- return (c === "x" ? r : r & 3 | 8).toString(16);
126
- });
127
- }
128
- function createId(prefix = "") {
129
- return prefix + uuid();
130
- }
131
- //#endregion
132
327
  //#region src/server/services/PluginIpcClient.ts
133
328
  var PluginIpcClient = class {
134
329
  listeners = /* @__PURE__ */ new Map();
@@ -277,14 +472,1008 @@ var PluginRouter = class {
277
472
  }
278
473
  };
279
474
  //#endregion
280
- //#region src/shared/services/LoggerService.ts
281
- var LoggerService = class LoggerService {
282
- info(message, meta) {}
283
- debug(message, meta) {}
284
- warn(message, meta) {}
285
- error(message, meta) {}
286
- child(options) {
287
- return new LoggerService();
475
+ //#region src/shared/exceptions/BaseException.ts
476
+ var BaseException = class BaseException extends Error {
477
+ statusCode = 500;
478
+ constructor(message, statusCode = 500) {
479
+ super(message);
480
+ this.name = this.constructor.name;
481
+ this.statusCode = statusCode;
482
+ }
483
+ static fromError(error) {
484
+ return new BaseException(error.message, 500);
485
+ }
486
+ };
487
+ //#endregion
488
+ //#region src/server/services/RouterFileBaseRoutingService.ts
489
+ var RouterFileBaseRoutingService = class RouterFileBaseRoutingService {
490
+ directory;
491
+ prefix;
492
+ module;
493
+ router;
494
+ logger = new LoggerService();
495
+ routes = [];
496
+ debug = false;
497
+ setDirectory(directory) {
498
+ this.directory = directory;
499
+ return this;
500
+ }
501
+ setPrefix(prefix) {
502
+ this.prefix = prefix;
503
+ return this;
504
+ }
505
+ setRouter(router) {
506
+ this.router = router;
507
+ return this;
508
+ }
509
+ setModule(module) {
510
+ this.module = module;
511
+ return this;
512
+ }
513
+ setLogger(logger) {
514
+ this.logger = logger;
515
+ return this;
516
+ }
517
+ setDebug(debug) {
518
+ this.debug = debug;
519
+ return this;
520
+ }
521
+ static create(directory) {
522
+ return new RouterFileBaseRoutingService().setDirectory(directory);
523
+ }
524
+ async loadFiles() {
525
+ const files = fg.sync("**/*.(ts|js)", { cwd: this.directory });
526
+ if (this.debug) this.logger.debug(`Found ${files.length} route files in ${this.directory}`, { files });
527
+ const routes = [];
528
+ for (const file of files) {
529
+ let routePath = file.replace(/\.(ts|js)$/, "");
530
+ let method = "get";
531
+ for (const suffix of [
532
+ ".post",
533
+ ".patch",
534
+ ".delete",
535
+ ".put"
536
+ ]) if (routePath.endsWith(suffix)) {
537
+ method = suffix.substring(1);
538
+ routePath = routePath.replace(suffix, "");
539
+ break;
540
+ }
541
+ routePath = routePath.replace(/\/index$/, "");
542
+ routePath = routePath.replace(/^index$/, "");
543
+ routePath = routePath.replace(/\[\.\.\.([^\]]+)]/g, "*$1");
544
+ routePath = routePath.replace(/\[([^\]]+)]/g, ":$1");
545
+ if (!routePath.startsWith("/")) routePath = "/" + routePath;
546
+ if (routePath === "/") routePath = "/";
547
+ if (this.prefix) routePath = (this.prefix.startsWith("/") ? this.prefix : "/" + this.prefix) + routePath;
548
+ let sortKey = 0;
549
+ if (routePath.includes("*")) sortKey += 1e6;
550
+ const paramCount = (routePath.match(/:/g) || []).length;
551
+ sortKey += paramCount * 1e4;
552
+ const segmentCount = routePath.split("/").filter((s) => s).length;
553
+ sortKey -= segmentCount * 100;
554
+ routes.push({
555
+ file,
556
+ routePath,
557
+ method,
558
+ sortKey,
559
+ module: this.module
560
+ });
561
+ }
562
+ routes.sort((a, b) => a.sortKey - b.sortKey);
563
+ this.routes = routes;
564
+ }
565
+ async registerRoutes() {
566
+ if (!this.router) throw new BaseException("Router instance not set");
567
+ const moduleName = this.module || "unknown";
568
+ const hook = function(route) {
569
+ route.metadata = {
570
+ ...route.metadata,
571
+ module: moduleName
572
+ };
573
+ };
574
+ this.router.on("added", hook);
575
+ for (const route of this.routes) {
576
+ const handler = (await import(`${this.directory}/${route.file}`)).default;
577
+ if (typeof handler !== "function") {
578
+ this.logger.warn(`Route file ${route.file} does not export a default function`);
579
+ continue;
580
+ }
581
+ this.router[route.method](route.routePath, handler);
582
+ }
583
+ this.router.off("added", hook);
584
+ }
585
+ async load() {
586
+ await this.loadFiles();
587
+ await this.registerRoutes();
588
+ }
589
+ };
590
+ //#endregion
591
+ //#region src/shared/services/ConfigService.ts
592
+ var ConfigService = class {
593
+ entries;
594
+ constructor() {
595
+ this.entries = /* @__PURE__ */ new Map();
596
+ }
597
+ list() {
598
+ return Array.from(this.entries.values());
599
+ }
600
+ parseValue(value) {
601
+ if (typeof value === "string" && value.endsWith(":boolean")) return value.replace(":boolean", "").trim() === "true";
602
+ return value;
603
+ }
604
+ loadFromRecord(record, source = "unknow") {
605
+ for (const [key, value] of Object.entries(record)) this.entries.set(key, {
606
+ key,
607
+ value: this.parseValue(value),
608
+ source
609
+ });
610
+ }
611
+ loadFromEntries(entries, source = "unknow") {
612
+ for (const [key, value] of entries) this.entries.set(key, {
613
+ key,
614
+ value: this.parseValue(value),
615
+ source
616
+ });
617
+ }
618
+ toRecord() {
619
+ const record = {};
620
+ for (const [key, entry] of this.entries.entries()) record[key] = entry.value;
621
+ return record;
622
+ }
623
+ has(key) {
624
+ if (this.entries.get(key)) return true;
625
+ if (!key.includes(".")) return false;
626
+ const primary = key.split(".")[0];
627
+ const primaryEntry = this.entries.get(primary);
628
+ if (!primaryEntry) return this.entries.get(key) ? true : false;
629
+ const value = primaryEntry.value;
630
+ if (typeof value !== "object" || Array.isArray(value)) return false;
631
+ return has(value, key.substring(primary.length + 1));
632
+ }
633
+ get(key, defaultValue) {
634
+ const entry = this.entries.get(key);
635
+ if (entry) return entry.value;
636
+ if (!key.includes(".")) return defaultValue;
637
+ const primary = key.split(".")[0];
638
+ const primaryEntry = this.entries.get(primary);
639
+ if (!primaryEntry) {
640
+ const entry = this.entries.get(key);
641
+ return entry ? entry.value : defaultValue;
642
+ }
643
+ const value = primaryEntry.value;
644
+ if (typeof value !== "object" || Array.isArray(value)) return defaultValue;
645
+ return get(value, key.substring(primary.length + 1), defaultValue);
646
+ }
647
+ getOne(keys, defaultValue) {
648
+ for (const key of keys) if (this.has(key)) return this.get(key);
649
+ return defaultValue;
650
+ }
651
+ set(key, value, source = "runtime") {
652
+ if (!key.includes(".")) {
653
+ this.entries.set(key, {
654
+ key,
655
+ source,
656
+ value
657
+ });
658
+ return;
659
+ }
660
+ const primary = key.split(".")[0];
661
+ let primaryValue = this.get(primary, {});
662
+ if (typeof primaryValue !== "object" || Array.isArray(primaryValue)) primaryValue = {};
663
+ set(primaryValue, key.substring(primary.length + 1), value);
664
+ this.entries.set(primary, {
665
+ key: primary,
666
+ source,
667
+ value: primaryValue
668
+ });
669
+ }
670
+ unset(key) {
671
+ if (!key.includes(".")) {
672
+ this.entries.delete(key);
673
+ return;
674
+ }
675
+ const primary = key.split(".")[0];
676
+ const primaryValue = this.get(primary, {});
677
+ if (!primaryValue) return;
678
+ if (typeof primaryValue !== "object" || Array.isArray(primaryValue)) return;
679
+ unset(primaryValue, key.substring(primary.length + 1));
680
+ this.entries.set(primary, {
681
+ key: primary,
682
+ source: "runtime",
683
+ value: primaryValue
684
+ });
685
+ }
686
+ clear() {
687
+ this.entries.clear();
688
+ }
689
+ };
690
+ //#endregion
691
+ //#region src/shared/services/ContainerService.ts
692
+ var ContainerService = class {
693
+ entries = /* @__PURE__ */ new Map();
694
+ loadFromRecord(record) {
695
+ Object.entries(record).forEach(([key, value]) => {
696
+ this.set(key, value);
697
+ });
698
+ }
699
+ toRecord() {
700
+ const record = {};
701
+ for (const [key, value] of this.entries.entries()) record[String(key)] = value;
702
+ return record;
703
+ }
704
+ set(payload, value) {
705
+ let key = payload;
706
+ if (typeof payload === "function" || typeof payload === "object") key = payload.name;
707
+ this.entries.set(key, value);
708
+ }
709
+ has(payload) {
710
+ let key = payload;
711
+ if (typeof payload === "function" || typeof payload === "object") key = payload.name;
712
+ return this.entries.has(key);
713
+ }
714
+ get(payload) {
715
+ let key = payload;
716
+ if (typeof payload === "function" || typeof payload === "object") key = payload.name;
717
+ if (!this.has(key)) throw new Error(`entry not found: ${String(key)}`);
718
+ return this.entries.get(key);
719
+ }
720
+ singleton(classConstructor) {
721
+ const key = classConstructor.name;
722
+ const existingInstance = this.entries.get(key);
723
+ if (existingInstance) return existingInstance;
724
+ const newInstance = new classConstructor();
725
+ this.entries.set(key, newInstance);
726
+ return newInstance;
727
+ }
728
+ load(entries) {
729
+ Object.entries(entries).forEach(([key, value]) => {
730
+ this.set(key, value);
731
+ });
732
+ }
733
+ proxy(key) {
734
+ return new Proxy({}, {
735
+ get: (_target, prop) => {
736
+ const entry = this.get(key);
737
+ const value = entry[prop];
738
+ if (typeof value === "function") return value.bind(entry);
739
+ return entry[prop];
740
+ },
741
+ set: (_target, prop, value) => {
742
+ const entry = this.get(key);
743
+ entry[prop] = value;
744
+ return true;
745
+ }
746
+ });
747
+ }
748
+ keys() {
749
+ return Array.from(this.entries.keys());
750
+ }
751
+ };
752
+ //#endregion
753
+ //#region src/shared/validators/url.ts
754
+ var url_exports = /* @__PURE__ */ __exportAll({
755
+ array: () => array,
756
+ arrayNumber: () => arrayNumber,
757
+ boolean: () => boolean,
758
+ date: () => date,
759
+ datetime: () => datetime,
760
+ number: () => number,
761
+ object: () => object
762
+ });
763
+ const number = () => v.pipe(v.union([v.string(), v.number()]), v.transform(Number), v.integer());
764
+ const boolean = () => v.pipe(v.union([v.string(), v.boolean()]), v.transform((v) => v === true || v === "true"));
765
+ const date = () => v.pipe(v.union([v.string(), v.date()]), v.transform((v) => v instanceof Date ? v : new Date(v)), v.transform((v) => v ? format(v, "yyyy-MM-dd") : v));
766
+ const datetime = () => v.pipe(v.union([v.string(), v.date()]), v.transform((v) => {
767
+ if (!v) return v;
768
+ if (v === "null") return null;
769
+ if (typeof v === "string") v = new Date(v);
770
+ return format(v, "yyyy-MM-dd HH:mm");
771
+ }));
772
+ const array = (schema = v.any()) => v.pipe(v.union([v.string(), v.array(v.string())]), v.transform((value) => Array.isArray(value) ? value : value.split(",")), v.array(schema));
773
+ const arrayNumber = () => v.pipe(array(), v.transform((value) => value.map(Number)));
774
+ const object = () => v.pipe(v.union([v.string(), v.record(v.string(), v.any())]), v.transform((value) => typeof value === "string" ? qs.parse(value) : value), v.transform((value) => {
775
+ const result = {};
776
+ for (const key in value) set(result, key, get(value, key));
777
+ return result;
778
+ }));
779
+ //#endregion
780
+ //#region src/shared/services/ValidatorService.ts
781
+ const extras = { url: url_exports };
782
+ var ValidatorService = class {
783
+ v = {
784
+ ...v,
785
+ extras
786
+ };
787
+ create(cb) {
788
+ return cb(this.v);
789
+ }
790
+ validate(payload, cb) {
791
+ const schema = typeof cb === "function" ? cb(this.v) : cb;
792
+ const { output, issues, success } = v.safeParse(schema, payload);
793
+ if (!success) {
794
+ const flatten = v.flatten(issues);
795
+ const messages = [];
796
+ if (flatten.root) messages.push(...flatten.root);
797
+ if (flatten.nested) Object.entries(flatten.nested).forEach((entry) => {
798
+ const [key, value] = entry;
799
+ messages.push(...value.map((v) => `${key}: ${v}`));
800
+ });
801
+ const error = new BaseException(messages.length ? messages.join(", ") : "Validation failed", 422);
802
+ error.name = "ValidationError";
803
+ Object.assign(error, { messages });
804
+ throw error;
805
+ }
806
+ return output;
807
+ }
808
+ async validateAsync(payload, cb) {
809
+ const schema = typeof cb === "function" ? cb(this.v) : cb;
810
+ const { output, issues, success } = await v.safeParseAsync(schema, payload);
811
+ if (!success) {
812
+ const error = /* @__PURE__ */ new Error("Validation failed");
813
+ const flatten = v.flatten(issues);
814
+ const details = {
815
+ ...flatten.root,
816
+ ...flatten.nested
817
+ };
818
+ Object.assign(error, { details });
819
+ throw error;
820
+ }
821
+ return output;
822
+ }
823
+ isValid(payload, cb) {
824
+ const schema = typeof cb === "function" ? cb(this.v) : cb;
825
+ const { success } = v.safeParse(schema, payload);
826
+ return success;
827
+ }
828
+ };
829
+ v.object({
830
+ id: v.number(),
831
+ permission_id: v.number(),
832
+ assignable_type: v.string(),
833
+ assignable_id: v.string(),
834
+ created_at: v.string(),
835
+ updated_at: v.string()
836
+ });
837
+ v.object({
838
+ id: v.number(),
839
+ name: v.nullable(v.string()),
840
+ description: v.nullable(v.string()),
841
+ action: v.string(),
842
+ subject: v.string(),
843
+ conditions: v.nullable(v.string()),
844
+ created_at: v.string(),
845
+ updated_at: v.string(),
846
+ expires_at: v.string()
847
+ });
848
+ v.object({
849
+ id: v.number(),
850
+ name: v.nullable(v.string()),
851
+ type: v.string(),
852
+ user_id: v.number(),
853
+ token: v.string(),
854
+ created_at: v.string(),
855
+ updated_at: v.string(),
856
+ expires_at: v.string()
857
+ });
858
+ //#endregion
859
+ //#region src/shared/exceptions/ShellException.ts
860
+ var ShellException = class extends BaseException {
861
+ output;
862
+ bin;
863
+ args;
864
+ constructor(message, output, bin, args) {
865
+ super(message, 501);
866
+ this.output = output;
867
+ this.bin = bin;
868
+ this.args = args;
869
+ }
870
+ };
871
+ new ValidatorService();
872
+ //#endregion
873
+ //#region src/shared/entities/LifecycleHook.ts
874
+ var LifecycleHook = class {
875
+ hook_id;
876
+ order;
877
+ subhooks;
878
+ constructor() {
879
+ if (!this.hook_id) this.hook_id = this.constructor.name;
880
+ }
881
+ async onRegister() {}
882
+ async onLoad() {}
883
+ async onBoot() {}
884
+ async onShutdown() {}
885
+ };
886
+ //#endregion
887
+ //#region src/shared/mixins/BaseEntityMixin.ts
888
+ function BaseEntity(Base) {
889
+ return class extends Base {
890
+ static from(data) {
891
+ const contructor = typeof this === "function" ? this : Base;
892
+ const instance = new contructor();
893
+ let payload = { ...data };
894
+ if (typeof contructor?.parse === "function") payload = contructor.parse(data);
895
+ if (typeof this?.parse === "function") payload = this.parse(data);
896
+ Object.assign(instance, payload);
897
+ return instance;
898
+ }
899
+ merge(data) {
900
+ Object.assign(this, data);
901
+ return this;
902
+ }
903
+ };
904
+ }
905
+ //#endregion
906
+ //#region src/shared/entities/ModuleEntity.ts
907
+ var Module$1 = class extends compose(BaseEntity, mixin(LifecycleHook)) {
908
+ id;
909
+ name;
910
+ enabled = false;
911
+ dependencies = {};
912
+ build = {};
913
+ directory;
914
+ upgrade_info;
915
+ setData(data) {
916
+ const filtered = Object.fromEntries(Object.entries(data).filter(([, v]) => v !== void 0));
917
+ Object.assign(this, filtered);
918
+ this.hook_id = `module:${this.id}`;
919
+ }
920
+ };
921
+ compose(BaseEntity);
922
+ //#endregion
923
+ //#region src/server/facades/container.ts
924
+ const container = globalThis.container || new ContainerService();
925
+ //#endregion
926
+ //#region src/server/facades/logger.ts
927
+ const logger = container.proxy(LoggerService);
928
+ //#endregion
929
+ //#region src/server/entities/RouteEntity.ts
930
+ var Route = class {
931
+ path = "";
932
+ method = "get";
933
+ handler = null;
934
+ middlewares = [];
935
+ metadata = {};
936
+ constructor(data = {}) {
937
+ this.path = data.path || "";
938
+ this.method = data.method || "get";
939
+ this.handler = data.handler || null;
940
+ this.middlewares = data.middlewares || [];
941
+ this.metadata = data.metadata || {};
942
+ }
943
+ static params(routePath, requestPath) {
944
+ const params = {};
945
+ const routeSegments = routePath.split("/").filter(Boolean);
946
+ const requestSegments = requestPath.split("/").filter(Boolean);
947
+ for (let i = 0; i < routeSegments.length; i++) {
948
+ const routeSegment = routeSegments[i];
949
+ const requestSegment = requestSegments[i];
950
+ if (routeSegment.startsWith(":")) {
951
+ const paramName = routeSegment.slice(1);
952
+ params[paramName] = requestSegment;
953
+ }
954
+ if (routeSegment === "*") {
955
+ params["*"] = requestSegments.slice(i).join("/");
956
+ break;
957
+ }
958
+ }
959
+ return params;
960
+ }
961
+ static query(requestPath) {
962
+ const query = {};
963
+ const queryString = requestPath.split("?")[1];
964
+ if (!queryString) return query;
965
+ return qs.parse(queryString);
966
+ }
967
+ toJSON() {
968
+ return {
969
+ path: this.path,
970
+ method: this.method,
971
+ middlewares: this.middlewares.map((mw) => mw.constructor.name),
972
+ metadata: this.metadata
973
+ };
974
+ }
975
+ };
976
+ //#endregion
977
+ //#region src/shared/mixins/HooksMixin.ts
978
+ async function emitHook(constructor, event, ...args) {
979
+ const listeners = constructor.listeners || [];
980
+ for await (const l of listeners.filter((l) => l.event === event)) await l.listener(...args);
981
+ }
982
+ function onHook(constructor, event, listener) {
983
+ const listeners = constructor.listeners || [];
984
+ if (listeners.find((l) => l.event === event && l.listener === listener)) return;
985
+ listeners.push({
986
+ event,
987
+ listener
988
+ });
989
+ constructor.listeners = listeners;
990
+ }
991
+ function HooksStatic(Base) {
992
+ return class extends Base {
993
+ constructor(...args) {
994
+ super(...args);
995
+ if (typeof this.constructor.boot === "function") this.constructor.boot.apply(this.constructor);
996
+ }
997
+ static listeners = [];
998
+ static on(event, listener) {
999
+ return onHook(this, event, listener);
1000
+ }
1001
+ static async emit(event, ...args) {
1002
+ return emitHook(this, event, ...args);
1003
+ }
1004
+ };
1005
+ }
1006
+ function Hooks(Base) {
1007
+ return class extends Base {
1008
+ listeners;
1009
+ constructor(...args) {
1010
+ super(...args);
1011
+ this.listeners = [];
1012
+ }
1013
+ on(event, listener) {
1014
+ this.listeners.push({
1015
+ event,
1016
+ listener
1017
+ });
1018
+ }
1019
+ off(event, listener) {
1020
+ const index = this.listeners.findIndex((l) => l.event === event && l.listener === listener);
1021
+ if (index === -1) return;
1022
+ this.listeners.splice(index, 1);
1023
+ }
1024
+ emit(event, ...args) {
1025
+ const listeners = this.listeners.filter((l) => l.event === event);
1026
+ for (const l of listeners) l.listener(...args);
1027
+ }
1028
+ async emitAsync(event, ...args) {
1029
+ const listeners = this.listeners.filter((l) => l.event === event);
1030
+ for await (const l of listeners) await l.listener(...args);
1031
+ }
1032
+ };
1033
+ }
1034
+ HooksStatic.emit = emitHook;
1035
+ HooksStatic.on = onHook;
1036
+ //#endregion
1037
+ //#region src/server/services/RouterService.ts
1038
+ var Router = class Router extends compose(Hooks) {
1039
+ routes = [];
1040
+ middlewares = [];
1041
+ prefixes = [];
1042
+ groups = [];
1043
+ groupPrefixes = [];
1044
+ debug = false;
1045
+ logger = logger.child({ label: "router" });
1046
+ metadata = {};
1047
+ constructor(data = {}) {
1048
+ super();
1049
+ this.routes = data.routes || [];
1050
+ this.middlewares = data.middlewares || [];
1051
+ this.prefixes = data.prefixes || [];
1052
+ this.groups = data.groups || [];
1053
+ this.groupPrefixes = data.groupPrefixes || [];
1054
+ this.debug = data.debug || false;
1055
+ this.metadata = data.metadata || {};
1056
+ this.listeners = data.listeners || [];
1057
+ }
1058
+ use(middleware, context = "route") {
1059
+ this.middlewares.push({
1060
+ middleware,
1061
+ context
1062
+ });
1063
+ return this;
1064
+ }
1065
+ prefix(prefix) {
1066
+ this.prefixes.push(prefix);
1067
+ return this;
1068
+ }
1069
+ makePath(args) {
1070
+ return join(...this.groupPrefixes, ...this.prefixes, args);
1071
+ }
1072
+ add(payload) {
1073
+ const route = new Route({
1074
+ method: payload.method,
1075
+ path: this.makePath(payload.path),
1076
+ handler: payload.handler,
1077
+ middlewares: this.middlewares.map((m) => m.middleware)
1078
+ });
1079
+ this.middlewares = this.middlewares.filter((m) => m.context !== "route");
1080
+ this.prefixes = [];
1081
+ this.routes.push(route);
1082
+ if (this.debug) this.logger.debug("added route", route);
1083
+ this.emit("added", route);
1084
+ }
1085
+ get(path, handler) {
1086
+ this.add({
1087
+ path,
1088
+ method: "GET",
1089
+ handler
1090
+ });
1091
+ }
1092
+ post(path, handler) {
1093
+ this.add({
1094
+ path,
1095
+ method: "POST",
1096
+ handler
1097
+ });
1098
+ }
1099
+ put(path, handler) {
1100
+ this.add({
1101
+ path,
1102
+ method: "PUT",
1103
+ handler
1104
+ });
1105
+ }
1106
+ patch(path, handler) {
1107
+ this.add({
1108
+ path,
1109
+ method: "PATCH",
1110
+ handler
1111
+ });
1112
+ }
1113
+ many(methods, path, handler) {
1114
+ methods.forEach((method) => {
1115
+ this.add({
1116
+ path,
1117
+ method,
1118
+ handler
1119
+ });
1120
+ });
1121
+ }
1122
+ delete(path, handler) {
1123
+ this.add({
1124
+ path,
1125
+ method: "DELETE",
1126
+ handler
1127
+ });
1128
+ }
1129
+ group() {
1130
+ const group = new Router({
1131
+ listeners: this.listeners,
1132
+ debug: this.debug
1133
+ });
1134
+ group.groupPrefixes = this.prefixes;
1135
+ group.middlewares = this.middlewares.map((r) => ({
1136
+ middleware: r.middleware,
1137
+ context: "group"
1138
+ }));
1139
+ this.groups.push(group);
1140
+ this.middlewares = this.middlewares.filter((m) => m.context !== "route");
1141
+ this.prefixes = [];
1142
+ return group;
1143
+ }
1144
+ resolve(method, path) {
1145
+ const route = this.list().find((r) => {
1146
+ if (r.method.toUpperCase() !== method.toUpperCase()) return false;
1147
+ return this.matchPath(r.path, path);
1148
+ });
1149
+ if (!route) return null;
1150
+ return route;
1151
+ }
1152
+ async execute(route, initialCtx) {
1153
+ if (!route.handler) throw new Error(`Route handler not found for ${route.method} ${route.path}`);
1154
+ const ctx = { ...initialCtx };
1155
+ for await (const middleware of route.middlewares) {
1156
+ const result = await middleware.handle(ctx);
1157
+ if (result && "redirect" in result) return result;
1158
+ Object.assign(ctx, result);
1159
+ }
1160
+ return route.handler(ctx);
1161
+ }
1162
+ matchPath(routePath, requestPath) {
1163
+ const routeSegments = routePath.split("/").filter(Boolean);
1164
+ const requestSegments = requestPath.split("/").filter(Boolean);
1165
+ for (let i = 0; i < routeSegments.length; i++) {
1166
+ const routeSegment = routeSegments[i];
1167
+ const requestSegment = requestSegments[i];
1168
+ if (routeSegment === "*") return true;
1169
+ if (i >= requestSegments.length) return false;
1170
+ if (routeSegment.startsWith(":")) continue;
1171
+ if (routeSegment !== requestSegment) return false;
1172
+ }
1173
+ if (requestSegments.length > routeSegments.length) return false;
1174
+ return true;
1175
+ }
1176
+ clear() {
1177
+ if (this.debug) this.logger.debug("clear", { count: this.routes.length });
1178
+ this.routes = [];
1179
+ this.groups = [];
1180
+ }
1181
+ list() {
1182
+ return this.routes.concat(...this.groups.map((g) => g.routes));
1183
+ }
1184
+ async load(options = {}) {
1185
+ this.debug = options.debug ?? this.debug;
1186
+ if (this.debug) this.logger.debug("service loaded in debug mode");
1187
+ }
1188
+ loadSync(options = {}) {
1189
+ this.debug = options.debug ?? this.debug;
1190
+ if (this.debug) this.logger.debug("service loaded in debug mode");
1191
+ }
1192
+ };
1193
+ //#endregion
1194
+ //#region src/server/services/ShellService.ts
1195
+ var ShellService = class {
1196
+ debug;
1197
+ logger;
1198
+ init(data = {}) {
1199
+ this.debug = data.debug || false;
1200
+ this.logger = data.logger || logger.child({ label: "shell" });
1201
+ if (this.debug) this.logger.debug("initialized in debug mode");
1202
+ }
1203
+ /**
1204
+ * Execute a shell command and return a promise
1205
+ */
1206
+ async command(bin, args, options = {}) {
1207
+ return new Promise((resolve, reject) => {
1208
+ const child = spawn(bin, args, {
1209
+ cwd: options.cwd || process.cwd(),
1210
+ stdio: "pipe",
1211
+ shell: options.shell ?? true,
1212
+ env: options.env || process.env
1213
+ });
1214
+ let data = "";
1215
+ child.stdout?.on("data", (d) => {
1216
+ data += d.toString();
1217
+ });
1218
+ child.stderr?.on("data", (d) => {
1219
+ data += d.toString();
1220
+ });
1221
+ child.on("close", (code) => {
1222
+ if (this.debug) this.logger.debug("command executed", {
1223
+ bin,
1224
+ args,
1225
+ output: data
1226
+ });
1227
+ if (code === 0) return resolve();
1228
+ const errorMessage = `Command failed with exit code ${code}`;
1229
+ this.logger.error(errorMessage, {
1230
+ bin,
1231
+ args,
1232
+ code,
1233
+ output: data
1234
+ });
1235
+ reject(new ShellException(errorMessage, data, bin, args));
1236
+ });
1237
+ child.on("error", (error) => {
1238
+ this.logger.error("Command execution error", {
1239
+ bin,
1240
+ args,
1241
+ error: error.message
1242
+ });
1243
+ reject(error);
1244
+ });
1245
+ });
1246
+ }
1247
+ /**
1248
+ * Execute a shell command and return the output as a string
1249
+ */
1250
+ async executeCommandWithOutput(bin, args, options = {}) {
1251
+ if (this.debug) this.logger.debug("executing command", {
1252
+ bin,
1253
+ args
1254
+ });
1255
+ return new Promise((resolve, reject) => {
1256
+ const child = spawn(bin, args, {
1257
+ cwd: options.cwd || process.cwd(),
1258
+ stdio: "pipe",
1259
+ shell: true,
1260
+ env: options.env || process.env
1261
+ });
1262
+ let output = "";
1263
+ let errorOutput = "";
1264
+ child.stdout?.on("data", (data) => {
1265
+ output += data.toString();
1266
+ });
1267
+ child.stderr?.on("data", (data) => {
1268
+ errorOutput += data.toString();
1269
+ });
1270
+ child.on("close", (code) => {
1271
+ if (code === 0) resolve(output.trim());
1272
+ else {
1273
+ const errorMessage = `Command failed with exit code ${code}: ${errorOutput}`;
1274
+ this.logger.error(errorMessage, {
1275
+ bin,
1276
+ args,
1277
+ code,
1278
+ errorOutput
1279
+ });
1280
+ reject(new ShellException(errorMessage, output, bin, args));
1281
+ }
1282
+ });
1283
+ child.on("error", (error) => {
1284
+ this.logger.error("Command execution error", {
1285
+ bin,
1286
+ args,
1287
+ error: error.message
1288
+ });
1289
+ reject(error);
1290
+ });
1291
+ });
1292
+ }
1293
+ };
1294
+ //#endregion
1295
+ //#region src/server/repositories/DatabaseRepository.ts
1296
+ var DatabaseRepository = class {
1297
+ db = null;
1298
+ table = "";
1299
+ primaryKey = "id";
1300
+ constructor(db, table, primaryKey) {
1301
+ if (db) this.db = db;
1302
+ if (table) this.table = table;
1303
+ if (primaryKey) this.primaryKey = primaryKey;
1304
+ }
1305
+ setDatabase(db) {
1306
+ this.db = db;
1307
+ return this;
1308
+ }
1309
+ setTable(table) {
1310
+ this.table = table;
1311
+ return this;
1312
+ }
1313
+ setPrimaryKey(primaryKey) {
1314
+ this.primaryKey = primaryKey;
1315
+ return this;
1316
+ }
1317
+ query(options) {
1318
+ return options?.qb || this.db.selectFrom(this.table);
1319
+ }
1320
+ async count(options) {
1321
+ let qb = this.query(options);
1322
+ qb = qb.select((eb) => eb.fn.countAll().as("count"));
1323
+ const result = await qb.executeTakeFirstOrThrow();
1324
+ return Number(result.count);
1325
+ }
1326
+ async findMany(options) {
1327
+ let qb = this.query(options);
1328
+ qb = qb.selectAll();
1329
+ if (options?.limit) qb = qb.limit(options.limit);
1330
+ if (options?.offset) qb = qb.offset(options.offset);
1331
+ if (options?.orderBy) {
1332
+ const orderBy = Array.isArray(options.orderBy) ? options.orderBy : [options.orderBy];
1333
+ const orderDirection = Array.isArray(options.orderDirection) ? options.orderDirection : [options.orderDirection ?? "asc"];
1334
+ orderBy.forEach((ob, index) => {
1335
+ qb = qb.orderBy(ob, orderDirection[index] || "asc");
1336
+ });
1337
+ }
1338
+ return await qb.execute();
1339
+ }
1340
+ async findById(id, options) {
1341
+ let qb = this.query(options);
1342
+ qb = qb.selectAll();
1343
+ qb = qb.where(this.primaryKey, "=", id);
1344
+ return await qb.executeTakeFirst();
1345
+ }
1346
+ async findByIdOrFail(id, options) {
1347
+ const item = await this.findById(id, options);
1348
+ if (!item) throw new BaseException("Item not found", 404);
1349
+ return item;
1350
+ }
1351
+ async paginate(options) {
1352
+ const page = options?.page ?? 1;
1353
+ const offset = (page - 1) * (options?.limit ?? 10);
1354
+ const limit = options?.limit ?? 10;
1355
+ const findAllOptions = {
1356
+ ...options,
1357
+ limit,
1358
+ offset
1359
+ };
1360
+ const countOptions = { ...options };
1361
+ const [items, totalItems] = await Promise.all([this.findMany(findAllOptions), this.count(countOptions)]);
1362
+ return {
1363
+ items,
1364
+ page,
1365
+ per_page: limit,
1366
+ total: totalItems,
1367
+ total_pages: Math.ceil(totalItems / limit)
1368
+ };
1369
+ }
1370
+ async create(data) {
1371
+ let qb = this.db.insertInto(this.table);
1372
+ qb = qb.values(data).returningAll();
1373
+ return await qb.executeTakeFirst();
1374
+ }
1375
+ async createMany(data) {
1376
+ let qb = this.db.insertInto(this.table);
1377
+ qb = qb.values(data).returningAll();
1378
+ return await qb.execute();
1379
+ }
1380
+ async updateById(id, data) {
1381
+ const row = await this.findByIdOrFail(id);
1382
+ let qb = this.db.updateTable(this.table);
1383
+ qb = qb.set(data).where(this.primaryKey, "=", row[this.primaryKey]).returningAll();
1384
+ await qb.executeTakeFirst();
1385
+ }
1386
+ async deleteById(id) {
1387
+ const row = await this.findByIdOrFail(id);
1388
+ let qb = this.db.deleteFrom(this.table);
1389
+ qb = qb.where(this.primaryKey, "=", row[this.primaryKey]);
1390
+ await qb.executeTakeFirst();
1391
+ }
1392
+ async deleteMany(options) {
1393
+ const deleteOptions = {
1394
+ ...options,
1395
+ qb: this.db.deleteFrom(this.table)
1396
+ };
1397
+ let qb = this.query(deleteOptions);
1398
+ if (options?.limit) qb = qb.limit(options.limit);
1399
+ await qb.execute();
1400
+ }
1401
+ };
1402
+ //#endregion
1403
+ //#region src/server/mixins/DatabaseRepositoryInferMixin.ts
1404
+ function DatabaseRepositoryInferMixin() {
1405
+ return function(Base) {
1406
+ class OptionsMixin extends Base {}
1407
+ return OptionsMixin;
1408
+ };
1409
+ }
1410
+ //#endregion
1411
+ //#region src/server/repositories/PermissionAssignmentRepository.ts
1412
+ var PermissionAssignmentRepository = class extends compose(mixin(DatabaseRepository), DatabaseRepositoryInferMixin()) {
1413
+ constructor(db) {
1414
+ super(db, "permissions_assignments", "id");
1415
+ }
1416
+ query(options) {
1417
+ let qb = super.query(options);
1418
+ if (options?.id) {
1419
+ const ids = Array.isArray(options.id) ? options.id : [options.id];
1420
+ qb = qb.where("id", "in", ids);
1421
+ }
1422
+ if (options?.permissionId) {
1423
+ const permissionIds = Array.isArray(options.permissionId) ? options.permissionId : [options.permissionId];
1424
+ qb = qb.where("permission_id", "in", permissionIds);
1425
+ }
1426
+ if (options?.assignableId) {
1427
+ const assignableIds = Array.isArray(options.assignableId) ? options.assignableId : [options.assignableId];
1428
+ qb = qb.where("assignable_id", "in", assignableIds);
1429
+ }
1430
+ if (options?.assignableType) {
1431
+ const assignableTypes = Array.isArray(options.assignableType) ? options.assignableType : [options.assignableType];
1432
+ qb = qb.where("assignable_type", "in", assignableTypes);
1433
+ }
1434
+ return qb;
1435
+ }
1436
+ };
1437
+ //#endregion
1438
+ //#region src/server/repositories/PermissionRepository.ts
1439
+ var PermissionRepository = class extends compose(mixin(DatabaseRepository), DatabaseRepositoryInferMixin()) {
1440
+ constructor(db) {
1441
+ super(db, "permissions", "id");
1442
+ }
1443
+ query(options) {
1444
+ let qb = super.query(options);
1445
+ if (options?.id) {
1446
+ const ids = Array.isArray(options.id) ? options.id : [options.id];
1447
+ qb = qb.where("id", "in", ids);
1448
+ }
1449
+ if (options?.search) qb = qb.where("name", "like", `%${options.search}%`);
1450
+ return qb;
1451
+ }
1452
+ };
1453
+ //#endregion
1454
+ //#region src/server/repositories/TokenRepository.ts
1455
+ var TokenRepository = class extends compose(mixin(DatabaseRepository), DatabaseRepositoryInferMixin()) {
1456
+ constructor(db) {
1457
+ super(db, "tokens", "id");
1458
+ }
1459
+ query(options) {
1460
+ let qb = super.query(options);
1461
+ if (options?.id) {
1462
+ const ids = Array.isArray(options.id) ? options.id : [options.id];
1463
+ qb = qb.where("id", "in", ids);
1464
+ }
1465
+ if (options?.search) qb = qb.where("name", "like", `%${options.search}%`);
1466
+ if (options?.type) {
1467
+ const types = Array.isArray(options.type) ? options.type : [options.type];
1468
+ qb = qb.where("type", "in", types);
1469
+ }
1470
+ return qb;
1471
+ }
1472
+ async findByToken(token) {
1473
+ let qb = this.query();
1474
+ qb = qb.selectAll();
1475
+ qb = qb.where("token", "=", token);
1476
+ return await qb.executeTakeFirst() || null;
288
1477
  }
289
1478
  };
290
1479
  //#endregion
@@ -314,7 +1503,7 @@ var GitGateway = class {
314
1503
  result.sshKeyFile = this.sshKeyFile;
315
1504
  }
316
1505
  if (this.sshKey) {
317
- const tempFile = this.sshKeyTmpFileName ?? join(tmpdir(), `git-ssh-key-${randomUUID()}`);
1506
+ const tempFile = this.sshKeyTmpFileName ?? join$1(tmpdir(), `git-ssh-key-${randomUUID()}`);
318
1507
  await writeFile(tempFile, this.sshKey, { mode: 384 });
319
1508
  result.env.GIT_SSH_COMMAND = `ssh -i ${escapeShellArgument(tempFile)} -o StrictHostKeyChecking=no`;
320
1509
  result.sshKeyFile = tempFile;
@@ -377,4 +1566,178 @@ var GitGateway = class {
377
1566
  }
378
1567
  };
379
1568
  //#endregion
380
- export { GitBranchRepository, GitCommitRepository, GitGateway, PluginIpcClient, PluginIpcHost, PluginRouter };
1569
+ //#region src/server/facades/config.ts
1570
+ const config = container.proxy(ConfigService);
1571
+ //#endregion
1572
+ //#region src/server/facades/database.ts
1573
+ const key = "database";
1574
+ const database = container.proxy(key);
1575
+ //#endregion
1576
+ //#region src/server/facades/router.ts
1577
+ const router = container.proxy(Router);
1578
+ //#endregion
1579
+ //#region src/server/facades/shell.ts
1580
+ const shell = new ShellService();
1581
+ //#endregion
1582
+ //#region src/server/utils/defineLoader.ts
1583
+ function defineLoader(loader) {
1584
+ return loader;
1585
+ }
1586
+ //#endregion
1587
+ //#region src/server/loaders/createHasManyThroughLoader.ts
1588
+ async function loadHasManyThrough(payload, options) {
1589
+ const entities = Array.isArray(payload) ? payload : [payload];
1590
+ const target = options.target;
1591
+ const pivot = options.pivot;
1592
+ function findKey(entity, keyOrFn) {
1593
+ if (typeof keyOrFn === "function") return keyOrFn(entity);
1594
+ return get(entity, keyOrFn);
1595
+ }
1596
+ const pivoIds = entities.map((e) => findKey(e, pivot.sourceKey)).filter(Boolean);
1597
+ const pivotEntities = await pivot.findEntities(pivoIds);
1598
+ const targetIds = pivotEntities.map((p) => findKey(p, pivot.targetKey)).filter(Boolean);
1599
+ const targetEntities = await target.findEntities(targetIds);
1600
+ for (const entity of entities) {
1601
+ const pivots = pivotEntities.filter((p) => findKey(p, pivot.sourceKey) === findKey(entity, pivot.sourceKey));
1602
+ if (!pivots.length) {
1603
+ set(entity, options.key, []);
1604
+ continue;
1605
+ }
1606
+ const targets = targetEntities.filter((t) => pivots.some((p) => findKey(p, target.sourceKey) === findKey(t, target.targetKey)));
1607
+ set(entity, options.key, targets);
1608
+ }
1609
+ }
1610
+ function createHasManyThroughLoader(options) {
1611
+ return defineLoader({ load: async (entities) => loadHasManyThrough(entities, options) });
1612
+ }
1613
+ //#endregion
1614
+ //#region src/server/utils/basePath.ts
1615
+ const BASE_PATH = process.env.ZENITH_BASE_PATH;
1616
+ function basePath(...args) {
1617
+ if (!BASE_PATH) throw new Error("ZENITH_BASE_PATH environment variable is not set");
1618
+ return path.resolve(BASE_PATH, ...args);
1619
+ }
1620
+ function tmpPath(...args) {
1621
+ return basePath("tmp", ...args);
1622
+ }
1623
+ //#endregion
1624
+ //#region src/server/entities/ModuleEntity.ts
1625
+ var Module = class extends composeWith(Module$1) {
1626
+ get git() {
1627
+ return new GitGateway({
1628
+ cwd: this.directory,
1629
+ sshKey: config.get(`modules.${this.id}.ssh_key`),
1630
+ sshKeyTmpFileName: tmpPath(`ssh_key_${this.id}.pem`),
1631
+ logger: logger.child({ label: "git" }),
1632
+ debug: config.get("git.debug", false)
1633
+ });
1634
+ }
1635
+ makePath(...parts) {
1636
+ return join(this.directory, this.id, ...parts);
1637
+ }
1638
+ staticPath(...parts) {
1639
+ return join("/static", "modules", this.id, ...parts);
1640
+ }
1641
+ command = (bin, args, options) => {
1642
+ return shell.command(bin, args, {
1643
+ cwd: this.directory,
1644
+ ...options
1645
+ });
1646
+ };
1647
+ load() {
1648
+ const manifestPath = this.makePath("module.json");
1649
+ if (!fs.existsSync(manifestPath)) return;
1650
+ const content = fs.readFileSync(manifestPath, "utf-8");
1651
+ const json = JSON.parse(content);
1652
+ this.dependencies = json.dependencies || {};
1653
+ this.build = json.build || {};
1654
+ }
1655
+ };
1656
+ //#endregion
1657
+ //#region src/server/utils/createLoaderFactory.ts
1658
+ function createLoaderFactory(loaders) {
1659
+ async function load(entities, names) {
1660
+ const items = Array.isArray(entities) ? entities : [entities];
1661
+ const relationNames = Array.isArray(names) ? names : [names];
1662
+ for (const name of relationNames) {
1663
+ const loader = loaders?.[name];
1664
+ if (!loader) throw new BaseException(`Loader ${String(name)} not declared`);
1665
+ await loader.load(items);
1666
+ }
1667
+ }
1668
+ return {
1669
+ keys: Object.keys(loaders),
1670
+ loaders,
1671
+ load
1672
+ };
1673
+ }
1674
+ //#endregion
1675
+ //#region src/server/utils/importAll.ts
1676
+ async function importFiles(files, options = {}) {
1677
+ const modules = {};
1678
+ let onError = (ctx) => {
1679
+ Object.assign(ctx.error, { filename: ctx.filename });
1680
+ logger.error(`Failed to import ${ctx.filename}`, ctx.error);
1681
+ };
1682
+ if (options.onError) onError = options.onError;
1683
+ for (const filename of files) {
1684
+ if (options.exclude && options.exclude.some((pattern) => filename.includes(pattern))) continue;
1685
+ const ctx = { filename };
1686
+ if (options.onBeforeImport) await options.onBeforeImport(ctx);
1687
+ const cleanFilename = ctx.filename.split("?")[0];
1688
+ if (/\.(mts|ts|js)$/.test(cleanFilename)) {
1689
+ const fileUrl = pathToFileURL(path.resolve(ctx.filename));
1690
+ if (options.cache === false) fileUrl.searchParams.set("t", Date.now().toString());
1691
+ const [error, mod] = await tryCatch(() => import(fileUrl.toString()));
1692
+ if (error) {
1693
+ Object.assign(error, {
1694
+ filename: ctx.filename,
1695
+ url: fileUrl
1696
+ });
1697
+ onError({
1698
+ filename: ctx.filename,
1699
+ error
1700
+ });
1701
+ continue;
1702
+ }
1703
+ modules[filename] = mod;
1704
+ }
1705
+ if (/\.json$/.test(cleanFilename)) {
1706
+ const [error, json] = await tryCatch(async () => {
1707
+ const text = await fs.promises.readFile(ctx.filename, "utf8");
1708
+ return JSON.parse(text);
1709
+ });
1710
+ if (error) {
1711
+ onError({
1712
+ filename: ctx.filename,
1713
+ error
1714
+ });
1715
+ continue;
1716
+ }
1717
+ modules[filename] = json;
1718
+ }
1719
+ if (options.onAfterImport) await options.onAfterImport({
1720
+ ...ctx,
1721
+ module: modules[filename]
1722
+ });
1723
+ }
1724
+ return modules;
1725
+ }
1726
+ async function importGlob(pattern, options = {}) {
1727
+ return importFiles(await fg(pattern), options);
1728
+ }
1729
+ async function importAll(directory, options = {}) {
1730
+ return importFiles((await fs.promises.readdir(directory, { withFileTypes: true })).filter((dirent) => dirent.isFile()).map((dirent) => path.join(directory, dirent.name)), options);
1731
+ }
1732
+ //#endregion
1733
+ //#region src/server/utils/importOne.ts
1734
+ async function importOne(filenames) {
1735
+ for (const filename of filenames) {
1736
+ const fileUrl = pathToFileURL$1(filename);
1737
+ if (!fs$1.existsSync(filename)) continue;
1738
+ return await import(fileUrl.toString());
1739
+ }
1740
+ return null;
1741
+ }
1742
+ //#endregion
1743
+ export { DatabaseRepository, DatabaseRepositoryInferMixin, EmmitterService, GitBranchRepository, GitCommitRepository, GitGateway, Module as ModuleEntity, PermissionAssignmentRepository, PermissionRepository, PluginIpcClient, PluginIpcHost, PluginRouter, Route as RouteEntity, RouterFileBaseRoutingService, Router as RouterService, ShellService, TokenRepository, basePath, config, container, createHasManyThroughLoader, createLoaderFactory, database, defineLoader, importAll, importFiles, importGlob, importOne, key, loadHasManyThrough, logger, router, shell, tmpPath };