@similie/hyphen-command-server-types 1.0.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.
Files changed (60) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1 -0
  4. package/dist/index.d.ts +5 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +5 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/models/base-model.d.ts +13 -0
  9. package/dist/models/base-model.d.ts.map +1 -0
  10. package/dist/models/base-model.js +2 -0
  11. package/dist/models/base-model.js.map +1 -0
  12. package/dist/models/index.d.ts +2 -0
  13. package/dist/models/index.d.ts.map +1 -0
  14. package/dist/models/index.js +2 -0
  15. package/dist/models/index.js.map +1 -0
  16. package/dist/modules/index.d.ts +3 -0
  17. package/dist/modules/index.d.ts.map +1 -0
  18. package/dist/modules/index.js +3 -0
  19. package/dist/modules/index.js.map +1 -0
  20. package/dist/modules/loader.d.ts +4 -0
  21. package/dist/modules/loader.d.ts.map +1 -0
  22. package/dist/modules/loader.js +53 -0
  23. package/dist/modules/loader.js.map +1 -0
  24. package/dist/modules/types.d.ts +29 -0
  25. package/dist/modules/types.d.ts.map +1 -0
  26. package/dist/modules/types.js +2 -0
  27. package/dist/modules/types.js.map +1 -0
  28. package/dist/services/index.d.ts +3 -0
  29. package/dist/services/index.d.ts.map +1 -0
  30. package/dist/services/index.js +3 -0
  31. package/dist/services/index.js.map +1 -0
  32. package/dist/services/leader-lock.d.ts +31 -0
  33. package/dist/services/leader-lock.d.ts.map +1 -0
  34. package/dist/services/leader-lock.js +103 -0
  35. package/dist/services/leader-lock.js.map +1 -0
  36. package/dist/services/redis.d.ts +27 -0
  37. package/dist/services/redis.d.ts.map +1 -0
  38. package/dist/services/redis.js +62 -0
  39. package/dist/services/redis.js.map +1 -0
  40. package/dist/tools/index.d.ts +2 -0
  41. package/dist/tools/index.d.ts.map +1 -0
  42. package/dist/tools/index.js +2 -0
  43. package/dist/tools/index.js.map +1 -0
  44. package/dist/tools/utils.d.ts +44 -0
  45. package/dist/tools/utils.d.ts.map +1 -0
  46. package/dist/tools/utils.js +283 -0
  47. package/dist/tools/utils.js.map +1 -0
  48. package/package.json +34 -0
  49. package/src/index.ts +4 -0
  50. package/src/models/base-model.ts +13 -0
  51. package/src/models/index.ts +1 -0
  52. package/src/modules/index.ts +2 -0
  53. package/src/modules/loader.ts +67 -0
  54. package/src/modules/types.ts +40 -0
  55. package/src/services/index.ts +2 -0
  56. package/src/services/leader-lock.ts +113 -0
  57. package/src/services/redis.ts +69 -0
  58. package/src/tools/index.ts +1 -0
  59. package/src/tools/utils.ts +349 -0
  60. package/tsconfig.json +46 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
+
5
+ ### 1.0.1 (2025-12-27)
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Similie
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # hyphen-command-center-sdk
@@ -0,0 +1,5 @@
1
+ export * from "./models";
2
+ export * from "./tools";
3
+ export * from "./services";
4
+ export * from "./modules";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from "./models";
2
+ export * from "./tools";
3
+ export * from "./services";
4
+ export * from "./modules";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type UUID as _UUID } from "@similie/ellipsies";
2
+ export type UUID = _UUID;
3
+ export interface BaseModel {
4
+ id: number;
5
+ createdAt: Date;
6
+ updatedAt: Date;
7
+ }
8
+ export interface BaseUIDModel {
9
+ uid: UUID;
10
+ createdAt: Date;
11
+ updatedAt: Date;
12
+ }
13
+ //# sourceMappingURL=base-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-model.d.ts","sourceRoot":"","sources":["../../src/models/base-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,IAAI,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACxD,MAAM,MAAM,IAAI,GAAG,KAAK,CAAC;AACzB,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,IAAI,CAAC;IACV,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB"}
@@ -0,0 +1,2 @@
1
+ import {} from "@similie/ellipsies";
2
+ //# sourceMappingURL=base-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-model.js","sourceRoot":"","sources":["../../src/models/base-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from "./base-model";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from "./base-model";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/models/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from "./types";
2
+ export * from "./loader";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/modules/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from "./types";
2
+ export * from "./loader";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/modules/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { ModuleContext, LoadedModule } from "./types";
2
+ export declare function loadModulesFromEnv(ctx: ModuleContext): Promise<LoadedModule[]>;
3
+ export declare function shutdownModules(ctx: ModuleContext, loaded: LoadedModule[]): Promise<void>;
4
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/modules/loader.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgB,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEzE,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,aAAa,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CA6CzB;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,YAAY,EAAE,iBAYvB"}
@@ -0,0 +1,53 @@
1
+ export async function loadModulesFromEnv(ctx) {
2
+ const raw = process.env.HYPHEN_MODULES?.trim();
3
+ if (!raw)
4
+ return [];
5
+ const specList = raw
6
+ .split(",")
7
+ .map((s) => s.trim())
8
+ .filter(Boolean);
9
+ const loaded = [];
10
+ for (const spec of specList) {
11
+ // spec can be:
12
+ // - "hyphen-rtsp-module"
13
+ // - "@similie/hyphen-rtsp-module"
14
+ // - "file:./dist/my-module.js" (dev)
15
+ try {
16
+ const imported = await import(spec);
17
+ const candidate = imported.default ?? imported.module ?? imported;
18
+ if (!candidate ||
19
+ typeof candidate.init !== "function" ||
20
+ !candidate.name) {
21
+ ctx.log(`[modules] invalid module export: ${spec}`, { spec });
22
+ continue;
23
+ }
24
+ ctx.log(`[modules] init ${candidate.name}`, {
25
+ spec,
26
+ version: candidate.version,
27
+ });
28
+ const res = await candidate.init(ctx);
29
+ loaded.push({ mod: candidate, res });
30
+ ctx.log(`[modules] ready ${candidate.name}`, { spec });
31
+ }
32
+ catch (e) {
33
+ ctx.log(`[modules] failed to load: ${spec}`, {
34
+ error: e?.message ?? String(e),
35
+ });
36
+ }
37
+ }
38
+ return loaded;
39
+ }
40
+ export async function shutdownModules(ctx, loaded) {
41
+ for (const { mod, res } of loaded) {
42
+ try {
43
+ res && (await res?.shutdown?.());
44
+ ctx.log(`[modules] shutdown ${mod.name}`);
45
+ }
46
+ catch (e) {
47
+ ctx.log(`[modules] shutdown failed ${mod.name}`, {
48
+ error: e?.message ?? String(e),
49
+ });
50
+ }
51
+ }
52
+ }
53
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/modules/loader.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,GAAkB;IAElB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC;IAC/C,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IAEpB,MAAM,QAAQ,GAAG,GAAG;SACjB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnB,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,eAAe;QACf,yBAAyB;QACzB,kCAAkC;QAClC,qCAAqC;QACrC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;YACpC,MAAM,SAAS,GACb,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC;YAElD,IACE,CAAC,SAAS;gBACV,OAAO,SAAS,CAAC,IAAI,KAAK,UAAU;gBACpC,CAAC,SAAS,CAAC,IAAI,EACf,CAAC;gBACD,GAAG,CAAC,GAAG,CAAC,oCAAoC,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC9D,SAAS;YACX,CAAC;YAED,GAAG,CAAC,GAAG,CAAC,kBAAkB,SAAS,CAAC,IAAI,EAAE,EAAE;gBAC1C,IAAI;gBACJ,OAAO,EAAE,SAAS,CAAC,OAAO;aAC3B,CAAC,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACtC,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC;YACrC,GAAG,CAAC,GAAG,CAAC,mBAAmB,SAAS,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,GAAG,CAAC,GAAG,CAAC,6BAA6B,IAAI,EAAE,EAAE;gBAC3C,KAAK,EAAE,CAAC,EAAE,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC;aAC/B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,GAAkB,EAClB,MAAsB;IAEtB,KAAK,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,MAAM,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,GAAG,IAAI,CAAC,MAAM,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;YACjC,GAAG,CAAC,GAAG,CAAC,sBAAsB,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,GAAG,CAAC,GAAG,CAAC,6BAA6B,GAAG,CAAC,IAAI,EAAE,EAAE;gBAC/C,KAAK,EAAE,CAAC,EAAE,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC;aAC/B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,29 @@
1
+ import type { RedisCache, LeaderElector } from "../services";
2
+ import type { Ellipsies } from "@similie/ellipsies";
3
+ export type EllipsiesInstance = Ellipsies;
4
+ export type CommandCenterSystemIdentity = {
5
+ name: string;
6
+ identity: string;
7
+ host: string;
8
+ port: number;
9
+ };
10
+ export type ModuleContext = {
11
+ ellipsies: EllipsiesInstance;
12
+ redis: typeof RedisCache;
13
+ leader: LeaderElector;
14
+ identity?: CommandCenterSystemIdentity;
15
+ log: (msg: string, extra?: Record<string, any>) => void;
16
+ };
17
+ export type ModuleInitResult = {
18
+ shutdown?: () => Promise<void> | void;
19
+ };
20
+ export interface HyphenModule {
21
+ name: string;
22
+ version?: string;
23
+ init(ctx: ModuleContext): Promise<ModuleInitResult | void> | (ModuleInitResult | void);
24
+ }
25
+ export type LoadedModule = {
26
+ mod: HyphenModule;
27
+ res?: ModuleInitResult | void;
28
+ };
29
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/modules/types.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,MAAM,iBAAiB,GAAG,SAAS,CAAC;AAE1C,MAAM,MAAM,2BAA2B,GAAG;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,EAAE,iBAAiB,CAAC;IAC7B,KAAK,EAAE,OAAO,UAAU,CAAC;IACzB,MAAM,EAAE,aAAa,CAAC;IACtB,QAAQ,CAAC,EAAE,2BAA2B,CAAC;IACvC,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,IAAI,CAAC;CACzD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAE7B,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACvC,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,IAAI,CACF,GAAG,EAAE,aAAa,GACjB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC;CACjE;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,YAAY,CAAC;IAClB,GAAG,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC/B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/modules/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export * from "./leader-lock";
2
+ export * from "./redis";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from "./leader-lock";
2
+ export * from "./redis";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { EventEmitter } from "events";
2
+ export type LeaderEvents = {
3
+ elected: () => void;
4
+ revoked: () => void;
5
+ error: (err: Error) => void;
6
+ };
7
+ export declare class LeaderElector extends EventEmitter {
8
+ private static instance;
9
+ private redlock;
10
+ private redis;
11
+ private renewTimer?;
12
+ private acquireTimer?;
13
+ private lock?;
14
+ private readonly lockKey;
15
+ private readonly ttlMs;
16
+ private readonly renewEveryMs;
17
+ private readonly retryDelayMs;
18
+ private readonly instanceId;
19
+ private constructor();
20
+ static get(): LeaderElector;
21
+ init(redisUrl: string): void;
22
+ /** Pure check: true only if we *currently* hold a live lock. */
23
+ amLeader(): boolean;
24
+ /** Stop loops and release if we are leader. */
25
+ shutdown(): Promise<void>;
26
+ private startAcquireLoop;
27
+ private startRenewLoop;
28
+ private safeRevoke;
29
+ private safeRelease;
30
+ }
31
+ //# sourceMappingURL=leader-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leader-lock.d.ts","sourceRoot":"","sources":["../../src/services/leader-lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAKtC,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;CAC7B,CAAC;AAEF,qBAAa,aAAc,SAAQ,YAAY;IAC7C,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAgB;IACvC,OAAO,CAAC,OAAO,CAAW;IAC1B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,UAAU,CAAC,CAAiB;IACpC,OAAO,CAAC,YAAY,CAAC,CAAiB;IACtC,OAAO,CAAC,IAAI,CAAC,CAAmB;IAEhC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAE3C,OAAO;IAIP,MAAM,CAAC,GAAG,IAAI,aAAa;IAK3B,IAAI,CAAC,QAAQ,EAAE,MAAM;IAYrB,gEAAgE;IAChE,QAAQ,IAAI,OAAO;IAInB,+CAA+C;IACzC,QAAQ;IASd,OAAO,CAAC,gBAAgB;IAqBxB,OAAO,CAAC,cAAc;YAcR,UAAU;YAMV,WAAW;CAU1B"}
@@ -0,0 +1,103 @@
1
+ import { EventEmitter } from "events";
2
+ import { Redis } from "ioredis";
3
+ import Redlock, { Lock } from "redlock";
4
+ import { randomUUID } from "crypto";
5
+ export class LeaderElector extends EventEmitter {
6
+ static instance;
7
+ redlock;
8
+ redis;
9
+ renewTimer;
10
+ acquireTimer;
11
+ lock;
12
+ lockKey = "mqtt:leader:lock";
13
+ ttlMs = 10000; // lock TTL
14
+ renewEveryMs = 5000; // extend interval (< TTL)
15
+ retryDelayMs = 1500; // backoff when not leader
16
+ instanceId = randomUUID(); // for logging/diagnostics
17
+ constructor() {
18
+ super();
19
+ }
20
+ static get() {
21
+ if (!this.instance)
22
+ this.instance = new LeaderElector();
23
+ return this.instance;
24
+ }
25
+ init(redisUrl) {
26
+ this.redis = new Redis(redisUrl);
27
+ this.redlock = new Redlock([this.redis], {
28
+ // Redlock will keep retrying for us when we explicitly request it,
29
+ // but we’ll manage our own retry loop here.
30
+ driftFactor: 0.01,
31
+ retryCount: 0,
32
+ retryDelay: 0,
33
+ });
34
+ this.startAcquireLoop();
35
+ }
36
+ /** Pure check: true only if we *currently* hold a live lock. */
37
+ amLeader() {
38
+ return !!this.lock;
39
+ }
40
+ /** Stop loops and release if we are leader. */
41
+ async shutdown() {
42
+ clearTimeout(this.acquireTimer);
43
+ clearInterval(this.renewTimer);
44
+ await this.safeRelease();
45
+ await this.redis?.quit();
46
+ }
47
+ // -------- internal --------
48
+ startAcquireLoop() {
49
+ const tryAcquire = async () => {
50
+ if (this.lock)
51
+ return; // already leader
52
+ try {
53
+ // Acquire without retries; we run our own loop.
54
+ const lock = await this.redlock.acquire([this.lockKey], this.ttlMs);
55
+ this.lock = lock;
56
+ this.emit("elected");
57
+ this.startRenewLoop();
58
+ }
59
+ catch {
60
+ // Not acquired (someone else is leader). Back off a bit (with jitter).
61
+ }
62
+ finally {
63
+ const jitter = Math.floor(Math.random() * 500);
64
+ this.acquireTimer = setTimeout(tryAcquire, this.retryDelayMs + jitter);
65
+ }
66
+ };
67
+ tryAcquire().catch((err) => this.emit("error", err));
68
+ }
69
+ startRenewLoop() {
70
+ clearInterval(this.renewTimer);
71
+ this.renewTimer = setInterval(async () => {
72
+ if (!this.lock)
73
+ return;
74
+ try {
75
+ this.lock = await this.lock.extend(this.ttlMs);
76
+ }
77
+ catch (err) {
78
+ // Couldn’t extend: we lost leadership (expired or Redis issue)
79
+ await this.safeRevoke();
80
+ // acquisition loop is already running, it’ll try to reacquire
81
+ }
82
+ }, this.renewEveryMs);
83
+ }
84
+ async safeRevoke() {
85
+ clearInterval(this.renewTimer);
86
+ this.lock = undefined;
87
+ this.emit("revoked");
88
+ }
89
+ async safeRelease() {
90
+ if (!this.lock)
91
+ return;
92
+ try {
93
+ await this.lock.release();
94
+ }
95
+ catch {
96
+ // If already expired or released, ignore.
97
+ }
98
+ finally {
99
+ await this.safeRevoke();
100
+ }
101
+ }
102
+ }
103
+ //# sourceMappingURL=leader-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leader-lock.js","sourceRoot":"","sources":["../../src/services/leader-lock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ export declare class RedisCache {
2
+ private static client;
3
+ private static DEFAULT_EXPIRATION_SECONDS;
4
+ /**
5
+ * Initializes the Redis client. Call this once on server startup.
6
+ */
7
+ static init(): Promise<void>;
8
+ /**
9
+ * Caches an object under a specified key.
10
+ * @param key The cache key.
11
+ * @param value The object to cache.
12
+ * @param expirationSeconds Optional expiration time in seconds (defaults to 15 minutes).
13
+ */
14
+ static set(key: string, value: any, expirationSeconds?: number): Promise<void>;
15
+ /**
16
+ * Retrieves a cached object by its key.
17
+ * @param key The cache key.
18
+ * @returns The cached object, or null if not found.
19
+ */
20
+ static get<T>(key: string): Promise<T | null>;
21
+ /**
22
+ * Deletes a cache entry.
23
+ * @param key The cache key.
24
+ */
25
+ static del(key: string): Promise<void>;
26
+ }
27
+ //# sourceMappingURL=redis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/services/redis.ts"],"names":[],"mappings":"AAKA,qBAAa,UAAU;IAErB,OAAO,CAAC,MAAM,CAAC,MAAM,CAA2C;IAChE,OAAO,CAAC,MAAM,CAAC,0BAA0B,CAAO;IAEhD;;OAEG;WACiB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAYzC;;;;;OAKG;WACiB,GAAG,CACrB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,GAAG,EACV,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,IAAI,CAAC;IAMhB;;;;OAIG;WACiB,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;IAe1D;;;OAGG;WACiB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGpD"}
@@ -0,0 +1,62 @@
1
+ // src/services/redis.ts
2
+ import { createClient } from "redis";
3
+ const getRedisConfig = () => {
4
+ return process.env.REDIS_CONFIG_URL || "redis://localhost:6379/1";
5
+ };
6
+ export class RedisCache {
7
+ // Create a Redis client instance.
8
+ static client = createClient({ url: getRedisConfig() });
9
+ static DEFAULT_EXPIRATION_SECONDS = 900; // 15 minutes
10
+ /**
11
+ * Initializes the Redis client. Call this once on server startup.
12
+ */
13
+ static async init() {
14
+ if (this.client.isOpen) {
15
+ return;
16
+ }
17
+ try {
18
+ await this.client.connect();
19
+ console.log("Connected to Redis");
20
+ }
21
+ catch (err) {
22
+ console.error("Error connecting to Redis:", err);
23
+ }
24
+ }
25
+ /**
26
+ * Caches an object under a specified key.
27
+ * @param key The cache key.
28
+ * @param value The object to cache.
29
+ * @param expirationSeconds Optional expiration time in seconds (defaults to 15 minutes).
30
+ */
31
+ static async set(key, value, expirationSeconds) {
32
+ const exp = expirationSeconds || this.DEFAULT_EXPIRATION_SECONDS;
33
+ const stringValue = JSON.stringify(value);
34
+ await this.client.set(key, stringValue, { EX: exp });
35
+ }
36
+ /**
37
+ * Retrieves a cached object by its key.
38
+ * @param key The cache key.
39
+ * @returns The cached object, or null if not found.
40
+ */
41
+ static async get(key) {
42
+ const data = await this.client.get(key);
43
+ if (data) {
44
+ try {
45
+ return JSON.parse(typeof data === "string" ? data : JSON.stringify(data));
46
+ }
47
+ catch (err) {
48
+ console.error("Error parsing cached data:", err);
49
+ return data;
50
+ }
51
+ }
52
+ return null;
53
+ }
54
+ /**
55
+ * Deletes a cache entry.
56
+ * @param key The cache key.
57
+ */
58
+ static async del(key) {
59
+ await this.client.del(key);
60
+ }
61
+ }
62
+ //# sourceMappingURL=redis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/services/redis.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AACrC,MAAM,cAAc,GAAG,GAAG,EAAE;IAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,0BAA0B,CAAC;AACpE,CAAC,CAAC;AACF,MAAM,OAAO,UAAU;IACrB,kCAAkC;IAC1B,MAAM,CAAC,MAAM,GAAG,YAAY,CAAC,EAAE,GAAG,EAAE,cAAc,EAAE,EAAE,CAAC,CAAC;IACxD,MAAM,CAAC,0BAA0B,GAAG,GAAG,CAAC,CAAC,aAAa;IAE9D;;OAEG;IACI,MAAM,CAAC,KAAK,CAAC,IAAI;QACtB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACvB,OAAO;QACT,CAAC;QACD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,GAAG,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACI,MAAM,CAAC,KAAK,CAAC,GAAG,CACrB,GAAW,EACX,KAAU,EACV,iBAA0B;QAE1B,MAAM,GAAG,GAAG,iBAAiB,IAAI,IAAI,CAAC,0BAA0B,CAAC;QACjE,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;IACvD,CAAC;IAED;;;;OAIG;IACI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAI,GAAW;QACpC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC;gBACH,OAAO,IAAI,CAAC,KAAK,CACf,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CACvD,CAAC;YACJ,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,GAAG,CAAC,CAAC;gBACjD,OAAO,IAA2B,CAAC;YACrC,CAAC;QACH,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAW;QACjC,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from "./utils";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from "./utils";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC"}
@@ -0,0 +1,44 @@
1
+ import type { UUID } from "../models";
2
+ export type MQTTFunctionalResponse = {
3
+ value: any;
4
+ key: string;
5
+ id: string;
6
+ request: string;
7
+ };
8
+ export declare const mqttMessageIdentity: (payload: Buffer<ArrayBufferLike>) => string;
9
+ export declare const emailRegex: RegExp;
10
+ export declare const wrapModelSet: <T>(models: T[], wrapOn?: keyof T) => (key: keyof T) => T | null | undefined;
11
+ export declare const URL_HOST_PATTERN_FOR_INPUT: RegExp;
12
+ export declare const DOMAIN_PATTERN: RegExp;
13
+ export declare function isNumeric(str: string): boolean;
14
+ export declare const generateUniqueUUID: () => UUID;
15
+ export declare function formatDate(date: Date | string, locale?: string, options?: Intl.DateTimeFormatOptions): string;
16
+ export declare function formatMoney(value: number, currencySymbol?: string): string;
17
+ export declare const siteMoneyFormatConfig: (value: number, currencyDivisor?: number, currencySymbol?: string) => string;
18
+ export declare const errorMessageWithCode: (message: string) => {
19
+ code: number;
20
+ message: string | undefined;
21
+ };
22
+ export declare const isDomainPattern: (str: string) => boolean;
23
+ export declare const extractFormToJson: <T extends Record<string, any> = {}>(form: FormData) => T;
24
+ export declare const delay: (timeout?: number) => Promise<unknown>;
25
+ export declare const generateRandomInt: (min: number, max: number) => number;
26
+ export declare const generateUniqueId: (numBytes?: number) => string;
27
+ export declare const isUUID: (value: string | UUID) => boolean;
28
+ export declare const validateEmail: (email: string) => boolean;
29
+ export declare const generateRandomPassword: (length: number) => string;
30
+ export declare const fileToUint8Array: (file: File) => Promise<Uint8Array>;
31
+ export declare function sha256String(values: string): string;
32
+ export declare const ParseSocketMessage: <T>(message: string) => T;
33
+ export declare const stripStateFromObject: (obj: any) => any;
34
+ export declare const buildShaValueString: (data: any) => string;
35
+ export declare const hashFileContents: (file: File) => Promise<string>;
36
+ export declare const fileListToFile: (file: File) => Promise<File>;
37
+ export declare const formatMessageServerMessage: (message: string) => any;
38
+ export declare const isOlderThanInDays: (created_at: Date, days: number) => boolean;
39
+ export declare const removeDoubleSpaces: (text: string) => string;
40
+ export declare const removeContentSpace: (text: string) => string;
41
+ export declare const removeHtmlEntities: (text: string) => string;
42
+ export declare function getLast30DaysLabels(locale?: string): string[];
43
+ export declare function humanizeNumber(value: number, precision?: number): string;
44
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/tools/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGtC,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,GAAG,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,MAAM,CAAC,eAAe,CAAC,KAC/B,MAQF,CAAC;AAEF,eAAO,MAAM,UAAU,QAAqD,CAAC;AAE7E,eAAO,MAAM,YAAY,GAAI,CAAC,EAC5B,QAAQ,CAAC,EAAE,EACX,SAAQ,MAAM,CAAoB,MAK1B,KAAK,MAAM,CAAC,yBAMrB,CAAC;AAEF,eAAO,MAAM,0BAA0B,QACiI,CAAC;AACzK,eAAO,MAAM,cAAc,QACyC,CAAC;AACrE,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAK9C;AAED,eAAO,MAAM,kBAAkB,QACd,IAChB,CAAC;AAEF,wBAAgB,UAAU,CACxB,IAAI,EAAE,IAAI,GAAG,MAAM,EACnB,MAAM,SAAU,EAChB,OAAO,GAAE,IAAI,CAAC,qBAIb,GACA,MAAM,CAKR;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,GAAE,MAAY,UAQtE;AAED,eAAO,MAAM,qBAAqB,GAChC,OAAO,MAAM,EACb,kBAAiB,MAAY,EAC7B,iBAAgB,MAAY,KAC3B,MAOF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,SAAS,MAAM;;;CAcnD,CAAC;AAEF,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,KAAG,OAG7C,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,EAClE,MAAM,QAAQ,KAWC,CAChB,CAAC;AAEF,eAAO,MAAM,KAAK,GAAI,gBAAc,qBACoB,CAAC;AAEzD,eAAO,MAAM,iBAAiB,GAAI,KAAK,MAAM,EAAE,KAAK,MAAM,KAAG,MAE5D,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,WAAU,MAAW,KAAG,MAIxD,CAAC;AAEF,eAAO,MAAM,MAAM,GAAI,OAAO,MAAM,GAAG,IAAI,YAI1C,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,OAG7C,CAAC;AAEF,eAAO,MAAM,sBAAsB,GAAI,QAAQ,MAAM,KAAG,MAWvD,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,MAAM,IAAI,KAAG,OAAO,CAAC,UAAU,CAa/D,CAAC;AAqCF,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,UAM1C;AAED,eAAO,MAAM,kBAAkB,GAAI,CAAC,EAAE,SAAS,MAAM,KAAG,CAMvD,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,KAAK,GAAG,QAM5C,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,MAAM,GAAG,WAE5C,CAAC;AAOF,eAAO,MAAM,gBAAgB,GAAU,MAAM,IAAI,KAAG,OAAO,CAAC,MAAM,CAGjE,CAAC;AAEF,eAAO,MAAM,cAAc,GAAU,MAAM,IAAI,KAAG,OAAO,CAAC,IAAI,CAM7D,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAI,SAAS,MAAM,QAkBzD,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,YAAY,IAAI,EAAE,MAAM,MAAM,KAAG,OAUlE,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,WAE9C,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,WAE9C,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,MAAM,MAAM,WAE9C,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,MAAM,SAAU,GAAG,MAAM,EAAE,CAiB9D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,SAAI,GAAG,MAAM,CAwBnE"}