@forklaunch/core 0.15.2 → 0.15.4

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.
@@ -61,7 +61,7 @@ var BaseEntity = class extends import_core.BaseEntity {
61
61
  static async update(data, em, ...constructorArgs) {
62
62
  const instance = new this(...constructorArgs);
63
63
  if (em) {
64
- return em.upsert(instance, data);
64
+ return em.merge(this, data);
65
65
  } else {
66
66
  Object.assign(instance, {
67
67
  ...data,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/persistence/index.ts","../../src/persistence/base.entity.ts"],"sourcesContent":["export * from './base.entity';\n","import {\n Constructor,\n EntityData,\n EntityDTO,\n EntityManager,\n BaseEntity as MikroORMBaseEntity,\n RequiredEntityData,\n wrap\n} from '@mikro-orm/core';\n\n/**\n * BaseEntity class extending MikroORM's BaseEntity to provide\n * convenience static methods for entity creation, updating, and reading.\n */\nexport class BaseEntity extends MikroORMBaseEntity {\n /**\n * Create a new entity instance with the given data.\n *\n * @template T - Entity type extending BaseEntity\n * @param this - The constructor of the entity\n * @param data - Data required to create the entity\n * @param em - Optional MikroORM EntityManager. If passed, this will call em.create()\n * @returns A promise resolving to the created entity\n */\n static async create<T extends BaseEntity>(\n this: Constructor<T>,\n data: RequiredEntityData<T>,\n em?: EntityManager,\n ...constructorArgs: ConstructorParameters<Constructor<T>>\n ): Promise<T> {\n const instance = new this(...constructorArgs);\n if (em) {\n return em.create(this, data);\n } else {\n Object.assign(instance, {\n ...data,\n createdAt: new Date(),\n updatedAt: new Date()\n });\n }\n return instance;\n }\n\n /**\n * Update an existing entity instance with the given data.\n *\n * @template T - Entity type extending BaseEntity\n * @param this - The constructor of the entity\n * @param data - Partial data to update the entity\n * @param em - Optional MikroORM EntityManager. If passed, this will call em.upsert()\n * @returns A promise resolving to the updated entity\n */\n static async update<T extends BaseEntity>(\n this: Constructor<T>,\n data: EntityData<T>,\n em?: EntityManager,\n ...constructorArgs: ConstructorParameters<Constructor<T>>\n ): Promise<T> {\n const instance = new this(...constructorArgs);\n if (em) {\n return em.upsert(instance, data);\n } else {\n Object.assign(instance, {\n ...data,\n updatedAt: new Date()\n });\n }\n return instance;\n }\n\n /**\n * Reads the entity, initializing it if necessary, and returns its DTO representation.\n *\n * @param em - Optional MikroORM EntityManager for initialization. If passed, entity will synchronize with database\n * @returns A promise resolving to the entity's DTO (plain object representation)\n * @throws Error if the entity is not initialized and no EntityManager is provided\n */\n async read(em?: EntityManager): Promise<EntityDTO<this>> {\n if (em && !this.isInitialized()) {\n await this.init({ em });\n }\n return wrap(this).toPOJO();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,kBAQO;AAMA,IAAM,aAAN,cAAyB,YAAAA,WAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUjD,aAAa,OAEX,MACA,OACG,iBACS;AACZ,UAAM,WAAW,IAAI,KAAK,GAAG,eAAe;AAC5C,QAAI,IAAI;AACN,aAAO,GAAG,OAAO,MAAM,IAAI;AAAA,IAC7B,OAAO;AACL,aAAO,OAAO,UAAU;AAAA,QACtB,GAAG;AAAA,QACH,WAAW,oBAAI,KAAK;AAAA,QACpB,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,aAAa,OAEX,MACA,OACG,iBACS;AACZ,UAAM,WAAW,IAAI,KAAK,GAAG,eAAe;AAC5C,QAAI,IAAI;AACN,aAAO,GAAG,OAAO,UAAU,IAAI;AAAA,IACjC,OAAO;AACL,aAAO,OAAO,UAAU;AAAA,QACtB,GAAG;AAAA,QACH,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,KAAK,IAA8C;AACvD,QAAI,MAAM,CAAC,KAAK,cAAc,GAAG;AAC/B,YAAM,KAAK,KAAK,EAAE,GAAG,CAAC;AAAA,IACxB;AACA,eAAO,kBAAK,IAAI,EAAE,OAAO;AAAA,EAC3B;AACF;","names":["MikroORMBaseEntity"]}
1
+ {"version":3,"sources":["../../src/persistence/index.ts","../../src/persistence/base.entity.ts"],"sourcesContent":["export * from './base.entity';\n","import {\n Constructor,\n EntityData,\n EntityDTO,\n EntityManager,\n BaseEntity as MikroORMBaseEntity,\n RequiredEntityData,\n wrap\n} from '@mikro-orm/core';\n\n/**\n * BaseEntity class extending MikroORM's BaseEntity to provide\n * convenience static methods for entity creation, updating, and reading.\n */\nexport class BaseEntity extends MikroORMBaseEntity {\n /**\n * Create a new entity instance with the given data.\n *\n * @template T - Entity type extending BaseEntity\n * @param this - The constructor of the entity\n * @param data - Data required to create the entity\n * @param em - Optional MikroORM EntityManager. If passed, this will call em.create()\n * @returns A promise resolving to the created entity\n */\n static async create<T extends BaseEntity>(\n this: Constructor<T>,\n data: RequiredEntityData<T>,\n em?: EntityManager,\n ...constructorArgs: ConstructorParameters<Constructor<T>>\n ): Promise<T> {\n const instance = new this(...constructorArgs);\n if (em) {\n return em.create(this, data);\n } else {\n Object.assign(instance, {\n ...data,\n createdAt: new Date(),\n updatedAt: new Date()\n });\n }\n return instance;\n }\n\n /**\n * Update an existing entity instance with the given data.\n *\n * @template T - Entity type extending BaseEntity\n * @param this - The constructor of the entity\n * @param data - Partial data to update the entity\n * @param em - Optional MikroORM EntityManager. If passed, this will call em.upsert()\n * @returns A promise resolving to the updated entity\n */\n static async update<T extends BaseEntity>(\n this: Constructor<T>,\n data: EntityData<T>,\n em?: EntityManager,\n ...constructorArgs: ConstructorParameters<Constructor<T>>\n ): Promise<T> {\n const instance = new this(...constructorArgs);\n if (em) {\n return em.merge(this, data);\n } else {\n Object.assign(instance, {\n ...data,\n updatedAt: new Date()\n });\n }\n return instance;\n }\n\n /**\n * Reads the entity, initializing it if necessary, and returns its DTO representation.\n *\n * @param em - Optional MikroORM EntityManager for initialization. If passed, entity will synchronize with database\n * @returns A promise resolving to the entity's DTO (plain object representation)\n * @throws Error if the entity is not initialized and no EntityManager is provided\n */\n async read(em?: EntityManager): Promise<EntityDTO<this>> {\n if (em && !this.isInitialized()) {\n await this.init({ em });\n }\n return wrap(this).toPOJO();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,kBAQO;AAMA,IAAM,aAAN,cAAyB,YAAAA,WAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUjD,aAAa,OAEX,MACA,OACG,iBACS;AACZ,UAAM,WAAW,IAAI,KAAK,GAAG,eAAe;AAC5C,QAAI,IAAI;AACN,aAAO,GAAG,OAAO,MAAM,IAAI;AAAA,IAC7B,OAAO;AACL,aAAO,OAAO,UAAU;AAAA,QACtB,GAAG;AAAA,QACH,WAAW,oBAAI,KAAK;AAAA,QACpB,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,aAAa,OAEX,MACA,OACG,iBACS;AACZ,UAAM,WAAW,IAAI,KAAK,GAAG,eAAe;AAC5C,QAAI,IAAI;AACN,aAAO,GAAG,MAAM,MAAM,IAAI;AAAA,IAC5B,OAAO;AACL,aAAO,OAAO,UAAU;AAAA,QACtB,GAAG;AAAA,QACH,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,KAAK,IAA8C;AACvD,QAAI,MAAM,CAAC,KAAK,cAAc,GAAG;AAC/B,YAAM,KAAK,KAAK,EAAE,GAAG,CAAC;AAAA,IACxB;AACA,eAAO,kBAAK,IAAI,EAAE,OAAO;AAAA,EAC3B;AACF;","names":["MikroORMBaseEntity"]}
@@ -38,7 +38,7 @@ var BaseEntity = class extends MikroORMBaseEntity {
38
38
  static async update(data, em, ...constructorArgs) {
39
39
  const instance = new this(...constructorArgs);
40
40
  if (em) {
41
- return em.upsert(instance, data);
41
+ return em.merge(this, data);
42
42
  } else {
43
43
  Object.assign(instance, {
44
44
  ...data,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/persistence/base.entity.ts"],"sourcesContent":["import {\n Constructor,\n EntityData,\n EntityDTO,\n EntityManager,\n BaseEntity as MikroORMBaseEntity,\n RequiredEntityData,\n wrap\n} from '@mikro-orm/core';\n\n/**\n * BaseEntity class extending MikroORM's BaseEntity to provide\n * convenience static methods for entity creation, updating, and reading.\n */\nexport class BaseEntity extends MikroORMBaseEntity {\n /**\n * Create a new entity instance with the given data.\n *\n * @template T - Entity type extending BaseEntity\n * @param this - The constructor of the entity\n * @param data - Data required to create the entity\n * @param em - Optional MikroORM EntityManager. If passed, this will call em.create()\n * @returns A promise resolving to the created entity\n */\n static async create<T extends BaseEntity>(\n this: Constructor<T>,\n data: RequiredEntityData<T>,\n em?: EntityManager,\n ...constructorArgs: ConstructorParameters<Constructor<T>>\n ): Promise<T> {\n const instance = new this(...constructorArgs);\n if (em) {\n return em.create(this, data);\n } else {\n Object.assign(instance, {\n ...data,\n createdAt: new Date(),\n updatedAt: new Date()\n });\n }\n return instance;\n }\n\n /**\n * Update an existing entity instance with the given data.\n *\n * @template T - Entity type extending BaseEntity\n * @param this - The constructor of the entity\n * @param data - Partial data to update the entity\n * @param em - Optional MikroORM EntityManager. If passed, this will call em.upsert()\n * @returns A promise resolving to the updated entity\n */\n static async update<T extends BaseEntity>(\n this: Constructor<T>,\n data: EntityData<T>,\n em?: EntityManager,\n ...constructorArgs: ConstructorParameters<Constructor<T>>\n ): Promise<T> {\n const instance = new this(...constructorArgs);\n if (em) {\n return em.upsert(instance, data);\n } else {\n Object.assign(instance, {\n ...data,\n updatedAt: new Date()\n });\n }\n return instance;\n }\n\n /**\n * Reads the entity, initializing it if necessary, and returns its DTO representation.\n *\n * @param em - Optional MikroORM EntityManager for initialization. If passed, entity will synchronize with database\n * @returns A promise resolving to the entity's DTO (plain object representation)\n * @throws Error if the entity is not initialized and no EntityManager is provided\n */\n async read(em?: EntityManager): Promise<EntityDTO<this>> {\n if (em && !this.isInitialized()) {\n await this.init({ em });\n }\n return wrap(this).toPOJO();\n }\n}\n"],"mappings":";AAAA;AAAA,EAKE,cAAc;AAAA,EAEd;AAAA,OACK;AAMA,IAAM,aAAN,cAAyB,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUjD,aAAa,OAEX,MACA,OACG,iBACS;AACZ,UAAM,WAAW,IAAI,KAAK,GAAG,eAAe;AAC5C,QAAI,IAAI;AACN,aAAO,GAAG,OAAO,MAAM,IAAI;AAAA,IAC7B,OAAO;AACL,aAAO,OAAO,UAAU;AAAA,QACtB,GAAG;AAAA,QACH,WAAW,oBAAI,KAAK;AAAA,QACpB,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,aAAa,OAEX,MACA,OACG,iBACS;AACZ,UAAM,WAAW,IAAI,KAAK,GAAG,eAAe;AAC5C,QAAI,IAAI;AACN,aAAO,GAAG,OAAO,UAAU,IAAI;AAAA,IACjC,OAAO;AACL,aAAO,OAAO,UAAU;AAAA,QACtB,GAAG;AAAA,QACH,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,KAAK,IAA8C;AACvD,QAAI,MAAM,CAAC,KAAK,cAAc,GAAG;AAC/B,YAAM,KAAK,KAAK,EAAE,GAAG,CAAC;AAAA,IACxB;AACA,WAAO,KAAK,IAAI,EAAE,OAAO;AAAA,EAC3B;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/persistence/base.entity.ts"],"sourcesContent":["import {\n Constructor,\n EntityData,\n EntityDTO,\n EntityManager,\n BaseEntity as MikroORMBaseEntity,\n RequiredEntityData,\n wrap\n} from '@mikro-orm/core';\n\n/**\n * BaseEntity class extending MikroORM's BaseEntity to provide\n * convenience static methods for entity creation, updating, and reading.\n */\nexport class BaseEntity extends MikroORMBaseEntity {\n /**\n * Create a new entity instance with the given data.\n *\n * @template T - Entity type extending BaseEntity\n * @param this - The constructor of the entity\n * @param data - Data required to create the entity\n * @param em - Optional MikroORM EntityManager. If passed, this will call em.create()\n * @returns A promise resolving to the created entity\n */\n static async create<T extends BaseEntity>(\n this: Constructor<T>,\n data: RequiredEntityData<T>,\n em?: EntityManager,\n ...constructorArgs: ConstructorParameters<Constructor<T>>\n ): Promise<T> {\n const instance = new this(...constructorArgs);\n if (em) {\n return em.create(this, data);\n } else {\n Object.assign(instance, {\n ...data,\n createdAt: new Date(),\n updatedAt: new Date()\n });\n }\n return instance;\n }\n\n /**\n * Update an existing entity instance with the given data.\n *\n * @template T - Entity type extending BaseEntity\n * @param this - The constructor of the entity\n * @param data - Partial data to update the entity\n * @param em - Optional MikroORM EntityManager. If passed, this will call em.upsert()\n * @returns A promise resolving to the updated entity\n */\n static async update<T extends BaseEntity>(\n this: Constructor<T>,\n data: EntityData<T>,\n em?: EntityManager,\n ...constructorArgs: ConstructorParameters<Constructor<T>>\n ): Promise<T> {\n const instance = new this(...constructorArgs);\n if (em) {\n return em.merge(this, data);\n } else {\n Object.assign(instance, {\n ...data,\n updatedAt: new Date()\n });\n }\n return instance;\n }\n\n /**\n * Reads the entity, initializing it if necessary, and returns its DTO representation.\n *\n * @param em - Optional MikroORM EntityManager for initialization. If passed, entity will synchronize with database\n * @returns A promise resolving to the entity's DTO (plain object representation)\n * @throws Error if the entity is not initialized and no EntityManager is provided\n */\n async read(em?: EntityManager): Promise<EntityDTO<this>> {\n if (em && !this.isInitialized()) {\n await this.init({ em });\n }\n return wrap(this).toPOJO();\n }\n}\n"],"mappings":";AAAA;AAAA,EAKE,cAAc;AAAA,EAEd;AAAA,OACK;AAMA,IAAM,aAAN,cAAyB,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUjD,aAAa,OAEX,MACA,OACG,iBACS;AACZ,UAAM,WAAW,IAAI,KAAK,GAAG,eAAe;AAC5C,QAAI,IAAI;AACN,aAAO,GAAG,OAAO,MAAM,IAAI;AAAA,IAC7B,OAAO;AACL,aAAO,OAAO,UAAU;AAAA,QACtB,GAAG;AAAA,QACH,WAAW,oBAAI,KAAK;AAAA,QACpB,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,aAAa,OAEX,MACA,OACG,iBACS;AACZ,UAAM,WAAW,IAAI,KAAK,GAAG,eAAe;AAC5C,QAAI,IAAI;AACN,aAAO,GAAG,MAAM,MAAM,IAAI;AAAA,IAC5B,OAAO;AACL,aAAO,OAAO,UAAU;AAAA,QACtB,GAAG;AAAA,QACH,WAAW,oBAAI,KAAK;AAAA,MACtB,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,KAAK,IAA8C;AACvD,QAAI,MAAM,CAAC,KAAK,cAAc,GAAG;AAC/B,YAAM,KAAK,KAAK,EAAE,GAAG,CAAC;AAAA,IACxB;AACA,WAAO,KAAK,IAAI,EAAE,OAAO;AAAA,EAC3B;AACF;","names":[]}
@@ -1,6 +1,16 @@
1
+ export { getCascadingEnvPaths, loadCascadingEnv } from '../environment/index.mjs';
1
2
  import { AnySchemaValidator, IdiomaticSchema, Schema, ParseResult } from '@forklaunch/validator';
2
3
  import { Collection } from '@mikro-orm/core';
3
4
 
5
+ /**
6
+ * Gets an environment variable and casts it to a string.
7
+ *
8
+ * It casts a potentially undefined value to a string, since it will be validated
9
+ * in order to be bootstrapped.
10
+ *
11
+ * @param name - The name of the environment variable to retrieve
12
+ * @returns The environment variable value as a string
13
+ */
4
14
  declare function getEnvVar(name: string): string;
5
15
 
6
16
  declare const Lifetime: {
@@ -1,6 +1,16 @@
1
+ export { getCascadingEnvPaths, loadCascadingEnv } from '../environment/index.js';
1
2
  import { AnySchemaValidator, IdiomaticSchema, Schema, ParseResult } from '@forklaunch/validator';
2
3
  import { Collection } from '@mikro-orm/core';
3
4
 
5
+ /**
6
+ * Gets an environment variable and casts it to a string.
7
+ *
8
+ * It casts a potentially undefined value to a string, since it will be validated
9
+ * in order to be bootstrapped.
10
+ *
11
+ * @param name - The name of the environment variable to retrieve
12
+ * @returns The environment variable value as a string
13
+ */
4
14
  declare function getEnvVar(name: string): string;
5
15
 
6
16
  declare const Lifetime: {
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/services/index.ts
@@ -22,7 +32,9 @@ var services_exports = {};
22
32
  __export(services_exports, {
23
33
  Lifetime: () => Lifetime,
24
34
  createConfigInjector: () => createConfigInjector,
25
- getEnvVar: () => getEnvVar
35
+ getCascadingEnvPaths: () => getCascadingEnvPaths,
36
+ getEnvVar: () => getEnvVar,
37
+ loadCascadingEnv: () => loadCascadingEnv
26
38
  });
27
39
  module.exports = __toCommonJS(services_exports);
28
40
 
@@ -32,6 +44,115 @@ function getEnvVar(name) {
32
44
  return value;
33
45
  }
34
46
 
47
+ // src/environment/loadCascadingEnv.ts
48
+ var import_dotenv = __toESM(require("dotenv"));
49
+ var import_fs = require("fs");
50
+ var import_path = require("path");
51
+ function getCascadingEnvPaths(projectEnvPath, projectRoot = process.cwd()) {
52
+ const result = {
53
+ rootEnvExists: false,
54
+ projectEnvExists: false,
55
+ rootEnvPath: void 0,
56
+ projectEnvFilePath: void 0,
57
+ loadOrder: []
58
+ };
59
+ const applicationRoot = findApplicationRoot(projectRoot);
60
+ const envLocalFiles = collectEnvLocalFiles(projectRoot, applicationRoot);
61
+ result.loadOrder.push(...envLocalFiles);
62
+ const rootEnvPath = (0, import_path.resolve)(applicationRoot, ".env.local");
63
+ if (envLocalFiles.includes(rootEnvPath)) {
64
+ result.rootEnvExists = true;
65
+ result.rootEnvPath = rootEnvPath;
66
+ }
67
+ if (projectEnvPath) {
68
+ const fullProjectEnvPath = (0, import_path.resolve)(projectRoot, projectEnvPath);
69
+ if ((0, import_fs.existsSync)(fullProjectEnvPath)) {
70
+ result.projectEnvExists = true;
71
+ result.projectEnvFilePath = fullProjectEnvPath;
72
+ if (!result.loadOrder.includes(fullProjectEnvPath)) {
73
+ result.loadOrder.push(fullProjectEnvPath);
74
+ }
75
+ }
76
+ }
77
+ return result;
78
+ }
79
+ function loadCascadingEnv(projectEnvPath, projectRoot = process.cwd()) {
80
+ const paths = getCascadingEnvPaths(projectEnvPath, projectRoot);
81
+ const result = {
82
+ rootEnvLoaded: false,
83
+ projectEnvLoaded: false,
84
+ rootEnvPath: paths.rootEnvPath,
85
+ projectEnvFilePath: paths.projectEnvFilePath,
86
+ envFilesLoaded: [],
87
+ totalEnvFilesLoaded: 0
88
+ };
89
+ const seen = /* @__PURE__ */ new Set();
90
+ for (const envPath of paths.loadOrder) {
91
+ if (seen.has(envPath)) {
92
+ continue;
93
+ }
94
+ seen.add(envPath);
95
+ const envResult = import_dotenv.default.config({
96
+ path: envPath,
97
+ override: true
98
+ });
99
+ if (!envResult?.error) {
100
+ result.envFilesLoaded.push(envPath);
101
+ result.totalEnvFilesLoaded++;
102
+ if (envPath === paths.rootEnvPath) {
103
+ result.rootEnvLoaded = true;
104
+ }
105
+ if (envPath === paths.projectEnvFilePath) {
106
+ result.projectEnvLoaded = true;
107
+ }
108
+ }
109
+ }
110
+ return result;
111
+ }
112
+ function collectEnvLocalFiles(projectRoot, applicationRoot) {
113
+ const envLocalPaths = [];
114
+ let currentPath = (0, import_path.resolve)(projectRoot);
115
+ const normalizedAppRoot = (0, import_path.resolve)(applicationRoot);
116
+ while (currentPath.length >= normalizedAppRoot.length) {
117
+ const envLocalPath = (0, import_path.resolve)(currentPath, ".env.local");
118
+ if ((0, import_fs.existsSync)(envLocalPath)) {
119
+ envLocalPaths.push(envLocalPath);
120
+ }
121
+ if (currentPath === normalizedAppRoot) {
122
+ break;
123
+ }
124
+ const parentPath = (0, import_path.dirname)(currentPath);
125
+ if (parentPath === currentPath) {
126
+ break;
127
+ }
128
+ currentPath = parentPath;
129
+ }
130
+ return envLocalPaths.reverse();
131
+ }
132
+ function findApplicationRoot(startPath) {
133
+ let currentPath = (0, import_path.resolve)(startPath);
134
+ const originalStart = currentPath;
135
+ const maxDepth = 10;
136
+ let depth = 0;
137
+ while (depth < maxDepth) {
138
+ const forklaunchManifest = (0, import_path.resolve)(
139
+ currentPath,
140
+ ".forklaunch",
141
+ "manifest.toml"
142
+ );
143
+ if ((0, import_fs.existsSync)(forklaunchManifest)) {
144
+ return currentPath;
145
+ }
146
+ const parentPath = (0, import_path.dirname)(currentPath);
147
+ if (parentPath === currentPath) {
148
+ break;
149
+ }
150
+ currentPath = parentPath;
151
+ depth++;
152
+ }
153
+ return originalStart;
154
+ }
155
+
35
156
  // src/services/configInjector.ts
36
157
  var import_common = require("@forklaunch/common");
37
158
  var import_validator = require("@forklaunch/validator");
@@ -313,6 +434,8 @@ var ValidConfigInjector = class extends ConfigInjector {
313
434
  0 && (module.exports = {
314
435
  Lifetime,
315
436
  createConfigInjector,
316
- getEnvVar
437
+ getCascadingEnvPaths,
438
+ getEnvVar,
439
+ loadCascadingEnv
317
440
  });
318
441
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/services/index.ts","../../../common/src/getEnvVar.ts","../../src/services/configInjector.ts","../../src/services/guards/isConstructed.ts","../../src/services/types/configInjector.types.ts","../../src/services/guards/isConstructedSingleton.ts","../../src/services/guards/isConstructor.ts"],"sourcesContent":["export * from '../../../common/src/getEnvVar';\nexport { createConfigInjector } from './configInjector';\nexport type { ConfigInjector, ValidConfigInjector } from './configInjector';\nexport * from './types/configInjector.types';\nexport * from './types/entityManager.types';\nexport * from './types/service.types';\n","// This is a simple function that returns the value of an environment variable.\n// It casts a potentially undefined value to a string, since it will be validated in order to be bootstrapped.\n\nexport function getEnvVar(name: string): string {\n const value = process.env[name];\n return value as string;\n}\n","import { extractArgumentNames, isNever } from '@forklaunch/common';\nimport {\n AnySchemaValidator,\n IdiomaticSchema,\n ParseResult,\n prettyPrintParseErrors,\n SchemaValidator\n} from '@forklaunch/validator';\nimport { isConstructed } from './guards/isConstructed';\nimport { isConstructedSingleton } from './guards/isConstructedSingleton';\nimport { isConstructor } from './guards/isConstructor';\nimport {\n ConfigValidator,\n Constructed,\n ConstructedSingleton,\n Lifetime,\n ResolvedConfigValidator,\n SchemaConstructor,\n SchemaFunction,\n Singleton\n} from './types/configInjector.types';\n\nexport function createConfigInjector<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n>(\n schemaValidator: SV,\n dependenciesDefinition: {\n [K in keyof CV]:\n | Singleton<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >\n | Constructed<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >;\n }\n) {\n return new ConfigInjector<SV, CV>(\n schemaValidator,\n dependenciesDefinition\n ).load();\n}\n\nexport class ConfigInjector<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n> {\n instances: {\n [K in keyof CV]?: ResolvedConfigValidator<SV, CV>[K];\n } = {};\n\n readonly configShapes: CV;\n\n load(inheritedScopeInstances?: {\n [K in keyof CV]?: ResolvedConfigValidator<SV, CV>[K];\n }): this {\n for (const token in inheritedScopeInstances) {\n this.instances[token] = inheritedScopeInstances[token];\n }\n\n for (const token in this.dependenciesDefinition) {\n const definition = this.dependenciesDefinition[token];\n if (\n definition.lifetime === Lifetime.Singleton &&\n !this.instances[token]\n ) {\n if (\n isConstructedSingleton<\n CV[typeof token],\n Omit<ResolvedConfigValidator<SV, CV>, typeof token>,\n ResolvedConfigValidator<SV, CV>[typeof token]\n >(definition)\n ) {\n this.instances[token] = this.resolveInstance<typeof token>(\n token,\n definition\n );\n } else {\n this.instances[token] = definition.value;\n }\n }\n }\n return this;\n }\n\n private resolveInstance<T extends keyof CV>(\n token: T,\n definition:\n | ConstructedSingleton<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >\n | Constructed<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >,\n context?: Record<string, unknown>,\n resolutionPath: (keyof CV)[] = []\n ): ResolvedConfigValidator<SV, CV>[T] {\n const injectorArgument = extractArgumentNames(definition.factory)[0];\n // short circuit as no args\n if (!injectorArgument || injectorArgument === '_args') {\n return definition.factory(\n {} as Omit<ResolvedConfigValidator<SV, CV>, T>,\n this.resolve.bind(this),\n context ?? ({} as Record<string, unknown>)\n );\n }\n\n if (!injectorArgument.startsWith('{') || !injectorArgument.endsWith('}')) {\n throw new Error(\n `Invalid injector argument for ${String(\n token\n )}: ${injectorArgument}. Please use object destructuring syntax: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment.`\n );\n }\n const resolvedArguments = Object.fromEntries(\n injectorArgument\n .replace('{', '')\n .replace('}', '')\n .split(',')\n .map((arg) => arg.split(':')[0].trim())\n .map((arg) => {\n const newResolutionPath = [...resolutionPath, token];\n if (resolutionPath.includes(arg)) {\n throw new Error(\n `Circular dependency detected: ${newResolutionPath.join(\n ' -> '\n )} -> ${arg}`\n );\n }\n const resolvedArg = this.resolve(arg, context, newResolutionPath);\n return [arg, resolvedArg];\n })\n ) as unknown as Omit<ResolvedConfigValidator<SV, CV>, T>;\n return definition.factory(\n resolvedArguments,\n this.resolve.bind(this),\n context ?? ({} as Record<string, unknown>)\n );\n }\n\n constructor(\n private schemaValidator: SV,\n private dependenciesDefinition: {\n [K in keyof CV]: (\n | Singleton<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >\n | Constructed<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >\n ) & {\n type: CV[K];\n };\n }\n ) {\n this.configShapes = Object.entries(this.dependenciesDefinition).reduce(\n (acc, [key, { type }]) => ({\n ...acc,\n [key]: type\n }),\n {} as Record<keyof CV, CV[keyof CV]>\n ) as CV;\n }\n\n safeValidateConfigSingletons(): ParseResult<ValidConfigInjector<SV, CV>> {\n const validNonSchemaSingletons = Object.entries(this.configShapes).reduce<\n ParseResult<ResolvedConfigValidator<SV, CV>>\n >(\n (acc, [key, value]) => {\n if (\n this.dependenciesDefinition[key].lifetime === Lifetime.Singleton &&\n !(this.schemaValidator as SchemaValidator).isSchema<\n SchemaFunction<SV> | SchemaConstructor<SV> | IdiomaticSchema<SV>\n >(value) &&\n isConstructor(value)\n ) {\n if (!(this.instances[key] instanceof value)) {\n const expected = value.name;\n const receivedValue: unknown = this.instances[key];\n const received = isConstructed(receivedValue)\n ? receivedValue.constructor.name\n : typeof receivedValue;\n\n if (acc.ok) {\n acc = {\n ok: false,\n errors: []\n };\n }\n acc.errors?.push({\n message: `Expected ${expected}, received ${received}`,\n path: [key]\n });\n } else {\n if (acc.ok) {\n acc = {\n ok: true,\n value: {\n ...acc.value,\n [key]: this.instances[key]\n }\n };\n }\n }\n return acc;\n }\n return acc;\n },\n {\n ok: true,\n value: {} as ResolvedConfigValidator<SV, CV>\n }\n );\n\n const singletons = Object.fromEntries(\n Object.entries(this.configShapes).filter(\n ([key, value]) =>\n this.dependenciesDefinition[key].lifetime === Lifetime.Singleton &&\n (this.schemaValidator as SchemaValidator).isSchema(value)\n )\n );\n const schemaSingletonParseResult = (\n this.schemaValidator as SchemaValidator\n ).parse(\n (this.schemaValidator as SchemaValidator).schemify(singletons),\n Object.fromEntries(\n Object.keys(singletons).map((key) => {\n const dependency = this.dependenciesDefinition[key];\n return [\n key,\n dependency.lifetime === Lifetime.Singleton\n ? this.instances[key]\n : undefined\n ];\n })\n )\n );\n\n const configKeys = Object.keys(this.configShapes);\n\n return validNonSchemaSingletons.ok && schemaSingletonParseResult.ok\n ? {\n ok: true as const,\n value: new ValidConfigInjector<SV, CV>(\n this.schemaValidator,\n this.dependenciesDefinition\n ).load({ ...this.instances })\n }\n : {\n ok: false as const,\n errors: [\n ...(!validNonSchemaSingletons.ok && validNonSchemaSingletons.errors\n ? validNonSchemaSingletons.errors\n : []),\n ...(!schemaSingletonParseResult.ok &&\n schemaSingletonParseResult.errors\n ? schemaSingletonParseResult.errors\n : [])\n ].sort(\n (a, b) =>\n configKeys.indexOf(a.path[0]) - configKeys.indexOf(b.path[0])\n )\n };\n }\n\n validateConfigSingletons(configName: string): ValidConfigInjector<SV, CV> {\n const safeValidateResult = this.safeValidateConfigSingletons();\n\n if (safeValidateResult.ok) {\n return safeValidateResult.value;\n }\n\n throw new Error(\n prettyPrintParseErrors(safeValidateResult.errors, configName)\n );\n }\n\n resolve<T extends keyof CV>(\n token: T,\n context?: Record<string, unknown>,\n resolutionPath: (keyof CV)[] = []\n ): ResolvedConfigValidator<SV, CV>[T] {\n const instance = this.instances[token];\n if (!instance) {\n const definition = this.dependenciesDefinition[token];\n\n if (!definition) {\n throw new Error(`Unable to resolve dependency ${String(token)}`);\n }\n\n switch (definition.lifetime) {\n case Lifetime.Singleton: {\n if (\n isConstructedSingleton<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >(definition) &&\n !this.instances[token]\n ) {\n this.instances[token] = this.resolveInstance<T>(\n token,\n definition,\n context,\n resolutionPath\n );\n }\n return this.instances[token] as ResolvedConfigValidator<SV, CV>[T];\n }\n case Lifetime.Scoped: {\n if (\n !isConstructed<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >(definition)\n ) {\n throw new Error(\n `Invalid dependency definition for ${String(token)}`\n );\n }\n\n const scopedInstance = this.resolveInstance<T>(\n token,\n definition,\n context,\n resolutionPath\n );\n this.instances[token] = scopedInstance;\n return scopedInstance;\n }\n case Lifetime.Transient: {\n if (\n !isConstructed<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >(definition)\n ) {\n throw new Error(\n `Invalid dependency definition for ${String(token)}`\n );\n }\n\n return this.resolveInstance<T>(\n token,\n definition,\n context,\n resolutionPath\n );\n }\n default: {\n isNever(definition);\n throw new Error(\n `Unable to resolve lifetime for dependency ${String(\n token\n )}, ${resolutionPath}`\n );\n }\n }\n } else {\n return instance;\n }\n }\n\n scopedResolver<T extends keyof CV>(\n token: T,\n context?: Record<string, unknown>,\n resolutionPath: (keyof CV)[] = []\n ): (scope?: ConfigInjector<SV, CV>) => ResolvedConfigValidator<SV, CV>[T] {\n return (scope) =>\n (scope ?? this.createScope()).resolve<T>(token, context, resolutionPath);\n }\n\n createScope(): ConfigInjector<SV, CV> {\n const singletons: Record<string, unknown> = {};\n for (const dependency in this.dependenciesDefinition) {\n if (\n this.dependenciesDefinition[dependency].lifetime === Lifetime.Singleton\n ) {\n singletons[dependency] = this.instances[dependency];\n }\n }\n return new ConfigInjector<SV, CV>(\n this.schemaValidator,\n this.dependenciesDefinition\n ).load(singletons as ResolvedConfigValidator<SV, CV>);\n }\n\n dispose(): void {\n this.instances = {};\n this.load();\n }\n\n chain<ChainedCV extends ConfigValidator<SV>>(dependenciesDefinition: {\n [K in keyof ChainedCV]: {\n type: ChainedCV[K];\n } & (\n | Singleton<\n ChainedCV[K],\n Omit<ResolvedConfigValidator<SV, CV & ChainedCV>, K>,\n ResolvedConfigValidator<SV, ChainedCV>[K]\n >\n | Constructed<\n ChainedCV[K],\n Omit<ResolvedConfigValidator<SV, CV & ChainedCV>, K>,\n ResolvedConfigValidator<SV, ChainedCV>[K]\n >\n );\n }): ConfigInjector<SV, CV & ChainedCV> {\n return new ConfigInjector<SV, CV>(this.schemaValidator, {\n ...this.dependenciesDefinition,\n ...dependenciesDefinition\n }).load({ ...this.instances }) as unknown as ConfigInjector<\n SV,\n CV & ChainedCV\n >;\n }\n\n tokens(): {\n [K in keyof CV]: K;\n } {\n return Object.fromEntries(\n Object.keys(this.dependenciesDefinition).map((key) => [key, key])\n ) as {\n [K in keyof CV]: K;\n };\n }\n}\n\nexport class ValidConfigInjector<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n> extends ConfigInjector<SV, CV> {\n validConfigInjector!: void;\n}\n","import { Constructed } from '../types/configInjector.types';\n\nexport function isConstructed<Type, Args, Return>(\n value: unknown\n): value is Constructed<Type, Args, Return> {\n return (\n typeof value === 'object' &&\n value != null &&\n 'constructor' in value &&\n value.constructor != null\n );\n}\n","import {\n AnySchemaValidator,\n IdiomaticSchema,\n Schema\n} from '@forklaunch/validator';\nimport { ConfigInjector } from '../configInjector';\n\nexport const Lifetime = {\n Singleton: 0,\n Transient: 1,\n Scoped: 2\n} as const;\nexport type Lifetime = (typeof Lifetime)[keyof typeof Lifetime];\n\nexport type Singleton<Type, Args, Value> =\n | {\n lifetime: typeof Lifetime.Singleton;\n type: Type;\n value: Value;\n }\n | ConstructedSingleton<Type, Args, Value>;\n\nexport type ConstructedSingleton<Type, Args, Return> = {\n lifetime: typeof Lifetime.Singleton;\n type: Type;\n factory: (\n args: Args,\n resolve: <T extends keyof Args>(\n token: T,\n context?: Record<string, unknown>\n ) => Args[T],\n context: Record<string, unknown>\n ) => Return;\n};\n\nexport type Constructed<Type, Args, Return> = {\n lifetime: typeof Lifetime.Transient | typeof Lifetime.Scoped;\n type: Type;\n factory: (\n args: Args,\n resolve: <T extends keyof Args>(\n token: T,\n context?: Record<string, unknown>\n ) => Args[T],\n context: Record<string, unknown>\n ) => Return;\n};\n\nexport type Constructor = new (...args: never[]) => unknown;\nexport type SchemaConstructor<SV extends AnySchemaValidator> = new (\n ...args: unknown[]\n) => IdiomaticSchema<SV>;\nexport type Function = (...args: never[]) => unknown;\nexport type FunctionToConstructor = (\n ...args: never[]\n) => new (...args: never[]) => unknown;\nexport type SchemaFunction<SV extends AnySchemaValidator> = (\n args: unknown\n) => IdiomaticSchema<SV>;\n\nexport type ConfigTypes<SV extends AnySchemaValidator> =\n | Function\n | SchemaFunction<SV>\n | Constructor\n | SchemaConstructor<SV>\n | IdiomaticSchema<SV>;\n\nexport type ConfigValidator<SV extends AnySchemaValidator> = Record<\n string,\n ConfigTypes<SV> | Record<string, ConfigTypes<SV>>\n>;\n\ntype ResolveConfigValue<SV extends AnySchemaValidator, T> =\n T extends SchemaConstructor<SV>\n ? Schema<InstanceType<T>, SV>\n : T extends SchemaFunction<SV>\n ? (...args: Parameters<T>) => Schema<ReturnType<T>, SV>\n : T extends FunctionToConstructor\n ? (...args: Parameters<T>) => InstanceType<ReturnType<T>>\n : T extends Function\n ? (...args: Parameters<T>) => ReturnType<T>\n : T extends Constructor\n ? InstanceType<T>\n : T extends IdiomaticSchema<SV>\n ? Schema<T, SV>\n : T extends Record<string, ConfigTypes<SV>>\n ? {\n [K in keyof T]: ResolveConfigValue<SV, T[K]>;\n }\n : Schema<T, SV>;\n\nexport type ResolvedConfigValidator<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n> = {\n [M in keyof CV]: ResolveConfigValue<SV, CV[M]>;\n};\n\nexport type ScopedDependencyFactory<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>,\n M extends keyof CV\n> = (scope?: ConfigInjector<SV, CV>) => ResolvedConfigValidator<SV, CV>[M];\n","import { ConstructedSingleton, Lifetime } from '../types/configInjector.types';\n\nexport function isConstructedSingleton<Type, Args, Return>(\n value: unknown\n): value is ConstructedSingleton<Type, Args, Return> {\n return (\n typeof value === 'object' &&\n value != null &&\n 'lifetime' in value &&\n value.lifetime === Lifetime.Singleton &&\n 'factory' in value\n );\n}\n","import { Constructor } from '../types/configInjector.types';\n\nexport function isConstructor(value: unknown): value is Constructor {\n return (\n typeof value === 'function' &&\n value.constructor != null &&\n value.prototype != null\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/services/index.ts","../../../common/src/getEnvVar.ts","../../src/environment/loadCascadingEnv.ts","../../src/services/configInjector.ts","../../src/services/guards/isConstructed.ts","../../src/services/types/configInjector.types.ts","../../src/services/guards/isConstructedSingleton.ts","../../src/services/guards/isConstructor.ts"],"sourcesContent":["export * from '../../../common/src/getEnvVar';\nexport * from '../environment';\nexport { createConfigInjector } from './configInjector';\nexport type { ConfigInjector, ValidConfigInjector } from './configInjector';\nexport * from './types/configInjector.types';\nexport * from './types/entityManager.types';\nexport * from './types/service.types';\n","/**\n * Gets an environment variable and casts it to a string.\n *\n * It casts a potentially undefined value to a string, since it will be validated\n * in order to be bootstrapped.\n *\n * @param name - The name of the environment variable to retrieve\n * @returns The environment variable value as a string\n */\nexport function getEnvVar(name: string): string {\n const value = process.env[name];\n return value as string;\n}\n","import dotenv from 'dotenv';\nimport { existsSync } from 'fs';\nimport { dirname, resolve } from 'path';\n\n/**\n * Gets cascading environment file paths: collects all .env.local files from project directory up to root\n * Root detection uses: .forklaunch/manifest.toml\n */\nexport function getCascadingEnvPaths(\n projectEnvPath: string | undefined,\n projectRoot: string = process.cwd()\n): {\n rootEnvExists: boolean;\n projectEnvExists: boolean;\n rootEnvPath?: string;\n projectEnvFilePath?: string;\n loadOrder: string[];\n} {\n const result = {\n rootEnvExists: false,\n projectEnvExists: false,\n rootEnvPath: undefined as string | undefined,\n projectEnvFilePath: undefined as string | undefined,\n loadOrder: [] as string[]\n };\n\n const applicationRoot = findApplicationRoot(projectRoot);\n\n const envLocalFiles = collectEnvLocalFiles(projectRoot, applicationRoot);\n result.loadOrder.push(...envLocalFiles);\n\n const rootEnvPath = resolve(applicationRoot, '.env.local');\n if (envLocalFiles.includes(rootEnvPath)) {\n result.rootEnvExists = true;\n result.rootEnvPath = rootEnvPath;\n }\n\n if (projectEnvPath) {\n const fullProjectEnvPath = resolve(projectRoot, projectEnvPath);\n if (existsSync(fullProjectEnvPath)) {\n result.projectEnvExists = true;\n result.projectEnvFilePath = fullProjectEnvPath;\n if (!result.loadOrder.includes(fullProjectEnvPath)) {\n result.loadOrder.push(fullProjectEnvPath);\n }\n }\n }\n\n return result;\n}\n\n/**\n * Loads environment variables with cascading precedence: all .env.local files from root to project, then project env file\n */\nexport function loadCascadingEnv(\n projectEnvPath: string | undefined,\n projectRoot: string = process.cwd()\n): {\n rootEnvLoaded: boolean;\n projectEnvLoaded: boolean;\n rootEnvPath?: string;\n projectEnvFilePath?: string;\n envFilesLoaded: string[];\n totalEnvFilesLoaded: number;\n} {\n const paths = getCascadingEnvPaths(projectEnvPath, projectRoot);\n const result = {\n rootEnvLoaded: false,\n projectEnvLoaded: false,\n rootEnvPath: paths.rootEnvPath,\n projectEnvFilePath: paths.projectEnvFilePath,\n envFilesLoaded: [] as string[],\n totalEnvFilesLoaded: 0\n };\n\n const seen = new Set<string>();\n for (const envPath of paths.loadOrder) {\n if (seen.has(envPath)) {\n continue;\n }\n seen.add(envPath);\n\n const envResult = dotenv.config({\n path: envPath,\n override: true\n });\n\n if (!envResult?.error) {\n result.envFilesLoaded.push(envPath);\n result.totalEnvFilesLoaded++;\n\n if (envPath === paths.rootEnvPath) {\n result.rootEnvLoaded = true;\n }\n if (envPath === paths.projectEnvFilePath) {\n result.projectEnvLoaded = true;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Collects all .env.local files from project directory up to application root\n * Returns paths in order from root to project (for proper precedence)\n */\nfunction collectEnvLocalFiles(\n projectRoot: string,\n applicationRoot: string\n): string[] {\n const envLocalPaths: string[] = [];\n\n let currentPath = resolve(projectRoot);\n const normalizedAppRoot = resolve(applicationRoot);\n\n while (currentPath.length >= normalizedAppRoot.length) {\n const envLocalPath = resolve(currentPath, '.env.local');\n if (existsSync(envLocalPath)) {\n envLocalPaths.push(envLocalPath);\n }\n\n if (currentPath === normalizedAppRoot) {\n break;\n }\n\n const parentPath = dirname(currentPath);\n if (parentPath === currentPath) {\n break;\n }\n\n currentPath = parentPath;\n }\n\n return envLocalPaths.reverse();\n}\n\n/**\n * Finds application root by looking for .forklaunch/manifest.toml\n */\nfunction findApplicationRoot(startPath: string): string {\n let currentPath = resolve(startPath);\n const originalStart = currentPath;\n const maxDepth = 10;\n let depth = 0;\n\n while (depth < maxDepth) {\n const forklaunchManifest = resolve(\n currentPath,\n '.forklaunch',\n 'manifest.toml'\n );\n if (existsSync(forklaunchManifest)) {\n return currentPath;\n }\n\n const parentPath = dirname(currentPath);\n if (parentPath === currentPath) {\n break;\n }\n\n currentPath = parentPath;\n depth++;\n }\n\n return originalStart;\n}\n","import { extractArgumentNames, isNever } from '@forklaunch/common';\nimport {\n AnySchemaValidator,\n IdiomaticSchema,\n ParseResult,\n prettyPrintParseErrors,\n SchemaValidator\n} from '@forklaunch/validator';\nimport { isConstructed } from './guards/isConstructed';\nimport { isConstructedSingleton } from './guards/isConstructedSingleton';\nimport { isConstructor } from './guards/isConstructor';\nimport {\n ConfigValidator,\n Constructed,\n ConstructedSingleton,\n Lifetime,\n ResolvedConfigValidator,\n SchemaConstructor,\n SchemaFunction,\n Singleton\n} from './types/configInjector.types';\n\nexport function createConfigInjector<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n>(\n schemaValidator: SV,\n dependenciesDefinition: {\n [K in keyof CV]:\n | Singleton<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >\n | Constructed<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >;\n }\n) {\n return new ConfigInjector<SV, CV>(\n schemaValidator,\n dependenciesDefinition\n ).load();\n}\n\nexport class ConfigInjector<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n> {\n instances: {\n [K in keyof CV]?: ResolvedConfigValidator<SV, CV>[K];\n } = {};\n\n readonly configShapes: CV;\n\n load(inheritedScopeInstances?: {\n [K in keyof CV]?: ResolvedConfigValidator<SV, CV>[K];\n }): this {\n for (const token in inheritedScopeInstances) {\n this.instances[token] = inheritedScopeInstances[token];\n }\n\n for (const token in this.dependenciesDefinition) {\n const definition = this.dependenciesDefinition[token];\n if (\n definition.lifetime === Lifetime.Singleton &&\n !this.instances[token]\n ) {\n if (\n isConstructedSingleton<\n CV[typeof token],\n Omit<ResolvedConfigValidator<SV, CV>, typeof token>,\n ResolvedConfigValidator<SV, CV>[typeof token]\n >(definition)\n ) {\n this.instances[token] = this.resolveInstance<typeof token>(\n token,\n definition\n );\n } else {\n this.instances[token] = definition.value;\n }\n }\n }\n return this;\n }\n\n private resolveInstance<T extends keyof CV>(\n token: T,\n definition:\n | ConstructedSingleton<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >\n | Constructed<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >,\n context?: Record<string, unknown>,\n resolutionPath: (keyof CV)[] = []\n ): ResolvedConfigValidator<SV, CV>[T] {\n const injectorArgument = extractArgumentNames(definition.factory)[0];\n // short circuit as no args\n if (!injectorArgument || injectorArgument === '_args') {\n return definition.factory(\n {} as Omit<ResolvedConfigValidator<SV, CV>, T>,\n this.resolve.bind(this),\n context ?? ({} as Record<string, unknown>)\n );\n }\n\n if (!injectorArgument.startsWith('{') || !injectorArgument.endsWith('}')) {\n throw new Error(\n `Invalid injector argument for ${String(\n token\n )}: ${injectorArgument}. Please use object destructuring syntax: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment.`\n );\n }\n const resolvedArguments = Object.fromEntries(\n injectorArgument\n .replace('{', '')\n .replace('}', '')\n .split(',')\n .map((arg) => arg.split(':')[0].trim())\n .map((arg) => {\n const newResolutionPath = [...resolutionPath, token];\n if (resolutionPath.includes(arg)) {\n throw new Error(\n `Circular dependency detected: ${newResolutionPath.join(\n ' -> '\n )} -> ${arg}`\n );\n }\n const resolvedArg = this.resolve(arg, context, newResolutionPath);\n return [arg, resolvedArg];\n })\n ) as unknown as Omit<ResolvedConfigValidator<SV, CV>, T>;\n return definition.factory(\n resolvedArguments,\n this.resolve.bind(this),\n context ?? ({} as Record<string, unknown>)\n );\n }\n\n constructor(\n private schemaValidator: SV,\n private dependenciesDefinition: {\n [K in keyof CV]: (\n | Singleton<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >\n | Constructed<\n CV[K],\n Omit<ResolvedConfigValidator<SV, CV>, K>,\n ResolvedConfigValidator<SV, CV>[K]\n >\n ) & {\n type: CV[K];\n };\n }\n ) {\n this.configShapes = Object.entries(this.dependenciesDefinition).reduce(\n (acc, [key, { type }]) => ({\n ...acc,\n [key]: type\n }),\n {} as Record<keyof CV, CV[keyof CV]>\n ) as CV;\n }\n\n safeValidateConfigSingletons(): ParseResult<ValidConfigInjector<SV, CV>> {\n const validNonSchemaSingletons = Object.entries(this.configShapes).reduce<\n ParseResult<ResolvedConfigValidator<SV, CV>>\n >(\n (acc, [key, value]) => {\n if (\n this.dependenciesDefinition[key].lifetime === Lifetime.Singleton &&\n !(this.schemaValidator as SchemaValidator).isSchema<\n SchemaFunction<SV> | SchemaConstructor<SV> | IdiomaticSchema<SV>\n >(value) &&\n isConstructor(value)\n ) {\n if (!(this.instances[key] instanceof value)) {\n const expected = value.name;\n const receivedValue: unknown = this.instances[key];\n const received = isConstructed(receivedValue)\n ? receivedValue.constructor.name\n : typeof receivedValue;\n\n if (acc.ok) {\n acc = {\n ok: false,\n errors: []\n };\n }\n acc.errors?.push({\n message: `Expected ${expected}, received ${received}`,\n path: [key]\n });\n } else {\n if (acc.ok) {\n acc = {\n ok: true,\n value: {\n ...acc.value,\n [key]: this.instances[key]\n }\n };\n }\n }\n return acc;\n }\n return acc;\n },\n {\n ok: true,\n value: {} as ResolvedConfigValidator<SV, CV>\n }\n );\n\n const singletons = Object.fromEntries(\n Object.entries(this.configShapes).filter(\n ([key, value]) =>\n this.dependenciesDefinition[key].lifetime === Lifetime.Singleton &&\n (this.schemaValidator as SchemaValidator).isSchema(value)\n )\n );\n const schemaSingletonParseResult = (\n this.schemaValidator as SchemaValidator\n ).parse(\n (this.schemaValidator as SchemaValidator).schemify(singletons),\n Object.fromEntries(\n Object.keys(singletons).map((key) => {\n const dependency = this.dependenciesDefinition[key];\n return [\n key,\n dependency.lifetime === Lifetime.Singleton\n ? this.instances[key]\n : undefined\n ];\n })\n )\n );\n\n const configKeys = Object.keys(this.configShapes);\n\n return validNonSchemaSingletons.ok && schemaSingletonParseResult.ok\n ? {\n ok: true as const,\n value: new ValidConfigInjector<SV, CV>(\n this.schemaValidator,\n this.dependenciesDefinition\n ).load({ ...this.instances })\n }\n : {\n ok: false as const,\n errors: [\n ...(!validNonSchemaSingletons.ok && validNonSchemaSingletons.errors\n ? validNonSchemaSingletons.errors\n : []),\n ...(!schemaSingletonParseResult.ok &&\n schemaSingletonParseResult.errors\n ? schemaSingletonParseResult.errors\n : [])\n ].sort(\n (a, b) =>\n configKeys.indexOf(a.path[0]) - configKeys.indexOf(b.path[0])\n )\n };\n }\n\n validateConfigSingletons(configName: string): ValidConfigInjector<SV, CV> {\n const safeValidateResult = this.safeValidateConfigSingletons();\n\n if (safeValidateResult.ok) {\n return safeValidateResult.value;\n }\n\n throw new Error(\n prettyPrintParseErrors(safeValidateResult.errors, configName)\n );\n }\n\n resolve<T extends keyof CV>(\n token: T,\n context?: Record<string, unknown>,\n resolutionPath: (keyof CV)[] = []\n ): ResolvedConfigValidator<SV, CV>[T] {\n const instance = this.instances[token];\n if (!instance) {\n const definition = this.dependenciesDefinition[token];\n\n if (!definition) {\n throw new Error(`Unable to resolve dependency ${String(token)}`);\n }\n\n switch (definition.lifetime) {\n case Lifetime.Singleton: {\n if (\n isConstructedSingleton<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >(definition) &&\n !this.instances[token]\n ) {\n this.instances[token] = this.resolveInstance<T>(\n token,\n definition,\n context,\n resolutionPath\n );\n }\n return this.instances[token] as ResolvedConfigValidator<SV, CV>[T];\n }\n case Lifetime.Scoped: {\n if (\n !isConstructed<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >(definition)\n ) {\n throw new Error(\n `Invalid dependency definition for ${String(token)}`\n );\n }\n\n const scopedInstance = this.resolveInstance<T>(\n token,\n definition,\n context,\n resolutionPath\n );\n this.instances[token] = scopedInstance;\n return scopedInstance;\n }\n case Lifetime.Transient: {\n if (\n !isConstructed<\n CV[T],\n Omit<ResolvedConfigValidator<SV, CV>, T>,\n ResolvedConfigValidator<SV, CV>[T]\n >(definition)\n ) {\n throw new Error(\n `Invalid dependency definition for ${String(token)}`\n );\n }\n\n return this.resolveInstance<T>(\n token,\n definition,\n context,\n resolutionPath\n );\n }\n default: {\n isNever(definition);\n throw new Error(\n `Unable to resolve lifetime for dependency ${String(\n token\n )}, ${resolutionPath}`\n );\n }\n }\n } else {\n return instance;\n }\n }\n\n scopedResolver<T extends keyof CV>(\n token: T,\n context?: Record<string, unknown>,\n resolutionPath: (keyof CV)[] = []\n ): (scope?: ConfigInjector<SV, CV>) => ResolvedConfigValidator<SV, CV>[T] {\n return (scope) =>\n (scope ?? this.createScope()).resolve<T>(token, context, resolutionPath);\n }\n\n createScope(): ConfigInjector<SV, CV> {\n const singletons: Record<string, unknown> = {};\n for (const dependency in this.dependenciesDefinition) {\n if (\n this.dependenciesDefinition[dependency].lifetime === Lifetime.Singleton\n ) {\n singletons[dependency] = this.instances[dependency];\n }\n }\n return new ConfigInjector<SV, CV>(\n this.schemaValidator,\n this.dependenciesDefinition\n ).load(singletons as ResolvedConfigValidator<SV, CV>);\n }\n\n dispose(): void {\n this.instances = {};\n this.load();\n }\n\n chain<ChainedCV extends ConfigValidator<SV>>(dependenciesDefinition: {\n [K in keyof ChainedCV]: {\n type: ChainedCV[K];\n } & (\n | Singleton<\n ChainedCV[K],\n Omit<ResolvedConfigValidator<SV, CV & ChainedCV>, K>,\n ResolvedConfigValidator<SV, ChainedCV>[K]\n >\n | Constructed<\n ChainedCV[K],\n Omit<ResolvedConfigValidator<SV, CV & ChainedCV>, K>,\n ResolvedConfigValidator<SV, ChainedCV>[K]\n >\n );\n }): ConfigInjector<SV, CV & ChainedCV> {\n return new ConfigInjector<SV, CV>(this.schemaValidator, {\n ...this.dependenciesDefinition,\n ...dependenciesDefinition\n }).load({ ...this.instances }) as unknown as ConfigInjector<\n SV,\n CV & ChainedCV\n >;\n }\n\n tokens(): {\n [K in keyof CV]: K;\n } {\n return Object.fromEntries(\n Object.keys(this.dependenciesDefinition).map((key) => [key, key])\n ) as {\n [K in keyof CV]: K;\n };\n }\n}\n\nexport class ValidConfigInjector<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n> extends ConfigInjector<SV, CV> {\n validConfigInjector!: void;\n}\n","import { Constructed } from '../types/configInjector.types';\n\nexport function isConstructed<Type, Args, Return>(\n value: unknown\n): value is Constructed<Type, Args, Return> {\n return (\n typeof value === 'object' &&\n value != null &&\n 'constructor' in value &&\n value.constructor != null\n );\n}\n","import {\n AnySchemaValidator,\n IdiomaticSchema,\n Schema\n} from '@forklaunch/validator';\nimport { ConfigInjector } from '../configInjector';\n\nexport const Lifetime = {\n Singleton: 0,\n Transient: 1,\n Scoped: 2\n} as const;\nexport type Lifetime = (typeof Lifetime)[keyof typeof Lifetime];\n\nexport type Singleton<Type, Args, Value> =\n | {\n lifetime: typeof Lifetime.Singleton;\n type: Type;\n value: Value;\n }\n | ConstructedSingleton<Type, Args, Value>;\n\nexport type ConstructedSingleton<Type, Args, Return> = {\n lifetime: typeof Lifetime.Singleton;\n type: Type;\n factory: (\n args: Args,\n resolve: <T extends keyof Args>(\n token: T,\n context?: Record<string, unknown>\n ) => Args[T],\n context: Record<string, unknown>\n ) => Return;\n};\n\nexport type Constructed<Type, Args, Return> = {\n lifetime: typeof Lifetime.Transient | typeof Lifetime.Scoped;\n type: Type;\n factory: (\n args: Args,\n resolve: <T extends keyof Args>(\n token: T,\n context?: Record<string, unknown>\n ) => Args[T],\n context: Record<string, unknown>\n ) => Return;\n};\n\nexport type Constructor = new (...args: never[]) => unknown;\nexport type SchemaConstructor<SV extends AnySchemaValidator> = new (\n ...args: unknown[]\n) => IdiomaticSchema<SV>;\nexport type Function = (...args: never[]) => unknown;\nexport type FunctionToConstructor = (\n ...args: never[]\n) => new (...args: never[]) => unknown;\nexport type SchemaFunction<SV extends AnySchemaValidator> = (\n args: unknown\n) => IdiomaticSchema<SV>;\n\nexport type ConfigTypes<SV extends AnySchemaValidator> =\n | Function\n | SchemaFunction<SV>\n | Constructor\n | SchemaConstructor<SV>\n | IdiomaticSchema<SV>;\n\nexport type ConfigValidator<SV extends AnySchemaValidator> = Record<\n string,\n ConfigTypes<SV> | Record<string, ConfigTypes<SV>>\n>;\n\ntype ResolveConfigValue<SV extends AnySchemaValidator, T> =\n T extends SchemaConstructor<SV>\n ? Schema<InstanceType<T>, SV>\n : T extends SchemaFunction<SV>\n ? (...args: Parameters<T>) => Schema<ReturnType<T>, SV>\n : T extends FunctionToConstructor\n ? (...args: Parameters<T>) => InstanceType<ReturnType<T>>\n : T extends Function\n ? (...args: Parameters<T>) => ReturnType<T>\n : T extends Constructor\n ? InstanceType<T>\n : T extends IdiomaticSchema<SV>\n ? Schema<T, SV>\n : T extends Record<string, ConfigTypes<SV>>\n ? {\n [K in keyof T]: ResolveConfigValue<SV, T[K]>;\n }\n : Schema<T, SV>;\n\nexport type ResolvedConfigValidator<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>\n> = {\n [M in keyof CV]: ResolveConfigValue<SV, CV[M]>;\n};\n\nexport type ScopedDependencyFactory<\n SV extends AnySchemaValidator,\n CV extends ConfigValidator<SV>,\n M extends keyof CV\n> = (scope?: ConfigInjector<SV, CV>) => ResolvedConfigValidator<SV, CV>[M];\n","import { ConstructedSingleton, Lifetime } from '../types/configInjector.types';\n\nexport function isConstructedSingleton<Type, Args, Return>(\n value: unknown\n): value is ConstructedSingleton<Type, Args, Return> {\n return (\n typeof value === 'object' &&\n value != null &&\n 'lifetime' in value &&\n value.lifetime === Lifetime.Singleton &&\n 'factory' in value\n );\n}\n","import { Constructor } from '../types/configInjector.types';\n\nexport function isConstructor(value: unknown): value is Constructor {\n return (\n typeof value === 'function' &&\n value.constructor != null &&\n value.prototype != null\n );\n}\n"],"mappings":"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","names":["dotenv"]}
@@ -4,6 +4,115 @@ function getEnvVar(name) {
4
4
  return value;
5
5
  }
6
6
 
7
+ // src/environment/loadCascadingEnv.ts
8
+ import dotenv from "dotenv";
9
+ import { existsSync } from "fs";
10
+ import { dirname, resolve } from "path";
11
+ function getCascadingEnvPaths(projectEnvPath, projectRoot = process.cwd()) {
12
+ const result = {
13
+ rootEnvExists: false,
14
+ projectEnvExists: false,
15
+ rootEnvPath: void 0,
16
+ projectEnvFilePath: void 0,
17
+ loadOrder: []
18
+ };
19
+ const applicationRoot = findApplicationRoot(projectRoot);
20
+ const envLocalFiles = collectEnvLocalFiles(projectRoot, applicationRoot);
21
+ result.loadOrder.push(...envLocalFiles);
22
+ const rootEnvPath = resolve(applicationRoot, ".env.local");
23
+ if (envLocalFiles.includes(rootEnvPath)) {
24
+ result.rootEnvExists = true;
25
+ result.rootEnvPath = rootEnvPath;
26
+ }
27
+ if (projectEnvPath) {
28
+ const fullProjectEnvPath = resolve(projectRoot, projectEnvPath);
29
+ if (existsSync(fullProjectEnvPath)) {
30
+ result.projectEnvExists = true;
31
+ result.projectEnvFilePath = fullProjectEnvPath;
32
+ if (!result.loadOrder.includes(fullProjectEnvPath)) {
33
+ result.loadOrder.push(fullProjectEnvPath);
34
+ }
35
+ }
36
+ }
37
+ return result;
38
+ }
39
+ function loadCascadingEnv(projectEnvPath, projectRoot = process.cwd()) {
40
+ const paths = getCascadingEnvPaths(projectEnvPath, projectRoot);
41
+ const result = {
42
+ rootEnvLoaded: false,
43
+ projectEnvLoaded: false,
44
+ rootEnvPath: paths.rootEnvPath,
45
+ projectEnvFilePath: paths.projectEnvFilePath,
46
+ envFilesLoaded: [],
47
+ totalEnvFilesLoaded: 0
48
+ };
49
+ const seen = /* @__PURE__ */ new Set();
50
+ for (const envPath of paths.loadOrder) {
51
+ if (seen.has(envPath)) {
52
+ continue;
53
+ }
54
+ seen.add(envPath);
55
+ const envResult = dotenv.config({
56
+ path: envPath,
57
+ override: true
58
+ });
59
+ if (!envResult?.error) {
60
+ result.envFilesLoaded.push(envPath);
61
+ result.totalEnvFilesLoaded++;
62
+ if (envPath === paths.rootEnvPath) {
63
+ result.rootEnvLoaded = true;
64
+ }
65
+ if (envPath === paths.projectEnvFilePath) {
66
+ result.projectEnvLoaded = true;
67
+ }
68
+ }
69
+ }
70
+ return result;
71
+ }
72
+ function collectEnvLocalFiles(projectRoot, applicationRoot) {
73
+ const envLocalPaths = [];
74
+ let currentPath = resolve(projectRoot);
75
+ const normalizedAppRoot = resolve(applicationRoot);
76
+ while (currentPath.length >= normalizedAppRoot.length) {
77
+ const envLocalPath = resolve(currentPath, ".env.local");
78
+ if (existsSync(envLocalPath)) {
79
+ envLocalPaths.push(envLocalPath);
80
+ }
81
+ if (currentPath === normalizedAppRoot) {
82
+ break;
83
+ }
84
+ const parentPath = dirname(currentPath);
85
+ if (parentPath === currentPath) {
86
+ break;
87
+ }
88
+ currentPath = parentPath;
89
+ }
90
+ return envLocalPaths.reverse();
91
+ }
92
+ function findApplicationRoot(startPath) {
93
+ let currentPath = resolve(startPath);
94
+ const originalStart = currentPath;
95
+ const maxDepth = 10;
96
+ let depth = 0;
97
+ while (depth < maxDepth) {
98
+ const forklaunchManifest = resolve(
99
+ currentPath,
100
+ ".forklaunch",
101
+ "manifest.toml"
102
+ );
103
+ if (existsSync(forklaunchManifest)) {
104
+ return currentPath;
105
+ }
106
+ const parentPath = dirname(currentPath);
107
+ if (parentPath === currentPath) {
108
+ break;
109
+ }
110
+ currentPath = parentPath;
111
+ depth++;
112
+ }
113
+ return originalStart;
114
+ }
115
+
7
116
  // src/services/configInjector.ts
8
117
  import { extractArgumentNames, isNever } from "@forklaunch/common";
9
118
  import {
@@ -286,6 +395,8 @@ var ValidConfigInjector = class extends ConfigInjector {
286
395
  export {
287
396
  Lifetime,
288
397
  createConfigInjector,
289
- getEnvVar
398
+ getCascadingEnvPaths,
399
+ getEnvVar,
400
+ loadCascadingEnv
290
401
  };
291
402
  //# sourceMappingURL=index.mjs.map