@sidekick-coder/zenith-kit 0.0.8 → 0.0.10

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.
@@ -9,6 +9,74 @@ declare class LoggerService {
9
9
  child(options: any): LoggerService;
10
10
  }
11
11
  //#endregion
12
+ //#region src/shared/services/EmmitterService.d.ts
13
+ interface EmmitterHandler {
14
+ id: string;
15
+ event: string;
16
+ listener: (...args: any[]) => any;
17
+ originalListener?: (...args: any[]) => any;
18
+ }
19
+ interface OnOptions {
20
+ id?: string;
21
+ unique?: boolean;
22
+ }
23
+ interface OnDebounceOptions extends OnOptions {
24
+ debounce?: number;
25
+ }
26
+ interface EmmitterServiceOptions {
27
+ debug?: boolean;
28
+ logger?: LoggerService;
29
+ }
30
+ declare class EmmitterService$1<Events extends Record<string, any> = Record<string, any>> {
31
+ private handlers;
32
+ private debug;
33
+ private logger;
34
+ load(options?: EmmitterServiceOptions): void;
35
+ on<K extends keyof Events>(event: K, listener: (args: Events[K]) => void, options?: OnOptions): EmmitterHandler;
36
+ on(event: string, listener: (args: any) => void, options?: OnOptions): EmmitterHandler;
37
+ once<K extends keyof Events>(event: K, listener: (args: Events[K]) => void, options?: OnOptions): EmmitterHandler;
38
+ once(event: string, listener: (args: any) => void, options?: OnOptions): EmmitterHandler;
39
+ onDebounce<K extends keyof Events>(event: K, listener: (args: Events[K]) => void, options?: OnDebounceOptions): EmmitterHandler;
40
+ onDebounce(event: string, listener: (args: any) => void, options?: OnDebounceOptions): EmmitterHandler;
41
+ onAnyOf<K extends keyof Events>(events: K[], listener: (args: Events[K]) => void, options?: OnOptions): EmmitterHandler[];
42
+ onAnyOf(events: string[], listener: (args: any) => void, options?: OnOptions): EmmitterHandler[];
43
+ off(event: string, listener: Function): void;
44
+ emit<K extends keyof Events>(event: K, args: Events[K]): void;
45
+ emit(event: string, args?: any): void;
46
+ emitAndWait<K extends keyof Events>(event: K, args: Events[K]): Promise<void>;
47
+ emitAndWait(event: string, args?: any): Promise<void>;
48
+ list(): EmmitterHandler[];
49
+ listByEvent(event: string): EmmitterHandler[];
50
+ remove(payload: string | string[]): void;
51
+ clear(): void;
52
+ hasHandlers(): boolean;
53
+ }
54
+ //#endregion
55
+ //#region src/server/contracts/events.d.ts
56
+ interface Events {
57
+ 'user:before-create': {
58
+ user: any;
59
+ };
60
+ 'user:after-create': {
61
+ user: any;
62
+ };
63
+ 'user:before-update': {
64
+ user: any;
65
+ };
66
+ 'user:after-update': {
67
+ user: any;
68
+ };
69
+ 'user:before-delete': {
70
+ user: any;
71
+ };
72
+ 'user:after-delete': {
73
+ user: any;
74
+ };
75
+ }
76
+ //#endregion
77
+ //#region src/server/services/EmmitterService.d.ts
78
+ declare class EmmitterService extends EmmitterService$1<Events> {}
79
+ //#endregion
12
80
  //#region src/server/gateways/GitGateway.d.ts
13
81
  interface GitRepoInfo {
14
82
  directory: string;
@@ -159,4 +227,4 @@ declare class PluginRouter {
159
227
  delete(path: string, handler: RouteHandler): void;
160
228
  }
161
229
  //#endregion
162
- export { GitBranch, GitBranchFetchOptions, GitBranchRepository, GitCommit, GitCommitListOptions, GitCommitRef, GitCommitRepository, GitGateway, GitGatewayOptions, GitRepoInfo, HttpMethod, IpcMessage, PaginatedCommits, PluginIpcClient, PluginIpcHost, PluginRouter, RouteDefinition, RouteHandler, RouteReply, RouteRequest, RouteResponsePayload };
230
+ export { EmmitterService, GitBranch, GitBranchFetchOptions, GitBranchRepository, GitCommit, GitCommitListOptions, GitCommitRef, GitCommitRepository, GitGateway, GitGatewayOptions, GitRepoInfo, HttpMethod, IpcMessage, PaginatedCommits, PluginIpcClient, PluginIpcHost, PluginRouter, RouteDefinition, RouteHandler, RouteReply, RouteRequest, RouteResponsePayload };
@@ -1,9 +1,143 @@
1
+ import { debounce } from "lodash-es";
1
2
  import { exec } from "node:child_process";
2
3
  import { promisify } from "node:util";
3
4
  import { unlink, writeFile } from "node:fs/promises";
4
5
  import { tmpdir } from "node:os";
5
6
  import { join } from "node:path";
6
7
  import { randomUUID } from "node:crypto";
8
+ //#region src/shared/utils/tryCatch.ts
9
+ async function tryCatch(tryer) {
10
+ try {
11
+ return [null, await tryer()];
12
+ } catch (error) {
13
+ return [error, null];
14
+ }
15
+ }
16
+ tryCatch.sync = function(tryer) {
17
+ try {
18
+ return [null, tryer()];
19
+ } catch (error) {
20
+ return [error, null];
21
+ }
22
+ };
23
+ //#endregion
24
+ //#region src/shared/utils/createId.ts
25
+ function uuid() {
26
+ if (typeof crypto !== "undefined" && crypto.randomUUID) return crypto.randomUUID();
27
+ if (typeof self !== "undefined" && self.crypto && self.crypto.randomUUID) return self.crypto.randomUUID();
28
+ if (typeof window !== "undefined" && window.crypto && window.crypto.randomUUID) return window.crypto.randomUUID();
29
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
30
+ const r = Math.random() * 16 | 0;
31
+ return (c === "x" ? r : r & 3 | 8).toString(16);
32
+ });
33
+ }
34
+ function createId(prefix = "") {
35
+ return prefix + uuid();
36
+ }
37
+ //#endregion
38
+ //#region src/shared/services/LoggerService.ts
39
+ var LoggerService = class LoggerService {
40
+ info(message, meta) {}
41
+ debug(message, meta) {}
42
+ warn(message, meta) {}
43
+ error(message, meta) {}
44
+ child(options) {
45
+ return new LoggerService();
46
+ }
47
+ };
48
+ //#endregion
49
+ //#region src/shared/services/EmmitterService.ts
50
+ var EmmitterService$1 = class {
51
+ handlers = [];
52
+ debug;
53
+ logger;
54
+ load(options) {
55
+ this.debug = options?.debug || false;
56
+ this.logger = options?.logger || new LoggerService();
57
+ if (this.debug) this.logger.debug("emmitter loaded with debug mode enabled");
58
+ }
59
+ on(event, listener, options) {
60
+ const id = options?.id || createId();
61
+ if (options?.unique) {
62
+ if (this.handlers.some((h) => h.event === event && h.listener === listener || h.id === id)) return;
63
+ }
64
+ const handler = {
65
+ id,
66
+ event,
67
+ listener
68
+ };
69
+ this.handlers.push(handler);
70
+ if (this.debug) this.logger.debug("handler added", handler);
71
+ return handler;
72
+ }
73
+ once(event, listener, options) {
74
+ const wrapper = (args) => {
75
+ listener(args);
76
+ this.off(event, wrapper);
77
+ };
78
+ return this.on(event, wrapper, options);
79
+ }
80
+ onDebounce(event, listener, options) {
81
+ const debounced = debounce(listener, options?.debounce || 300);
82
+ const handler = this.on(event, debounced, options);
83
+ if (handler) handler.originalListener = listener;
84
+ return handler;
85
+ }
86
+ onAnyOf(events, listener, options) {
87
+ const handlers = [];
88
+ for (const event of events) {
89
+ const handler = this.on(event, listener, options);
90
+ if (handler) handlers.push(handler);
91
+ }
92
+ return handlers;
93
+ }
94
+ off(event, listener) {
95
+ this.handlers = this.handlers.filter((h) => {
96
+ if (h.event === event && (h.listener === listener || h.originalListener === listener)) return false;
97
+ return true;
98
+ });
99
+ if (this.debug) this.logger.debug("handler removed", { event });
100
+ }
101
+ emit(event, args) {
102
+ if (this.debug) this.logger.debug("emitting event", {
103
+ event,
104
+ args
105
+ });
106
+ const handlers = this.handlers.filter((h) => h.event === event);
107
+ for (const handler of handlers) tryCatch.sync(() => handler.listener(args));
108
+ }
109
+ async emitAndWait(event, args) {
110
+ const handlers = this.handlers.filter((h) => h.event === event);
111
+ if (this.debug) this.logger.debug("emitting event", {
112
+ handlers: handlers.length,
113
+ event,
114
+ args
115
+ });
116
+ for await (const handler of handlers) await handler.listener(args);
117
+ }
118
+ list() {
119
+ return this.handlers;
120
+ }
121
+ listByEvent(event) {
122
+ return this.handlers.filter((h) => h.event === event);
123
+ }
124
+ remove(payload) {
125
+ const ids = Array.isArray(payload) ? payload : [payload];
126
+ this.handlers = this.handlers.filter((h) => !ids.includes(h.id));
127
+ if (this.debug) this.logger.debug("handlers removed", { ids });
128
+ }
129
+ clear() {
130
+ this.handlers = [];
131
+ if (this.debug) this.logger.debug("all handlers cleared");
132
+ }
133
+ hasHandlers() {
134
+ return this.handlers.length > 0;
135
+ }
136
+ };
137
+ //#endregion
138
+ //#region src/server/services/EmmitterService.ts
139
+ var EmmitterService = class extends EmmitterService$1 {};
140
+ //#endregion
7
141
  //#region src/server/services/GitBranchRepository.ts
8
142
  var GitBranchRepository = class {
9
143
  constructor(gateway) {
@@ -115,20 +249,6 @@ var GitCommitRepository = class {
115
249
  }
116
250
  };
117
251
  //#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
252
  //#region src/server/services/PluginIpcClient.ts
133
253
  var PluginIpcClient = class {
134
254
  listeners = /* @__PURE__ */ new Map();
@@ -277,17 +397,6 @@ var PluginRouter = class {
277
397
  }
278
398
  };
279
399
  //#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();
288
- }
289
- };
290
- //#endregion
291
400
  //#region src/server/gateways/GitGateway.ts
292
401
  const execAsync = promisify(exec);
293
402
  function escapeShellArgument(value) {
@@ -377,4 +486,4 @@ var GitGateway = class {
377
486
  }
378
487
  };
379
488
  //#endregion
380
- export { GitBranchRepository, GitCommitRepository, GitGateway, PluginIpcClient, PluginIpcHost, PluginRouter };
489
+ export { EmmitterService, GitBranchRepository, GitCommitRepository, GitGateway, PluginIpcClient, PluginIpcHost, PluginRouter };
@@ -1,5 +1,54 @@
1
1
  import * as v from "valibot";
2
2
 
3
+ //#region src/shared/services/ConfigService.d.ts
4
+ interface Entry {
5
+ key: string;
6
+ value: any;
7
+ source: string;
8
+ }
9
+ declare class ConfigService {
10
+ entries: Map<string, Entry>;
11
+ constructor();
12
+ list(): Entry[];
13
+ parseValue(value: any): any;
14
+ loadFromRecord(record: Record<string, any>, source?: string): void;
15
+ loadFromEntries(entries: [string, any][], source?: string): void;
16
+ toRecord(): Record<string, any>;
17
+ has(key: string): boolean;
18
+ get<T = any | undefined>(key: string, defaultValue?: any): T;
19
+ getOne<T = any | undefined>(keys: string[], defaultValue?: any): T;
20
+ set(key: string, value: any, source?: string): void;
21
+ unset(key: string): void;
22
+ clear(): void;
23
+ }
24
+ //#endregion
25
+ //#region src/shared/services/ContainerService.d.ts
26
+ type Constructor$1<T = object> = new (...args: any[]) => T;
27
+ type EntryKey = string | symbol | Constructor$1;
28
+ declare class DIService {
29
+ private entries;
30
+ loadFromRecord(record: Record<string, any>): void;
31
+ toRecord(): Record<string, any>;
32
+ set(payload: EntryKey, value: any): void;
33
+ has(payload: EntryKey): boolean;
34
+ get<T>(payload: EntryKey): T;
35
+ singleton<T>(classConstructor: Constructor$1<T>): T;
36
+ load(entries: Record<any, any>): void;
37
+ proxy<T = unknown>(key: EntryKey): T;
38
+ keys(): EntryKey[];
39
+ }
40
+ //#endregion
41
+ //#region src/shared/services/CookieService.d.ts
42
+ declare class CookieService {
43
+ cookies: Map<string, string>;
44
+ prefix: string;
45
+ constructor(data?: Partial<CookieService>);
46
+ load(cookies: Record<string, string> | Map<string, string>): void;
47
+ get(name: string, defaultValue?: string | null): string | null;
48
+ set(name: string, value: string, options?: any): void;
49
+ toRecord(): Record<string, string>;
50
+ }
51
+ //#endregion
3
52
  //#region src/shared/services/LoggerService.d.ts
4
53
  declare class LoggerService {
5
54
  info(message: string, meta?: any): void;
@@ -10,10 +59,59 @@ declare class LoggerService {
10
59
  }
11
60
  //#endregion
12
61
  //#region src/shared/services/EmmitterService.d.ts
62
+ interface EmmitterHandler {
63
+ id: string;
64
+ event: string;
65
+ listener: (...args: any[]) => any;
66
+ originalListener?: (...args: any[]) => any;
67
+ }
68
+ interface OnOptions {
69
+ id?: string;
70
+ unique?: boolean;
71
+ }
72
+ interface OnDebounceOptions extends OnOptions {
73
+ debounce?: number;
74
+ }
13
75
  interface EmmitterServiceOptions {
14
76
  debug?: boolean;
15
77
  logger?: LoggerService;
16
78
  }
79
+ declare class EmmitterService<Events extends Record<string, any> = Record<string, any>> {
80
+ private handlers;
81
+ private debug;
82
+ private logger;
83
+ load(options?: EmmitterServiceOptions): void;
84
+ on<K extends keyof Events>(event: K, listener: (args: Events[K]) => void, options?: OnOptions): EmmitterHandler;
85
+ on(event: string, listener: (args: any) => void, options?: OnOptions): EmmitterHandler;
86
+ once<K extends keyof Events>(event: K, listener: (args: Events[K]) => void, options?: OnOptions): EmmitterHandler;
87
+ once(event: string, listener: (args: any) => void, options?: OnOptions): EmmitterHandler;
88
+ onDebounce<K extends keyof Events>(event: K, listener: (args: Events[K]) => void, options?: OnDebounceOptions): EmmitterHandler;
89
+ onDebounce(event: string, listener: (args: any) => void, options?: OnDebounceOptions): EmmitterHandler;
90
+ onAnyOf<K extends keyof Events>(events: K[], listener: (args: Events[K]) => void, options?: OnOptions): EmmitterHandler[];
91
+ onAnyOf(events: string[], listener: (args: any) => void, options?: OnOptions): EmmitterHandler[];
92
+ off(event: string, listener: Function): void;
93
+ emit<K extends keyof Events>(event: K, args: Events[K]): void;
94
+ emit(event: string, args?: any): void;
95
+ emitAndWait<K extends keyof Events>(event: K, args: Events[K]): Promise<void>;
96
+ emitAndWait(event: string, args?: any): Promise<void>;
97
+ list(): EmmitterHandler[];
98
+ listByEvent(event: string): EmmitterHandler[];
99
+ remove(payload: string | string[]): void;
100
+ clear(): void;
101
+ hasHandlers(): boolean;
102
+ }
103
+ //#endregion
104
+ //#region src/shared/entities/LifecycleHook.d.ts
105
+ declare class LifecycleHook {
106
+ hook_id: string;
107
+ order?: number;
108
+ subhooks?: LifecycleHook[];
109
+ constructor();
110
+ onRegister(): Promise<void>;
111
+ onLoad(): Promise<void>;
112
+ onBoot(): Promise<void>;
113
+ onShutdown(): Promise<void>;
114
+ }
17
115
  //#endregion
18
116
  //#region src/shared/utils/typing.d.ts
19
117
  type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
@@ -60,6 +158,52 @@ declare function compose<M extends Array<(base: Constructor<any>) => Constructor
60
158
  declare function composeWith<TBase extends Constructor, M extends Array<(base: Constructor) => Constructor<any>>>(baseClass: TBase, ...mixins: M): TBase & UnionToIntersection<ReturnType<M[number]>>;
61
159
  declare function mixin<TBase extends Constructor>(Source: TBase): <TTarget extends Constructor>(Target: TTarget) => TTarget & TBase;
62
160
  //#endregion
161
+ //#region src/shared/services/LifecycleService.d.ts
162
+ interface ListOptions {
163
+ exclude?: (string | Constructor<LifecycleHook> | LifecycleHook)[];
164
+ }
165
+ declare class LifecycleService {
166
+ hooks: Map<string, LifecycleHook>;
167
+ logger: LoggerService;
168
+ debug: boolean;
169
+ constructor(data?: Partial<LifecycleService>);
170
+ private executeHookMethod;
171
+ list(options?: ListOptions): LifecycleHook[];
172
+ add(...payload: (LifecycleHook | Constructor<LifecycleHook>)[]): void;
173
+ register(options?: ListOptions): Promise<void>;
174
+ load(options?: ListOptions): Promise<void>;
175
+ boot(options?: ListOptions): Promise<void>;
176
+ shutdown(options?: ListOptions): Promise<void>;
177
+ clear(): void;
178
+ }
179
+ //#endregion
180
+ //#region src/shared/services/TranslatorService.d.ts
181
+ declare class TranslatorService {
182
+ entries: Map<string, string>;
183
+ locale: string;
184
+ localeLoaders: Map<string, () => Promise<Record<string, string>>>;
185
+ debug: boolean;
186
+ logger: LoggerService;
187
+ cache: Map<string, Record<string, string>>;
188
+ constructor(data?: Partial<TranslatorService>);
189
+ get locales(): string[];
190
+ list(): {
191
+ key: string;
192
+ value: string;
193
+ }[];
194
+ getEntries(locale: string): Promise<Record<string, string>>;
195
+ load(locale: string): Promise<void>;
196
+ t(key: string, args?: any): string;
197
+ date(data: string | number | Date): string;
198
+ datetime(data: string | number | Date): string;
199
+ }
200
+ //#endregion
201
+ //#region src/shared/services/UploadService.d.ts
202
+ declare class UploadService {
203
+ single(name: string): void;
204
+ multiple(name: string): void;
205
+ }
206
+ //#endregion
63
207
  //#region src/shared/services/ValidatorService.d.ts
64
208
  type Valibot = typeof v;
65
209
  type ValibotSchema = v.BaseSchema<unknown, unknown, v.BaseIssue<unknown>>;
@@ -79,6 +223,7 @@ declare class ValidatorService {
79
223
  validateAsync<T extends ValibotSchemaAsync>(payload: any, cb: ValidatorCallbackAsync<T> | T): Promise<v.InferOutput<T>>;
80
224
  isValid<T extends ValibotSchema>(payload: any, cb: ValidatePayload<T>): boolean;
81
225
  }
226
+ declare const validator: ValidatorService;
82
227
  //#endregion
83
228
  //#region src/shared/utils/createId.d.ts
84
229
  declare function createId(prefix?: string): string;
@@ -107,4 +252,4 @@ declare namespace tryCatch {
107
252
  var sync: <T extends Tryer>(tryer: T) => TryCatchResult<T>;
108
253
  }
109
254
  //#endregion
110
- export { AnyClass, Constructor, EmmitterServiceOptions, Mixin, PartialBy, PublicData, UnionToIntersection, Valibot, ValibotSchema, ValibotSchemaAsync, ValidatePayload, ValidateResult, ValidatorCallback, ValidatorCallbackAsync, ValidatorResult, ValidatorService, compose, composeWith, createId, flatten, formatBytes, generateIndexFile, mixin, tryCatch, unflatten };
255
+ export { AnyClass, ConfigService, Constructor, DIService as ContainerService, CookieService, EmmitterService, EmmitterServiceOptions, LifecycleService, LoggerService, Mixin, PartialBy, PublicData, TranslatorService, UnionToIntersection, UploadService, Valibot, ValibotSchema, ValibotSchemaAsync, ValidatePayload, ValidateResult, ValidatorCallback, ValidatorCallbackAsync, ValidatorResult, validator as ValidatorService, compose, composeWith, createId, flatten, formatBytes, generateIndexFile, mixin, tryCatch, unflatten };
@@ -1,8 +1,203 @@
1
- import "lodash-es";
1
+ import { debounce, get, has, set, unset } from "lodash-es";
2
2
  import * as v from "valibot";
3
3
  import fg from "fast-glob";
4
4
  import fs from "fs";
5
5
  import path from "path";
6
+ //#region src/shared/services/ConfigService.ts
7
+ var ConfigService = class {
8
+ entries;
9
+ constructor() {
10
+ this.entries = /* @__PURE__ */ new Map();
11
+ }
12
+ list() {
13
+ return Array.from(this.entries.values());
14
+ }
15
+ parseValue(value) {
16
+ if (typeof value === "string" && value.endsWith(":boolean")) return value.replace(":boolean", "").trim() === "true";
17
+ return value;
18
+ }
19
+ loadFromRecord(record, source = "unknow") {
20
+ for (const [key, value] of Object.entries(record)) this.entries.set(key, {
21
+ key,
22
+ value: this.parseValue(value),
23
+ source
24
+ });
25
+ }
26
+ loadFromEntries(entries, source = "unknow") {
27
+ for (const [key, value] of entries) this.entries.set(key, {
28
+ key,
29
+ value: this.parseValue(value),
30
+ source
31
+ });
32
+ }
33
+ toRecord() {
34
+ const record = {};
35
+ for (const [key, entry] of this.entries.entries()) record[key] = entry.value;
36
+ return record;
37
+ }
38
+ has(key) {
39
+ if (this.entries.get(key)) return true;
40
+ if (!key.includes(".")) return false;
41
+ const primary = key.split(".")[0];
42
+ const primaryEntry = this.entries.get(primary);
43
+ if (!primaryEntry) return this.entries.get(key) ? true : false;
44
+ const value = primaryEntry.value;
45
+ if (typeof value !== "object" || Array.isArray(value)) return false;
46
+ return has(value, key.substring(primary.length + 1));
47
+ }
48
+ get(key, defaultValue) {
49
+ const entry = this.entries.get(key);
50
+ if (entry) return entry.value;
51
+ if (!key.includes(".")) return defaultValue;
52
+ const primary = key.split(".")[0];
53
+ const primaryEntry = this.entries.get(primary);
54
+ if (!primaryEntry) {
55
+ const entry = this.entries.get(key);
56
+ return entry ? entry.value : defaultValue;
57
+ }
58
+ const value = primaryEntry.value;
59
+ if (typeof value !== "object" || Array.isArray(value)) return defaultValue;
60
+ return get(value, key.substring(primary.length + 1), defaultValue);
61
+ }
62
+ getOne(keys, defaultValue) {
63
+ for (const key of keys) if (this.has(key)) return this.get(key);
64
+ return defaultValue;
65
+ }
66
+ set(key, value, source = "runtime") {
67
+ if (!key.includes(".")) {
68
+ this.entries.set(key, {
69
+ key,
70
+ source,
71
+ value
72
+ });
73
+ return;
74
+ }
75
+ const primary = key.split(".")[0];
76
+ let primaryValue = this.get(primary, {});
77
+ if (typeof primaryValue !== "object" || Array.isArray(primaryValue)) primaryValue = {};
78
+ set(primaryValue, key.substring(primary.length + 1), value);
79
+ this.entries.set(primary, {
80
+ key: primary,
81
+ source,
82
+ value: primaryValue
83
+ });
84
+ }
85
+ unset(key) {
86
+ if (!key.includes(".")) {
87
+ this.entries.delete(key);
88
+ return;
89
+ }
90
+ const primary = key.split(".")[0];
91
+ const primaryValue = this.get(primary, {});
92
+ if (!primaryValue) return;
93
+ if (typeof primaryValue !== "object" || Array.isArray(primaryValue)) return;
94
+ unset(primaryValue, key.substring(primary.length + 1));
95
+ this.entries.set(primary, {
96
+ key: primary,
97
+ source: "runtime",
98
+ value: primaryValue
99
+ });
100
+ }
101
+ clear() {
102
+ this.entries.clear();
103
+ }
104
+ };
105
+ //#endregion
106
+ //#region src/shared/services/ContainerService.ts
107
+ var DIService = class {
108
+ entries = /* @__PURE__ */ new Map();
109
+ loadFromRecord(record) {
110
+ Object.entries(record).forEach(([key, value]) => {
111
+ this.set(key, value);
112
+ });
113
+ }
114
+ toRecord() {
115
+ const record = {};
116
+ for (const [key, value] of this.entries.entries()) record[String(key)] = value;
117
+ return record;
118
+ }
119
+ set(payload, value) {
120
+ let key = payload;
121
+ if (typeof payload === "function" || typeof payload === "object") key = payload.name;
122
+ this.entries.set(key, value);
123
+ }
124
+ has(payload) {
125
+ let key = payload;
126
+ if (typeof payload === "function" || typeof payload === "object") key = payload.name;
127
+ return this.entries.has(key);
128
+ }
129
+ get(payload) {
130
+ let key = payload;
131
+ if (typeof payload === "function" || typeof payload === "object") key = payload.name;
132
+ if (!this.has(key)) throw new Error(`entry not found: ${String(key)}`);
133
+ return this.entries.get(key);
134
+ }
135
+ singleton(classConstructor) {
136
+ const key = classConstructor.name;
137
+ const existingInstance = this.entries.get(key);
138
+ if (existingInstance) return existingInstance;
139
+ const newInstance = new classConstructor();
140
+ this.entries.set(key, newInstance);
141
+ return newInstance;
142
+ }
143
+ load(entries) {
144
+ Object.entries(entries).forEach(([key, value]) => {
145
+ this.set(key, value);
146
+ });
147
+ }
148
+ proxy(key) {
149
+ return new Proxy({}, {
150
+ get: (_target, prop) => {
151
+ const entry = this.get(key);
152
+ const value = entry[prop];
153
+ if (typeof value === "function") return value.bind(entry);
154
+ return entry[prop];
155
+ },
156
+ set: (_target, prop, value) => {
157
+ const entry = this.get(key);
158
+ entry[prop] = value;
159
+ return true;
160
+ }
161
+ });
162
+ }
163
+ keys() {
164
+ return Array.from(this.entries.keys());
165
+ }
166
+ };
167
+ //#endregion
168
+ //#region src/shared/services/CookieService.ts
169
+ var CookieService = class {
170
+ cookies;
171
+ prefix;
172
+ constructor(data = {}) {
173
+ this.cookies = data.cookies || /* @__PURE__ */ new Map();
174
+ this.prefix = data.prefix || "";
175
+ }
176
+ load(cookies) {
177
+ if (cookies instanceof Map) {
178
+ for (const [key, value] of cookies.entries()) this.set(key, value);
179
+ return;
180
+ }
181
+ for (const key of Object.keys(cookies)) this.set(key, cookies[key]);
182
+ }
183
+ get(name, defaultValue = null) {
184
+ const fullName = this.prefix + name;
185
+ return this.cookies.get(fullName) || defaultValue;
186
+ }
187
+ set(name, value, options) {
188
+ const fullName = this.prefix + name;
189
+ this.cookies.set(fullName, value);
190
+ }
191
+ toRecord() {
192
+ const result = {};
193
+ for (const [key, value] of this.cookies.entries()) if (key.startsWith(this.prefix)) {
194
+ const unprefixedKey = key.slice(this.prefix.length);
195
+ result[unprefixedKey] = value;
196
+ }
197
+ return result;
198
+ }
199
+ };
200
+ //#endregion
6
201
  //#region src/shared/utils/compose.ts
7
202
  /**
8
203
  * Composes multiple mixins into a single class that can be extended.
@@ -128,6 +323,301 @@ function createId(prefix = "") {
128
323
  return prefix + uuid();
129
324
  }
130
325
  //#endregion
326
+ //#region src/shared/services/LoggerService.ts
327
+ var LoggerService = class LoggerService {
328
+ info(message, meta) {}
329
+ debug(message, meta) {}
330
+ warn(message, meta) {}
331
+ error(message, meta) {}
332
+ child(options) {
333
+ return new LoggerService();
334
+ }
335
+ };
336
+ //#endregion
337
+ //#region src/shared/services/EmmitterService.ts
338
+ var EmmitterService = class {
339
+ handlers = [];
340
+ debug;
341
+ logger;
342
+ load(options) {
343
+ this.debug = options?.debug || false;
344
+ this.logger = options?.logger || new LoggerService();
345
+ if (this.debug) this.logger.debug("emmitter loaded with debug mode enabled");
346
+ }
347
+ on(event, listener, options) {
348
+ const id = options?.id || createId();
349
+ if (options?.unique) {
350
+ if (this.handlers.some((h) => h.event === event && h.listener === listener || h.id === id)) return;
351
+ }
352
+ const handler = {
353
+ id,
354
+ event,
355
+ listener
356
+ };
357
+ this.handlers.push(handler);
358
+ if (this.debug) this.logger.debug("handler added", handler);
359
+ return handler;
360
+ }
361
+ once(event, listener, options) {
362
+ const wrapper = (args) => {
363
+ listener(args);
364
+ this.off(event, wrapper);
365
+ };
366
+ return this.on(event, wrapper, options);
367
+ }
368
+ onDebounce(event, listener, options) {
369
+ const debounced = debounce(listener, options?.debounce || 300);
370
+ const handler = this.on(event, debounced, options);
371
+ if (handler) handler.originalListener = listener;
372
+ return handler;
373
+ }
374
+ onAnyOf(events, listener, options) {
375
+ const handlers = [];
376
+ for (const event of events) {
377
+ const handler = this.on(event, listener, options);
378
+ if (handler) handlers.push(handler);
379
+ }
380
+ return handlers;
381
+ }
382
+ off(event, listener) {
383
+ this.handlers = this.handlers.filter((h) => {
384
+ if (h.event === event && (h.listener === listener || h.originalListener === listener)) return false;
385
+ return true;
386
+ });
387
+ if (this.debug) this.logger.debug("handler removed", { event });
388
+ }
389
+ emit(event, args) {
390
+ if (this.debug) this.logger.debug("emitting event", {
391
+ event,
392
+ args
393
+ });
394
+ const handlers = this.handlers.filter((h) => h.event === event);
395
+ for (const handler of handlers) tryCatch.sync(() => handler.listener(args));
396
+ }
397
+ async emitAndWait(event, args) {
398
+ const handlers = this.handlers.filter((h) => h.event === event);
399
+ if (this.debug) this.logger.debug("emitting event", {
400
+ handlers: handlers.length,
401
+ event,
402
+ args
403
+ });
404
+ for await (const handler of handlers) await handler.listener(args);
405
+ }
406
+ list() {
407
+ return this.handlers;
408
+ }
409
+ listByEvent(event) {
410
+ return this.handlers.filter((h) => h.event === event);
411
+ }
412
+ remove(payload) {
413
+ const ids = Array.isArray(payload) ? payload : [payload];
414
+ this.handlers = this.handlers.filter((h) => !ids.includes(h.id));
415
+ if (this.debug) this.logger.debug("handlers removed", { ids });
416
+ }
417
+ clear() {
418
+ this.handlers = [];
419
+ if (this.debug) this.logger.debug("all handlers cleared");
420
+ }
421
+ hasHandlers() {
422
+ return this.handlers.length > 0;
423
+ }
424
+ };
425
+ //#endregion
426
+ //#region src/shared/services/LifecycleService.ts
427
+ var LifecycleService = class {
428
+ hooks;
429
+ logger;
430
+ debug = false;
431
+ constructor(data = {}) {
432
+ this.debug = data.debug ?? this.debug;
433
+ this.hooks = data.hooks ?? /* @__PURE__ */ new Map();
434
+ this.logger = data.logger ?? new LoggerService();
435
+ }
436
+ async executeHookMethod(hook, method) {
437
+ await hook[method]();
438
+ if (hook.subhooks) for (const subhook of hook.subhooks) await this.executeHookMethod(subhook, method);
439
+ }
440
+ list(options) {
441
+ let hooks = Array.from(this.hooks.values());
442
+ if (options?.exclude) {
443
+ const ids = options.exclude.filter((item) => typeof item === "string");
444
+ const constructors = options.exclude.filter((item) => typeof item === "function");
445
+ const instances = options.exclude.filter((item) => typeof item === "object");
446
+ hooks = hooks.filter((hook) => {
447
+ if (ids.includes(hook.hook_id)) return false;
448
+ if (constructors.find((ctor) => hook instanceof ctor)) return false;
449
+ if (instances.find((inst) => hook === inst)) return false;
450
+ return true;
451
+ });
452
+ }
453
+ hooks.sort((a, b) => {
454
+ return (a.order ?? 0) - (b.order ?? 0);
455
+ });
456
+ return hooks;
457
+ }
458
+ add(...payload) {
459
+ const instances = [];
460
+ for (const item of payload) {
461
+ if (typeof item === "function") {
462
+ instances.push(new item());
463
+ continue;
464
+ }
465
+ instances.push(item);
466
+ }
467
+ for (const hook of instances) {
468
+ this.hooks.set(hook.hook_id, hook);
469
+ if (this.debug) this.logger.debug("add " + hook.hook_id);
470
+ }
471
+ }
472
+ async register(options) {
473
+ for (const hook of this.list(options)) {
474
+ const [error] = await tryCatch(() => this.executeHookMethod(hook, "onRegister"));
475
+ if (error) {
476
+ Object.assign(error, { hookId: hook.hook_id });
477
+ this.logger.error("error in hook register: ", error);
478
+ continue;
479
+ }
480
+ if (this.debug) this.logger.debug("register " + hook.hook_id);
481
+ }
482
+ }
483
+ async load(options) {
484
+ for (const hook of this.list(options)) {
485
+ const [error] = await tryCatch(() => this.executeHookMethod(hook, "onLoad"));
486
+ if (error) {
487
+ Object.assign(error, { hookId: hook.hook_id });
488
+ this.logger.error("error in hook load:", error);
489
+ continue;
490
+ }
491
+ if (this.debug) this.logger.debug("load " + hook.hook_id);
492
+ }
493
+ }
494
+ async boot(options) {
495
+ const hooks = this.list(options);
496
+ for (const hook of hooks) {
497
+ const [error] = await tryCatch(() => this.executeHookMethod(hook, "onBoot"));
498
+ if (error) {
499
+ Object.assign(error, { hookId: hook.hook_id });
500
+ this.logger.error("error in hook boot:", error);
501
+ continue;
502
+ }
503
+ if (this.debug) this.logger.debug("boot " + hook.hook_id);
504
+ }
505
+ }
506
+ async shutdown(options) {
507
+ for (const hook of this.list(options)) {
508
+ const [error] = await tryCatch(() => this.executeHookMethod(hook, "onShutdown"));
509
+ if (error) {
510
+ Object.assign(error, { hookId: hook.hook_id });
511
+ this.logger.error("error in hook shutdown:", error);
512
+ continue;
513
+ }
514
+ if (this.debug) this.logger.debug("shutdown " + hook.hook_id);
515
+ }
516
+ }
517
+ clear() {
518
+ this.hooks.clear();
519
+ }
520
+ };
521
+ //#endregion
522
+ //#region src/shared/services/TranslatorService.ts
523
+ var TranslatorService = class {
524
+ entries;
525
+ locale;
526
+ localeLoaders;
527
+ debug = false;
528
+ logger;
529
+ cache;
530
+ constructor(data = {}) {
531
+ this.entries = data.entries || /* @__PURE__ */ new Map();
532
+ this.locale = data.locale || "en";
533
+ this.debug = data.debug || false;
534
+ this.cache = data.cache || /* @__PURE__ */ new Map();
535
+ this.logger = data.logger || new LoggerService();
536
+ this.localeLoaders = /* @__PURE__ */ new Map();
537
+ if (this.debug) this.logger.debug("initialized in debug mode", { locale: this.locale });
538
+ }
539
+ get locales() {
540
+ return Array.from(this.localeLoaders.keys());
541
+ }
542
+ list() {
543
+ const items = [];
544
+ this.entries.forEach((value, key) => {
545
+ items.push({
546
+ key,
547
+ value
548
+ });
549
+ });
550
+ return items;
551
+ }
552
+ async getEntries(locale) {
553
+ const cache = this.cache.get(locale);
554
+ if (cache && this.debug) this.logger.debug(`load locale "${locale}" from cache`, {
555
+ locale,
556
+ length: Object.keys(cache).length
557
+ });
558
+ if (cache) return cache;
559
+ const loader = this.localeLoaders.get(locale);
560
+ if (!loader) {
561
+ this.logger.warn(`no loader found for locale "${locale}"`);
562
+ return {};
563
+ }
564
+ const entries = await loader();
565
+ this.cache.set(locale, entries);
566
+ if (this.debug) this.logger.debug(`load locale ${locale}`, {
567
+ locale,
568
+ keys: Object.keys(entries).length
569
+ });
570
+ return entries;
571
+ }
572
+ async load(locale) {
573
+ const entries = await this.getEntries(locale);
574
+ this.entries = new Map(Object.entries(entries));
575
+ this.locale = locale;
576
+ }
577
+ t(key, args = {}) {
578
+ if (!this.entries.has(key) && this.debug) this.logger.debug(`missing translation for key "${key}"`, {
579
+ key,
580
+ locale: this.locale
581
+ });
582
+ let translation = this.entries.get(key) || key;
583
+ if (!Object.keys(args).length) return translation;
584
+ Object.entries(args).forEach(([aKey, aValue]) => {
585
+ translation = translation.replace(`:${aKey}`, aValue);
586
+ });
587
+ return translation;
588
+ }
589
+ date(data) {
590
+ return new Date(data).toLocaleDateString(this.locale, {
591
+ year: "numeric",
592
+ month: "2-digit",
593
+ day: "2-digit"
594
+ });
595
+ }
596
+ datetime(data) {
597
+ return new Date(data).toLocaleString(this.locale, {
598
+ year: "numeric",
599
+ month: "2-digit",
600
+ day: "2-digit",
601
+ hour: "2-digit",
602
+ minute: "2-digit"
603
+ });
604
+ }
605
+ };
606
+ //#endregion
607
+ //#region src/shared/services/UploadService.ts
608
+ var UploadService = class {
609
+ single(name) {
610
+ const error = /* @__PURE__ */ new Error("Method not implemented.");
611
+ Object.assign(error, { name });
612
+ throw error;
613
+ }
614
+ multiple(name) {
615
+ const error = /* @__PURE__ */ new Error("Method not implemented.");
616
+ Object.assign(error, { name });
617
+ throw error;
618
+ }
619
+ };
620
+ //#endregion
131
621
  //#region src/shared/exceptions/BaseException.ts
132
622
  var BaseException = class BaseException extends Error {
133
623
  statusCode = 500;
@@ -185,7 +675,7 @@ var ValidatorService = class {
185
675
  return success;
186
676
  }
187
677
  };
188
- new ValidatorService();
678
+ const validator = new ValidatorService();
189
679
  //#endregion
190
680
  //#region src/shared/utils/generateIndexFile.ts
191
681
  function generateIndexFile(options) {
@@ -196,11 +686,13 @@ function generateIndexFile(options) {
196
686
  const files = fg.sync(`${folder}/**/*.ts`, { ignore: ["**/index.ts"] });
197
687
  for (const file of files) {
198
688
  const filePath = path.relative(path.dirname(filename), file);
689
+ const hasDefaultExport = fs.readFileSync(file, "utf-8").includes("export default") && !filePath.includes("generateIndexFile.ts");
199
690
  content += `export * from './${filePath}'\n`;
691
+ if (hasDefaultExport) content += `export { default as ${path.basename(file, ".ts")} } from './${filePath}'\n`;
200
692
  }
201
693
  }
202
694
  content = content.trim();
203
695
  fs.writeFileSync(filename, content);
204
696
  }
205
697
  //#endregion
206
- export { ValidatorService, compose, composeWith, createId, flatten, formatBytes, generateIndexFile, mixin, tryCatch, unflatten };
698
+ export { ConfigService, DIService as ContainerService, CookieService, EmmitterService, LifecycleService, LoggerService, TranslatorService, UploadService, validator as ValidatorService, compose, composeWith, createId, flatten, formatBytes, generateIndexFile, mixin, tryCatch, unflatten };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sidekick-coder/zenith-kit",
3
- "version": "0.0.8",
3
+ "version": "0.0.10",
4
4
  "license": "MIT",
5
5
  "description": "A collection of utilities and tools for building language servers and related applications.",
6
6
  "keywords": [],