@forklaunch/core 0.3.0 → 0.3.1

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.
@@ -25,7 +25,11 @@ __export(dtoMapper_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(dtoMapper_exports);
27
27
 
28
+ // src/dtoMapper/models/requestDtoMapper.model.ts
29
+ var import_validator2 = require("@forklaunch/validator");
30
+
28
31
  // src/dtoMapper/models/baseDtoMapper.model.ts
32
+ var import_validator = require("@forklaunch/validator");
29
33
  function construct(self, schemaValidator) {
30
34
  return new self(schemaValidator || {});
31
35
  }
@@ -67,7 +71,7 @@ var BaseDtoMapper = class {
67
71
  _dto
68
72
  );
69
73
  if (!parsedSchema.ok) {
70
- throw new Error(`Invalid DTO: ${parsedSchema.error}`);
74
+ throw new Error((0, import_validator.prettyPrintParseErrors)(parsedSchema.errors, "DTO"));
71
75
  }
72
76
  this._dto = _dto;
73
77
  }
@@ -112,7 +116,7 @@ var RequestDtoMapper = class extends BaseDtoMapper {
112
116
  json
113
117
  );
114
118
  if (!parsedSchema.ok) {
115
- throw new Error(`Invalid DTO: ${parsedSchema.error}`);
119
+ throw new Error((0, import_validator2.prettyPrintParseErrors)(parsedSchema.errors, "DTO"));
116
120
  }
117
121
  this.dto = json;
118
122
  return this;
@@ -159,6 +163,7 @@ var RequestDtoMapper = class extends BaseDtoMapper {
159
163
  };
160
164
 
161
165
  // src/dtoMapper/models/responseDtoMapper.model.ts
166
+ var import_validator3 = require("@forklaunch/validator");
162
167
  var ResponseDtoMapper = class extends BaseDtoMapper {
163
168
  /**
164
169
  * The entity type.
@@ -178,7 +183,7 @@ var ResponseDtoMapper = class extends BaseDtoMapper {
178
183
  this.dto
179
184
  );
180
185
  if (!parsedSchema.ok) {
181
- throw new Error(`Invalid DTO: ${parsedSchema.error}`);
186
+ throw new Error((0, import_validator3.prettyPrintParseErrors)(parsedSchema.errors, "DTO"));
182
187
  }
183
188
  return this.dto;
184
189
  }
@@ -1,4 +1,12 @@
1
+ // src/dtoMapper/models/requestDtoMapper.model.ts
2
+ import {
3
+ prettyPrintParseErrors as prettyPrintParseErrors2
4
+ } from "@forklaunch/validator";
5
+
1
6
  // src/dtoMapper/models/baseDtoMapper.model.ts
7
+ import {
8
+ prettyPrintParseErrors
9
+ } from "@forklaunch/validator";
2
10
  function construct(self, schemaValidator) {
3
11
  return new self(schemaValidator || {});
4
12
  }
@@ -40,7 +48,7 @@ var BaseDtoMapper = class {
40
48
  _dto
41
49
  );
42
50
  if (!parsedSchema.ok) {
43
- throw new Error(`Invalid DTO: ${parsedSchema.error}`);
51
+ throw new Error(prettyPrintParseErrors(parsedSchema.errors, "DTO"));
44
52
  }
45
53
  this._dto = _dto;
46
54
  }
@@ -85,7 +93,7 @@ var RequestDtoMapper = class extends BaseDtoMapper {
85
93
  json
86
94
  );
87
95
  if (!parsedSchema.ok) {
88
- throw new Error(`Invalid DTO: ${parsedSchema.error}`);
96
+ throw new Error(prettyPrintParseErrors2(parsedSchema.errors, "DTO"));
89
97
  }
90
98
  this.dto = json;
91
99
  return this;
@@ -132,6 +140,9 @@ var RequestDtoMapper = class extends BaseDtoMapper {
132
140
  };
133
141
 
134
142
  // src/dtoMapper/models/responseDtoMapper.model.ts
143
+ import {
144
+ prettyPrintParseErrors as prettyPrintParseErrors3
145
+ } from "@forklaunch/validator";
135
146
  var ResponseDtoMapper = class extends BaseDtoMapper {
136
147
  /**
137
148
  * The entity type.
@@ -151,7 +162,7 @@ var ResponseDtoMapper = class extends BaseDtoMapper {
151
162
  this.dto
152
163
  );
153
164
  if (!parsedSchema.ok) {
154
- throw new Error(`Invalid DTO: ${parsedSchema.error}`);
165
+ throw new Error(prettyPrintParseErrors3(parsedSchema.errors, "DTO"));
155
166
  }
156
167
  return this.dto;
157
168
  }
package/lib/http/index.js CHANGED
@@ -271,6 +271,9 @@ function enrichDetails(contractDetails, requestSchema, responseSchemas) {
271
271
  };
272
272
  }
273
273
 
274
+ // src/http/middleware/request/parse.middleware.ts
275
+ var import_validator = require("@forklaunch/validator");
276
+
274
277
  // src/http/guards/isResponseShape.ts
275
278
  function isResponseShape(maybeResponseShape) {
276
279
  return maybeResponseShape != null && "body" in maybeResponseShape && "query" in maybeResponseShape && "params" in maybeResponseShape && "headers" in maybeResponseShape;
@@ -296,10 +299,12 @@ function parse(req, _res, next) {
296
299
  switch (req.contractDetails.options?.requestValidation) {
297
300
  default:
298
301
  case "error":
299
- next?.(new Error(`Invalid request: ${parsedRequest.error}`));
302
+ next?.(
303
+ new Error((0, import_validator.prettyPrintParseErrors)(parsedRequest.errors, "Request"))
304
+ );
300
305
  break;
301
306
  case "warning":
302
- console.warn(`Invalid request: ${parsedRequest.error}`);
307
+ console.warn((0, import_validator.prettyPrintParseErrors)(parsedRequest.errors, "Request"));
303
308
  break;
304
309
  case "none":
305
310
  break;
@@ -2004,10 +2009,7 @@ function generateSwaggerDocument(schemaValidator, port, routers) {
2004
2009
  description: `${controllerName} Operations`
2005
2010
  });
2006
2011
  router.routes.forEach((route) => {
2007
- const fullPath = `${router.basePath}${route.path === "/" ? "" : route.path}`.replace(
2008
- /:(\w+)/g,
2009
- "{$1}"
2010
- );
2012
+ const fullPath = `${router.basePath}${route.path === "/" ? "" : route.path}`.replace(/:(\w+)/g, "{$1}");
2011
2013
  if (!paths[fullPath]) {
2012
2014
  paths[fullPath] = {};
2013
2015
  }
@@ -2087,6 +2089,7 @@ function generateSwaggerDocument(schemaValidator, port, routers) {
2087
2089
  }
2088
2090
 
2089
2091
  // src/http/middleware/response/parse.middleware.ts
2092
+ var import_validator2 = require("@forklaunch/validator");
2090
2093
  function parse2(req, res, next) {
2091
2094
  console.debug("[MIDDLEWARE] parseResponse started");
2092
2095
  const { headers, responses } = res.responseSchemas;
@@ -2100,14 +2103,19 @@ function parse2(req, res, next) {
2100
2103
  );
2101
2104
  const parseErrors = [];
2102
2105
  if (!parsedHeaders.ok) {
2103
- parseErrors.push(
2104
- `${parsedHeaders.error ? `Header ${parsedHeaders.error}` : ""}`
2105
- );
2106
+ const headerErrors = (0, import_validator2.prettyPrintParseErrors)(parsedHeaders.errors, "Header");
2107
+ if (headerErrors) {
2108
+ parseErrors.push(headerErrors);
2109
+ }
2106
2110
  }
2107
2111
  if (!parsedResponse.ok) {
2108
- parseErrors.push(
2109
- `${parsedResponse.error ? `Response ${parsedResponse.error}` : ""}`
2112
+ const responseErrors = (0, import_validator2.prettyPrintParseErrors)(
2113
+ parsedResponse.errors,
2114
+ "Response"
2110
2115
  );
2116
+ if (responseErrors) {
2117
+ parseErrors.push(responseErrors);
2118
+ }
2111
2119
  }
2112
2120
  if (parseErrors.length > 0) {
2113
2121
  switch (req.contractDetails.options?.responseValidation) {
@@ -213,6 +213,11 @@ function enrichDetails(contractDetails, requestSchema, responseSchemas) {
213
213
  };
214
214
  }
215
215
 
216
+ // src/http/middleware/request/parse.middleware.ts
217
+ import {
218
+ prettyPrintParseErrors
219
+ } from "@forklaunch/validator";
220
+
216
221
  // src/http/guards/isResponseShape.ts
217
222
  function isResponseShape(maybeResponseShape) {
218
223
  return maybeResponseShape != null && "body" in maybeResponseShape && "query" in maybeResponseShape && "params" in maybeResponseShape && "headers" in maybeResponseShape;
@@ -238,10 +243,12 @@ function parse(req, _res, next) {
238
243
  switch (req.contractDetails.options?.requestValidation) {
239
244
  default:
240
245
  case "error":
241
- next?.(new Error(`Invalid request: ${parsedRequest.error}`));
246
+ next?.(
247
+ new Error(prettyPrintParseErrors(parsedRequest.errors, "Request"))
248
+ );
242
249
  break;
243
250
  case "warning":
244
- console.warn(`Invalid request: ${parsedRequest.error}`);
251
+ console.warn(prettyPrintParseErrors(parsedRequest.errors, "Request"));
245
252
  break;
246
253
  case "none":
247
254
  break;
@@ -1946,10 +1953,7 @@ function generateSwaggerDocument(schemaValidator, port, routers) {
1946
1953
  description: `${controllerName} Operations`
1947
1954
  });
1948
1955
  router.routes.forEach((route) => {
1949
- const fullPath = `${router.basePath}${route.path === "/" ? "" : route.path}`.replace(
1950
- /:(\w+)/g,
1951
- "{$1}"
1952
- );
1956
+ const fullPath = `${router.basePath}${route.path === "/" ? "" : route.path}`.replace(/:(\w+)/g, "{$1}");
1953
1957
  if (!paths[fullPath]) {
1954
1958
  paths[fullPath] = {};
1955
1959
  }
@@ -2029,6 +2033,9 @@ function generateSwaggerDocument(schemaValidator, port, routers) {
2029
2033
  }
2030
2034
 
2031
2035
  // src/http/middleware/response/parse.middleware.ts
2036
+ import {
2037
+ prettyPrintParseErrors as prettyPrintParseErrors2
2038
+ } from "@forklaunch/validator";
2032
2039
  function parse2(req, res, next) {
2033
2040
  console.debug("[MIDDLEWARE] parseResponse started");
2034
2041
  const { headers, responses } = res.responseSchemas;
@@ -2042,14 +2049,19 @@ function parse2(req, res, next) {
2042
2049
  );
2043
2050
  const parseErrors = [];
2044
2051
  if (!parsedHeaders.ok) {
2045
- parseErrors.push(
2046
- `${parsedHeaders.error ? `Header ${parsedHeaders.error}` : ""}`
2047
- );
2052
+ const headerErrors = prettyPrintParseErrors2(parsedHeaders.errors, "Header");
2053
+ if (headerErrors) {
2054
+ parseErrors.push(headerErrors);
2055
+ }
2048
2056
  }
2049
2057
  if (!parsedResponse.ok) {
2050
- parseErrors.push(
2051
- `${parsedResponse.error ? `Response ${parsedResponse.error}` : ""}`
2058
+ const responseErrors = prettyPrintParseErrors2(
2059
+ parsedResponse.errors,
2060
+ "Response"
2052
2061
  );
2062
+ if (responseErrors) {
2063
+ parseErrors.push(responseErrors);
2064
+ }
2053
2065
  }
2054
2066
  if (parseErrors.length > 0) {
2055
2067
  switch (req.contractDetails.options?.responseValidation) {
@@ -22,6 +22,9 @@ type ConfigValidator<SV extends AnySchemaValidator> = Record<string, Function |
22
22
  type ResolvedConfigValidator<SV extends AnySchemaValidator, CV extends ConfigValidator<SV>> = {
23
23
  [M in keyof CV]: CV[M] extends SchemaConstructor<SV> ? Schema<InstanceType<CV[M]>, SV> : CV[M] extends SchemaFunction<SV> ? Schema<ReturnType<CV[M]>, SV> : CV[M] extends Function ? ReturnType<CV[M]> : CV[M] extends Constructor ? InstanceType<CV[M]> : Schema<CV[M], SV>;
24
24
  };
25
+ type ValidResolvedConfigValidator<SV extends AnySchemaValidator, CV extends ConfigValidator<SV>> = ResolvedConfigValidator<SV, CV> & {
26
+ validResolvedConfigValidator: void;
27
+ };
25
28
  type ScopedDependencyFactory<SV extends AnySchemaValidator, CV extends ConfigValidator<SV>, M extends keyof CV> = (scope?: ConfigInjector<SV, CV>) => ResolvedConfigValidator<SV, CV>[M];
26
29
 
27
30
  declare class ConfigInjector<SV extends AnySchemaValidator, CV extends ConfigValidator<SV>> {
@@ -36,13 +39,15 @@ declare class ConfigInjector<SV extends AnySchemaValidator, CV extends ConfigVal
36
39
  constructor(schemaValidator: SV, configShapes: CV, dependenciesDefinition: {
37
40
  [K in keyof CV]: Singleton<ResolvedConfigValidator<SV, CV>[K]> | Constructed<Omit<ResolvedConfigValidator<SV, CV>, K>, ResolvedConfigValidator<SV, CV>[K]>;
38
41
  });
39
- validateConfigSingletons(config: Partial<ResolvedConfigValidator<SV, CV>>): ParseResult<unknown>;
42
+ validateConfigSingletons(): ParseResult<ValidResolvedConfigValidator<SV, CV>>;
40
43
  resolve<T extends keyof CV>(token: T, context?: Record<string, unknown>, resolutionPath?: (keyof CV)[]): ResolvedConfigValidator<SV, CV>[T];
41
44
  scopedResolver<T extends keyof CV>(token: T, context?: Record<string, unknown>, resolutionPath?: (keyof CV)[]): (scope?: ConfigInjector<SV, CV>) => ResolvedConfigValidator<SV, CV>[T];
42
45
  createScope(): ConfigInjector<SV, CV>;
43
46
  dispose(): void;
44
47
  }
45
48
 
49
+ declare function getEnvVar(name: string): string;
50
+
46
51
  /**
47
52
  * Interface representing a base service.
48
53
  *
@@ -61,4 +66,4 @@ type EntityManager = {
61
66
  fork: <Options>(options?: Options) => EntityManager;
62
67
  };
63
68
 
64
- export { type BaseService, ConfigInjector, type ConfigValidator, type Constructed, type Constructor, type EntityManager, type Function, Lifetime, type ResolvedConfigValidator, type SchemaConstructor, type SchemaFunction, type ScopedDependencyFactory, type Singleton };
69
+ export { type BaseService, ConfigInjector, type ConfigValidator, type Constructed, type Constructor, type EntityManager, type Function, Lifetime, type ResolvedConfigValidator, type SchemaConstructor, type SchemaFunction, type ScopedDependencyFactory, type Singleton, type ValidResolvedConfigValidator, getEnvVar };
@@ -22,6 +22,9 @@ type ConfigValidator<SV extends AnySchemaValidator> = Record<string, Function |
22
22
  type ResolvedConfigValidator<SV extends AnySchemaValidator, CV extends ConfigValidator<SV>> = {
23
23
  [M in keyof CV]: CV[M] extends SchemaConstructor<SV> ? Schema<InstanceType<CV[M]>, SV> : CV[M] extends SchemaFunction<SV> ? Schema<ReturnType<CV[M]>, SV> : CV[M] extends Function ? ReturnType<CV[M]> : CV[M] extends Constructor ? InstanceType<CV[M]> : Schema<CV[M], SV>;
24
24
  };
25
+ type ValidResolvedConfigValidator<SV extends AnySchemaValidator, CV extends ConfigValidator<SV>> = ResolvedConfigValidator<SV, CV> & {
26
+ validResolvedConfigValidator: void;
27
+ };
25
28
  type ScopedDependencyFactory<SV extends AnySchemaValidator, CV extends ConfigValidator<SV>, M extends keyof CV> = (scope?: ConfigInjector<SV, CV>) => ResolvedConfigValidator<SV, CV>[M];
26
29
 
27
30
  declare class ConfigInjector<SV extends AnySchemaValidator, CV extends ConfigValidator<SV>> {
@@ -36,13 +39,15 @@ declare class ConfigInjector<SV extends AnySchemaValidator, CV extends ConfigVal
36
39
  constructor(schemaValidator: SV, configShapes: CV, dependenciesDefinition: {
37
40
  [K in keyof CV]: Singleton<ResolvedConfigValidator<SV, CV>[K]> | Constructed<Omit<ResolvedConfigValidator<SV, CV>, K>, ResolvedConfigValidator<SV, CV>[K]>;
38
41
  });
39
- validateConfigSingletons(config: Partial<ResolvedConfigValidator<SV, CV>>): ParseResult<unknown>;
42
+ validateConfigSingletons(): ParseResult<ValidResolvedConfigValidator<SV, CV>>;
40
43
  resolve<T extends keyof CV>(token: T, context?: Record<string, unknown>, resolutionPath?: (keyof CV)[]): ResolvedConfigValidator<SV, CV>[T];
41
44
  scopedResolver<T extends keyof CV>(token: T, context?: Record<string, unknown>, resolutionPath?: (keyof CV)[]): (scope?: ConfigInjector<SV, CV>) => ResolvedConfigValidator<SV, CV>[T];
42
45
  createScope(): ConfigInjector<SV, CV>;
43
46
  dispose(): void;
44
47
  }
45
48
 
49
+ declare function getEnvVar(name: string): string;
50
+
46
51
  /**
47
52
  * Interface representing a base service.
48
53
  *
@@ -61,4 +66,4 @@ type EntityManager = {
61
66
  fork: <Options>(options?: Options) => EntityManager;
62
67
  };
63
68
 
64
- export { type BaseService, ConfigInjector, type ConfigValidator, type Constructed, type Constructor, type EntityManager, type Function, Lifetime, type ResolvedConfigValidator, type SchemaConstructor, type SchemaFunction, type ScopedDependencyFactory, type Singleton };
69
+ export { type BaseService, ConfigInjector, type ConfigValidator, type Constructed, type Constructor, type EntityManager, type Function, Lifetime, type ResolvedConfigValidator, type SchemaConstructor, type SchemaFunction, type ScopedDependencyFactory, type Singleton, type ValidResolvedConfigValidator, getEnvVar };
@@ -21,13 +21,24 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var services_exports = {};
22
22
  __export(services_exports, {
23
23
  ConfigInjector: () => ConfigInjector,
24
- Lifetime: () => Lifetime
24
+ Lifetime: () => Lifetime,
25
+ getEnvVar: () => getEnvVar
25
26
  });
26
27
  module.exports = __toCommonJS(services_exports);
27
28
 
28
29
  // src/services/configInjector.ts
29
30
  var import_common = require("@forklaunch/common");
30
31
 
32
+ // src/services/guards/isConstructed.ts
33
+ function isConstructed(value) {
34
+ return typeof value === "object" && value != null && "constructor" in value && value.constructor != null;
35
+ }
36
+
37
+ // src/services/guards/isConstructor.ts
38
+ function isConstructor(value) {
39
+ return typeof value === "function" && value.constructor != null && value.prototype != null;
40
+ }
41
+
31
42
  // src/services/types/configInjector.types.ts
32
43
  var Lifetime = /* @__PURE__ */ ((Lifetime2) => {
33
44
  Lifetime2[Lifetime2["Singleton"] = 0] = "Singleton";
@@ -64,7 +75,9 @@ var ConfigInjector = class _ConfigInjector {
64
75
  }
65
76
  if (!injectorArgument.startsWith("{") || !injectorArgument.endsWith("}")) {
66
77
  throw new Error(
67
- `Invalid injector argument for ${String(token)}: ${injectorArgument}. Please use object destructuring syntax: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment.`
78
+ `Invalid injector argument for ${String(
79
+ token
80
+ )}: ${injectorArgument}. Please use object destructuring syntax: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment.`
68
81
  );
69
82
  }
70
83
  const resolvedArguments = Object.fromEntries(
@@ -72,7 +85,9 @@ var ConfigInjector = class _ConfigInjector {
72
85
  const newResolutionPath = [...resolutionPath, token];
73
86
  if (resolutionPath.includes(arg)) {
74
87
  throw new Error(
75
- `Circular dependency detected: ${newResolutionPath.join(" -> ")} -> ${arg}`
88
+ `Circular dependency detected: ${newResolutionPath.join(
89
+ " -> "
90
+ )} -> ${arg}`
76
91
  );
77
92
  }
78
93
  const resolvedArg = this.resolve(arg, context, newResolutionPath);
@@ -85,17 +100,78 @@ var ConfigInjector = class _ConfigInjector {
85
100
  context ?? {}
86
101
  );
87
102
  }
88
- validateConfigSingletons(config) {
89
- return this.schemaValidator.parse(
90
- this.schemaValidator.schemify(
91
- Object.fromEntries(
92
- Object.entries(this.configShapes).filter(
93
- ([key, value]) => this.dependenciesDefinition[key].lifetime === 0 /* Singleton */ && this.schemaValidator.isSchema(value)
94
- )
95
- )
96
- ),
97
- config
103
+ validateConfigSingletons() {
104
+ const validNonSchemaSingletons = Object.entries(this.configShapes).reduce(
105
+ (acc, [key, value]) => {
106
+ if (this.dependenciesDefinition[key].lifetime === 0 /* Singleton */ && !this.schemaValidator.isSchema(value) && isConstructor(value)) {
107
+ if (!(this.dependenciesDefinition[key].value instanceof value)) {
108
+ const expected = value.name;
109
+ const receivedValue = this.dependenciesDefinition[key].value;
110
+ const received = isConstructed(receivedValue) ? receivedValue.constructor.name : typeof receivedValue;
111
+ if (acc.ok) {
112
+ acc = {
113
+ ok: false,
114
+ errors: []
115
+ };
116
+ }
117
+ acc.errors?.push({
118
+ message: `Expected ${expected}, received ${received}`,
119
+ path: [key]
120
+ });
121
+ } else {
122
+ if (acc.ok) {
123
+ acc = {
124
+ ok: true,
125
+ value: {
126
+ ...acc.value,
127
+ [key]: this.dependenciesDefinition[key].value
128
+ }
129
+ };
130
+ }
131
+ }
132
+ return acc;
133
+ }
134
+ return acc;
135
+ },
136
+ {
137
+ ok: true,
138
+ value: {}
139
+ }
98
140
  );
141
+ const singletons = Object.fromEntries(
142
+ Object.entries(this.configShapes).filter(
143
+ ([key, value]) => this.dependenciesDefinition[key].lifetime === 0 /* Singleton */ && this.schemaValidator.isSchema(value)
144
+ )
145
+ );
146
+ const schemaSingletonParseResult = this.schemaValidator.parse(
147
+ this.schemaValidator.schemify(singletons),
148
+ Object.fromEntries(
149
+ Object.keys(singletons).map((key) => {
150
+ const dependency = this.dependenciesDefinition[key];
151
+ return [
152
+ key,
153
+ dependency.lifetime === 0 /* Singleton */ ? dependency.value : void 0
154
+ ];
155
+ })
156
+ )
157
+ );
158
+ const configKeys = Object.keys(this.configShapes);
159
+ return validNonSchemaSingletons.ok && schemaSingletonParseResult.ok ? {
160
+ ok: true,
161
+ value: {
162
+ validResolvedConfigValidator: void 0,
163
+ ...validNonSchemaSingletons.value,
164
+ ...schemaSingletonParseResult.value
165
+ }
166
+ } : {
167
+ ok: false,
168
+ errors: [
169
+ ...!validNonSchemaSingletons.ok && validNonSchemaSingletons.errors ? validNonSchemaSingletons.errors : [],
170
+ ...!schemaSingletonParseResult.ok && schemaSingletonParseResult.errors ? schemaSingletonParseResult.errors : []
171
+ ].sort(
172
+ (a, b) => configKeys.indexOf(a.path[0]) - configKeys.indexOf(b.path[0])
173
+ )
174
+ };
99
175
  }
100
176
  resolve(token, context, resolutionPath = []) {
101
177
  const instance = this.instances[token];
@@ -129,7 +205,9 @@ var ConfigInjector = class _ConfigInjector {
129
205
  default: {
130
206
  (0, import_common.isNever)(definition);
131
207
  throw new Error(
132
- `Unable to resolve lifetime for dependency ${String(token)}, ${resolutionPath}`
208
+ `Unable to resolve lifetime for dependency ${String(
209
+ token
210
+ )}, ${resolutionPath}`
133
211
  );
134
212
  }
135
213
  }
@@ -152,8 +230,15 @@ var ConfigInjector = class _ConfigInjector {
152
230
  this.loadSingletons();
153
231
  }
154
232
  };
233
+
234
+ // src/services/getEnvVar.ts
235
+ function getEnvVar(name) {
236
+ const value = process.env[name];
237
+ return value;
238
+ }
155
239
  // Annotate the CommonJS export names for ESM import in node:
156
240
  0 && (module.exports = {
157
241
  ConfigInjector,
158
- Lifetime
242
+ Lifetime,
243
+ getEnvVar
159
244
  });
@@ -1,6 +1,16 @@
1
1
  // src/services/configInjector.ts
2
2
  import { extractArgumentNames, isNever } from "@forklaunch/common";
3
3
 
4
+ // src/services/guards/isConstructed.ts
5
+ function isConstructed(value) {
6
+ return typeof value === "object" && value != null && "constructor" in value && value.constructor != null;
7
+ }
8
+
9
+ // src/services/guards/isConstructor.ts
10
+ function isConstructor(value) {
11
+ return typeof value === "function" && value.constructor != null && value.prototype != null;
12
+ }
13
+
4
14
  // src/services/types/configInjector.types.ts
5
15
  var Lifetime = /* @__PURE__ */ ((Lifetime2) => {
6
16
  Lifetime2[Lifetime2["Singleton"] = 0] = "Singleton";
@@ -37,7 +47,9 @@ var ConfigInjector = class _ConfigInjector {
37
47
  }
38
48
  if (!injectorArgument.startsWith("{") || !injectorArgument.endsWith("}")) {
39
49
  throw new Error(
40
- `Invalid injector argument for ${String(token)}: ${injectorArgument}. Please use object destructuring syntax: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment.`
50
+ `Invalid injector argument for ${String(
51
+ token
52
+ )}: ${injectorArgument}. Please use object destructuring syntax: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment.`
41
53
  );
42
54
  }
43
55
  const resolvedArguments = Object.fromEntries(
@@ -45,7 +57,9 @@ var ConfigInjector = class _ConfigInjector {
45
57
  const newResolutionPath = [...resolutionPath, token];
46
58
  if (resolutionPath.includes(arg)) {
47
59
  throw new Error(
48
- `Circular dependency detected: ${newResolutionPath.join(" -> ")} -> ${arg}`
60
+ `Circular dependency detected: ${newResolutionPath.join(
61
+ " -> "
62
+ )} -> ${arg}`
49
63
  );
50
64
  }
51
65
  const resolvedArg = this.resolve(arg, context, newResolutionPath);
@@ -58,17 +72,78 @@ var ConfigInjector = class _ConfigInjector {
58
72
  context ?? {}
59
73
  );
60
74
  }
61
- validateConfigSingletons(config) {
62
- return this.schemaValidator.parse(
63
- this.schemaValidator.schemify(
64
- Object.fromEntries(
65
- Object.entries(this.configShapes).filter(
66
- ([key, value]) => this.dependenciesDefinition[key].lifetime === 0 /* Singleton */ && this.schemaValidator.isSchema(value)
67
- )
68
- )
69
- ),
70
- config
75
+ validateConfigSingletons() {
76
+ const validNonSchemaSingletons = Object.entries(this.configShapes).reduce(
77
+ (acc, [key, value]) => {
78
+ if (this.dependenciesDefinition[key].lifetime === 0 /* Singleton */ && !this.schemaValidator.isSchema(value) && isConstructor(value)) {
79
+ if (!(this.dependenciesDefinition[key].value instanceof value)) {
80
+ const expected = value.name;
81
+ const receivedValue = this.dependenciesDefinition[key].value;
82
+ const received = isConstructed(receivedValue) ? receivedValue.constructor.name : typeof receivedValue;
83
+ if (acc.ok) {
84
+ acc = {
85
+ ok: false,
86
+ errors: []
87
+ };
88
+ }
89
+ acc.errors?.push({
90
+ message: `Expected ${expected}, received ${received}`,
91
+ path: [key]
92
+ });
93
+ } else {
94
+ if (acc.ok) {
95
+ acc = {
96
+ ok: true,
97
+ value: {
98
+ ...acc.value,
99
+ [key]: this.dependenciesDefinition[key].value
100
+ }
101
+ };
102
+ }
103
+ }
104
+ return acc;
105
+ }
106
+ return acc;
107
+ },
108
+ {
109
+ ok: true,
110
+ value: {}
111
+ }
71
112
  );
113
+ const singletons = Object.fromEntries(
114
+ Object.entries(this.configShapes).filter(
115
+ ([key, value]) => this.dependenciesDefinition[key].lifetime === 0 /* Singleton */ && this.schemaValidator.isSchema(value)
116
+ )
117
+ );
118
+ const schemaSingletonParseResult = this.schemaValidator.parse(
119
+ this.schemaValidator.schemify(singletons),
120
+ Object.fromEntries(
121
+ Object.keys(singletons).map((key) => {
122
+ const dependency = this.dependenciesDefinition[key];
123
+ return [
124
+ key,
125
+ dependency.lifetime === 0 /* Singleton */ ? dependency.value : void 0
126
+ ];
127
+ })
128
+ )
129
+ );
130
+ const configKeys = Object.keys(this.configShapes);
131
+ return validNonSchemaSingletons.ok && schemaSingletonParseResult.ok ? {
132
+ ok: true,
133
+ value: {
134
+ validResolvedConfigValidator: void 0,
135
+ ...validNonSchemaSingletons.value,
136
+ ...schemaSingletonParseResult.value
137
+ }
138
+ } : {
139
+ ok: false,
140
+ errors: [
141
+ ...!validNonSchemaSingletons.ok && validNonSchemaSingletons.errors ? validNonSchemaSingletons.errors : [],
142
+ ...!schemaSingletonParseResult.ok && schemaSingletonParseResult.errors ? schemaSingletonParseResult.errors : []
143
+ ].sort(
144
+ (a, b) => configKeys.indexOf(a.path[0]) - configKeys.indexOf(b.path[0])
145
+ )
146
+ };
72
147
  }
73
148
  resolve(token, context, resolutionPath = []) {
74
149
  const instance = this.instances[token];
@@ -102,7 +177,9 @@ var ConfigInjector = class _ConfigInjector {
102
177
  default: {
103
178
  isNever(definition);
104
179
  throw new Error(
105
- `Unable to resolve lifetime for dependency ${String(token)}, ${resolutionPath}`
180
+ `Unable to resolve lifetime for dependency ${String(
181
+ token
182
+ )}, ${resolutionPath}`
106
183
  );
107
184
  }
108
185
  }
@@ -125,7 +202,14 @@ var ConfigInjector = class _ConfigInjector {
125
202
  this.loadSingletons();
126
203
  }
127
204
  };
205
+
206
+ // src/services/getEnvVar.ts
207
+ function getEnvVar(name) {
208
+ const value = process.env[name];
209
+ return value;
210
+ }
128
211
  export {
129
212
  ConfigInjector,
130
- Lifetime
213
+ Lifetime,
214
+ getEnvVar
131
215
  };
package/package.json CHANGED
@@ -1,52 +1,17 @@
1
1
  {
2
2
  "name": "@forklaunch/core",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "forklaunch-js core package. Contains useful building blocks.",
5
- "files": [
6
- "lib"
7
- ],
8
- "types": "lib/index.d.ts",
9
- "author": "Rohin Bhargava",
10
- "license": "MIT",
11
- "repository": {
12
- "type": "git",
13
- "url": "git+https://github.com/forklaunch/forklaunch-js.git"
14
- },
5
+ "homepage": "https://github.com/forklaunch/forklaunch-js#readme",
15
6
  "bugs": {
16
7
  "url": "https://github.com/forklaunch/forklaunch-js/issues"
17
8
  },
18
- "homepage": "https://github.com/forklaunch/forklaunch-js#readme",
19
- "dependencies": {
20
- "@mikro-orm/core": "^6.4.3",
21
- "@mikro-orm/mongodb": "^6.4.3",
22
- "cors": "^2.8.5",
23
- "jose": "^5.9.6",
24
- "openapi3-ts": "^4.4.0",
25
- "redis": "^4.7.0",
26
- "uuid": "^11.0.5",
27
- "@forklaunch/common": "0.2.0",
28
- "@forklaunch/validator": "0.4.0"
29
- },
30
- "devDependencies": {
31
- "@eslint/js": "^9.17.0",
32
- "@types/cors": "^2.8.17",
33
- "@types/jest": "^29.5.14",
34
- "@types/qs": "^6.9.17",
35
- "@types/uuid": "^10.0.0",
36
- "globals": "^15.14.0",
37
- "jest": "^29.7.0",
38
- "prettier": "^3.4.2",
39
- "testcontainers": "^10.16.0",
40
- "ts-jest": "^29.2.5",
41
- "ts-node": "^10.9.2",
42
- "tsup": "^8.3.5",
43
- "typedoc": "^0.27.6",
44
- "typescript": "^5.7.3",
45
- "typescript-eslint": "^8.19.1"
46
- },
47
- "directories": {
48
- "test": "tests"
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/forklaunch/forklaunch-js.git"
49
12
  },
13
+ "license": "MIT",
14
+ "author": "Rohin Bhargava",
50
15
  "exports": {
51
16
  "./cache": {
52
17
  "types": "./lib/cache/index.d.ts",
@@ -85,14 +50,49 @@
85
50
  "default": "./lib/services/index.js"
86
51
  }
87
52
  },
53
+ "types": "lib/index.d.ts",
54
+ "directories": {
55
+ "test": "tests"
56
+ },
57
+ "files": [
58
+ "lib"
59
+ ],
60
+ "dependencies": {
61
+ "@mikro-orm/core": "^6.4.3",
62
+ "@mikro-orm/mongodb": "^6.4.3",
63
+ "cors": "^2.8.5",
64
+ "jose": "^5.9.6",
65
+ "openapi3-ts": "^4.4.0",
66
+ "redis": "^4.7.0",
67
+ "uuid": "^11.0.5",
68
+ "@forklaunch/common": "0.2.0",
69
+ "@forklaunch/validator": "0.4.1"
70
+ },
71
+ "devDependencies": {
72
+ "@eslint/js": "^9.17.0",
73
+ "@types/cors": "^2.8.17",
74
+ "@types/jest": "^29.5.14",
75
+ "@types/qs": "^6.9.17",
76
+ "@types/uuid": "^10.0.0",
77
+ "globals": "^15.14.0",
78
+ "jest": "^29.7.0",
79
+ "prettier": "^3.4.2",
80
+ "testcontainers": "^10.16.0",
81
+ "ts-jest": "^29.2.5",
82
+ "ts-node": "^10.9.2",
83
+ "tsup": "^8.3.5",
84
+ "typedoc": "^0.27.6",
85
+ "typescript": "^5.7.3",
86
+ "typescript-eslint": "^8.19.1"
87
+ },
88
88
  "scripts": {
89
- "test": "vitest --passWithNoTests",
90
89
  "build": "tsc --noEmit && tsup ./src/cache/index.ts ./src/controllers/index.ts ./src/database/index.ts ./src/dtoMapper/index.ts ./src/http/index.ts ./src/services/index.ts --format cjs,esm --no-splitting --dts --tsconfig tsconfig.json --out-dir lib --clean",
91
90
  "clean": "rm -rf lib pnpm.lock.yaml node_modules",
92
91
  "docs": "typedoc --out docs *",
92
+ "format": "prettier --ignore-path=.prettierignore --config .prettierrc '**/*.{ts,tsx,json}' --write",
93
93
  "lint": "eslint . -c eslint.config.mjs",
94
94
  "lint:fix": "eslint . -c eslint.config.mjs --fix",
95
- "format": "prettier --ignore-path=.prettierignore --config .prettierrc '**/*.ts' --write",
96
- "publish:package": "./publish-package.bash"
95
+ "publish:package": "./publish-package.bash",
96
+ "test": "vitest --passWithNoTests"
97
97
  }
98
98
  }