@sentzunhat/zacatl 0.0.25 → 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "main": "build/index.js",
5
5
  "module": "build/index.js",
6
6
  "types": "build/index.d.ts",
7
- "version": "0.0.25",
7
+ "version": "0.0.26",
8
8
  "packageManager": "npm@10.9.0",
9
9
  "exports": {
10
10
  ".": {
@@ -1,6 +1,17 @@
1
1
  import "reflect-metadata";
2
2
  import { container as tsyringeContainer } from "tsyringe";
3
3
  import type { DependencyContainer, InjectionToken } from "tsyringe";
4
+ import type { Constructor } from "../service/architecture/architecture";
5
+
6
+ /**
7
+ * Track registered classes to avoid requiring decorator metadata
8
+ */
9
+ const registeredClasses = new Set<Constructor>();
10
+
11
+ /**
12
+ * Cache for singleton instances
13
+ */
14
+ const singletonInstances = new Map<Constructor, object>();
4
15
 
5
16
  /**
6
17
  * Standalone DI container decoupled from microservice architecture.
@@ -101,13 +112,25 @@ export const resolveDependency = <T>(token: InjectionToken<T>): T => {
101
112
  * registerWithDependencies(MachineService, [MachineRepository]);
102
113
  * ```
103
114
  */
104
- export const registerWithDependencies = <T>(
105
- serviceClass: new (...args: unknown[]) => T,
106
- dependencies: Array<new (...args: unknown[]) => unknown> = [],
115
+ export const registerWithDependencies = <T extends object>(
116
+ serviceClass: Constructor<T>,
117
+ dependencies: Constructor[] = [],
107
118
  ): void => {
119
+ // Track this class as registered
120
+ registeredClasses.add(serviceClass);
121
+
108
122
  tsyringeContainer.register(serviceClass, {
109
- useFactory: (c: DependencyContainer) => {
110
- const resolvedDeps = dependencies.map((dep) => c.resolve(dep));
123
+ useFactory: () => {
124
+ const resolvedDeps = dependencies.map((dep) => {
125
+ // Check if dependency was registered
126
+ if (!registeredClasses.has(dep)) {
127
+ throw new Error(
128
+ `Dependency ${dep.name} not registered. Register it before ${serviceClass.name}.`,
129
+ );
130
+ }
131
+ // Resolve from container (works because we registered it)
132
+ return tsyringeContainer.resolve(dep);
133
+ });
111
134
  return new serviceClass(...resolvedDeps);
112
135
  },
113
136
  } as never);
@@ -128,14 +151,37 @@ export const registerWithDependencies = <T>(
128
151
  * registerSingletonWithDependencies(MachineService, [MachineRepository]);
129
152
  * ```
130
153
  */
131
- export const registerSingletonWithDependencies = <T>(
132
- serviceClass: new (...args: unknown[]) => T,
133
- dependencies: Array<new (...args: unknown[]) => unknown> = [],
154
+ export const registerSingletonWithDependencies = <T extends object>(
155
+ serviceClass: Constructor<T>,
156
+ dependencies: Constructor[] = [],
134
157
  ): void => {
135
- tsyringeContainer.registerSingleton(serviceClass, {
136
- useFactory: (c: DependencyContainer) => {
137
- const resolvedDeps = dependencies.map((dep) => c.resolve(dep));
138
- return new serviceClass(...resolvedDeps);
158
+ // Track this class as registered
159
+ registeredClasses.add(serviceClass);
160
+
161
+ // Use register() with manual singleton pattern (lifecycle can't be used with factories)
162
+ tsyringeContainer.register(serviceClass, {
163
+ useFactory: () => {
164
+ // Check if we already have a singleton instance
165
+ if (singletonInstances.has(serviceClass)) {
166
+ return singletonInstances.get(serviceClass) as T;
167
+ }
168
+
169
+ // Create new instance
170
+ const resolvedDeps = dependencies.map((dep) => {
171
+ // Check if dependency was registered
172
+ if (!registeredClasses.has(dep)) {
173
+ throw new Error(
174
+ `Dependency ${dep.name} not registered. Register it before ${serviceClass.name}.`,
175
+ );
176
+ }
177
+ // Resolve from container (works because we registered it)
178
+ return tsyringeContainer.resolve(dep);
179
+ });
180
+ const instance = new serviceClass(...resolvedDeps);
181
+
182
+ // Cache the singleton instance
183
+ singletonInstances.set(serviceClass, instance);
184
+ return instance;
139
185
  },
140
186
  } as never);
141
187
  };
@@ -146,4 +192,6 @@ export const registerSingletonWithDependencies = <T>(
146
192
  export const clearContainer = (): void => {
147
193
  tsyringeContainer.clearInstances();
148
194
  tsyringeContainer.reset();
195
+ singletonInstances.clear();
196
+ registeredClasses.clear();
149
197
  };
@@ -1,6 +1,11 @@
1
1
  import { container } from "tsyringe";
2
2
 
3
- export type Constructor<T = unknown> = new (...args: unknown[]) => T;
3
+ /**
4
+ * Constructor type that accepts classes with any parameter signature
5
+ * Uses contravariant any[] to allow flexibility in DI container
6
+ */
7
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
8
+ export type Constructor<T = object> = new (...args: any[]) => T;
4
9
 
5
10
  type Architecture = {
6
11
  start: () => void;