@forklaunch/core 0.18.4 → 0.18.6

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.
@@ -20,5 +20,9 @@ declare function loadCascadingEnv(projectEnvPath: string | undefined, projectRoo
20
20
  envFilesLoaded: string[];
21
21
  totalEnvFilesLoaded: number;
22
22
  };
23
+ /**
24
+ * Finds application root by looking for .forklaunch/manifest.toml
25
+ */
26
+ declare function findApplicationRoot(startPath: string): string;
23
27
 
24
- export { getCascadingEnvPaths, loadCascadingEnv };
28
+ export { findApplicationRoot, getCascadingEnvPaths, loadCascadingEnv };
@@ -20,5 +20,9 @@ declare function loadCascadingEnv(projectEnvPath: string | undefined, projectRoo
20
20
  envFilesLoaded: string[];
21
21
  totalEnvFilesLoaded: number;
22
22
  };
23
+ /**
24
+ * Finds application root by looking for .forklaunch/manifest.toml
25
+ */
26
+ declare function findApplicationRoot(startPath: string): string;
23
27
 
24
- export { getCascadingEnvPaths, loadCascadingEnv };
28
+ export { findApplicationRoot, getCascadingEnvPaths, loadCascadingEnv };
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/environment/index.ts
31
31
  var environment_exports = {};
32
32
  __export(environment_exports, {
33
+ findApplicationRoot: () => findApplicationRoot,
33
34
  getCascadingEnvPaths: () => getCascadingEnvPaths,
34
35
  loadCascadingEnv: () => loadCascadingEnv
35
36
  });
@@ -145,6 +146,7 @@ function findApplicationRoot(startPath) {
145
146
  }
146
147
  // Annotate the CommonJS export names for ESM import in node:
147
148
  0 && (module.exports = {
149
+ findApplicationRoot,
148
150
  getCascadingEnvPaths,
149
151
  loadCascadingEnv
150
152
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/environment/index.ts","../../src/environment/loadCascadingEnv.ts"],"sourcesContent":["export * from './loadCascadingEnv';\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"],"mappings":"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","names":["dotenv"]}
1
+ {"version":3,"sources":["../../src/environment/index.ts","../../src/environment/loadCascadingEnv.ts"],"sourcesContent":["export * from './loadCascadingEnv';\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 */\nexport function 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"],"mappings":"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","names":["dotenv"]}
@@ -107,6 +107,7 @@ function findApplicationRoot(startPath) {
107
107
  return originalStart;
108
108
  }
109
109
  export {
110
+ findApplicationRoot,
110
111
  getCascadingEnvPaths,
111
112
  loadCascadingEnv
112
113
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/environment/loadCascadingEnv.ts"],"sourcesContent":["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"],"mappings":";AAAA,OAAO,YAAY;AACnB,SAAS,kBAAkB;AAC3B,SAAS,SAAS,eAAe;AAM1B,SAAS,qBACd,gBACA,cAAsB,QAAQ,IAAI,GAOlC;AACA,QAAM,SAAS;AAAA,IACb,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,oBAAoB;AAAA,IACpB,WAAW,CAAC;AAAA,EACd;AAEA,QAAM,kBAAkB,oBAAoB,WAAW;AAEvD,QAAM,gBAAgB,qBAAqB,aAAa,eAAe;AACvE,SAAO,UAAU,KAAK,GAAG,aAAa;AAEtC,QAAM,cAAc,QAAQ,iBAAiB,YAAY;AACzD,MAAI,cAAc,SAAS,WAAW,GAAG;AACvC,WAAO,gBAAgB;AACvB,WAAO,cAAc;AAAA,EACvB;AAEA,MAAI,gBAAgB;AAClB,UAAM,qBAAqB,QAAQ,aAAa,cAAc;AAC9D,QAAI,WAAW,kBAAkB,GAAG;AAClC,aAAO,mBAAmB;AAC1B,aAAO,qBAAqB;AAC5B,UAAI,CAAC,OAAO,UAAU,SAAS,kBAAkB,GAAG;AAClD,eAAO,UAAU,KAAK,kBAAkB;AAAA,MAC1C;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,iBACd,gBACA,cAAsB,QAAQ,IAAI,GAQlC;AACA,QAAM,QAAQ,qBAAqB,gBAAgB,WAAW;AAC9D,QAAM,SAAS;AAAA,IACb,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,aAAa,MAAM;AAAA,IACnB,oBAAoB,MAAM;AAAA,IAC1B,gBAAgB,CAAC;AAAA,IACjB,qBAAqB;AAAA,EACvB;AAEA,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,WAAW,MAAM,WAAW;AACrC,QAAI,KAAK,IAAI,OAAO,GAAG;AACrB;AAAA,IACF;AACA,SAAK,IAAI,OAAO;AAEhB,UAAM,YAAY,OAAO,OAAO;AAAA,MAC9B,MAAM;AAAA,MACN,UAAU;AAAA,IACZ,CAAC;AAED,QAAI,CAAC,WAAW,OAAO;AACrB,aAAO,eAAe,KAAK,OAAO;AAClC,aAAO;AAEP,UAAI,YAAY,MAAM,aAAa;AACjC,eAAO,gBAAgB;AAAA,MACzB;AACA,UAAI,YAAY,MAAM,oBAAoB;AACxC,eAAO,mBAAmB;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMA,SAAS,qBACP,aACA,iBACU;AACV,QAAM,gBAA0B,CAAC;AAEjC,MAAI,cAAc,QAAQ,WAAW;AACrC,QAAM,oBAAoB,QAAQ,eAAe;AAEjD,SAAO,YAAY,UAAU,kBAAkB,QAAQ;AACrD,UAAM,eAAe,QAAQ,aAAa,YAAY;AACtD,QAAI,WAAW,YAAY,GAAG;AAC5B,oBAAc,KAAK,YAAY;AAAA,IACjC;AAEA,QAAI,gBAAgB,mBAAmB;AACrC;AAAA,IACF;AAEA,UAAM,aAAa,QAAQ,WAAW;AACtC,QAAI,eAAe,aAAa;AAC9B;AAAA,IACF;AAEA,kBAAc;AAAA,EAChB;AAEA,SAAO,cAAc,QAAQ;AAC/B;AAKA,SAAS,oBAAoB,WAA2B;AACtD,MAAI,cAAc,QAAQ,SAAS;AACnC,QAAM,gBAAgB;AACtB,QAAM,WAAW;AACjB,MAAI,QAAQ;AAEZ,SAAO,QAAQ,UAAU;AACvB,UAAM,qBAAqB;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,WAAW,kBAAkB,GAAG;AAClC,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,QAAQ,WAAW;AACtC,QAAI,eAAe,aAAa;AAC9B;AAAA,IACF;AAEA,kBAAc;AACd;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../src/environment/loadCascadingEnv.ts"],"sourcesContent":["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 */\nexport function 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"],"mappings":";AAAA,OAAO,YAAY;AACnB,SAAS,kBAAkB;AAC3B,SAAS,SAAS,eAAe;AAM1B,SAAS,qBACd,gBACA,cAAsB,QAAQ,IAAI,GAOlC;AACA,QAAM,SAAS;AAAA,IACb,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,oBAAoB;AAAA,IACpB,WAAW,CAAC;AAAA,EACd;AAEA,QAAM,kBAAkB,oBAAoB,WAAW;AAEvD,QAAM,gBAAgB,qBAAqB,aAAa,eAAe;AACvE,SAAO,UAAU,KAAK,GAAG,aAAa;AAEtC,QAAM,cAAc,QAAQ,iBAAiB,YAAY;AACzD,MAAI,cAAc,SAAS,WAAW,GAAG;AACvC,WAAO,gBAAgB;AACvB,WAAO,cAAc;AAAA,EACvB;AAEA,MAAI,gBAAgB;AAClB,UAAM,qBAAqB,QAAQ,aAAa,cAAc;AAC9D,QAAI,WAAW,kBAAkB,GAAG;AAClC,aAAO,mBAAmB;AAC1B,aAAO,qBAAqB;AAC5B,UAAI,CAAC,OAAO,UAAU,SAAS,kBAAkB,GAAG;AAClD,eAAO,UAAU,KAAK,kBAAkB;AAAA,MAC1C;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,iBACd,gBACA,cAAsB,QAAQ,IAAI,GAQlC;AACA,QAAM,QAAQ,qBAAqB,gBAAgB,WAAW;AAC9D,QAAM,SAAS;AAAA,IACb,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,aAAa,MAAM;AAAA,IACnB,oBAAoB,MAAM;AAAA,IAC1B,gBAAgB,CAAC;AAAA,IACjB,qBAAqB;AAAA,EACvB;AAEA,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,WAAW,MAAM,WAAW;AACrC,QAAI,KAAK,IAAI,OAAO,GAAG;AACrB;AAAA,IACF;AACA,SAAK,IAAI,OAAO;AAEhB,UAAM,YAAY,OAAO,OAAO;AAAA,MAC9B,MAAM;AAAA,MACN,UAAU;AAAA,IACZ,CAAC;AAED,QAAI,CAAC,WAAW,OAAO;AACrB,aAAO,eAAe,KAAK,OAAO;AAClC,aAAO;AAEP,UAAI,YAAY,MAAM,aAAa;AACjC,eAAO,gBAAgB;AAAA,MACzB;AACA,UAAI,YAAY,MAAM,oBAAoB;AACxC,eAAO,mBAAmB;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMA,SAAS,qBACP,aACA,iBACU;AACV,QAAM,gBAA0B,CAAC;AAEjC,MAAI,cAAc,QAAQ,WAAW;AACrC,QAAM,oBAAoB,QAAQ,eAAe;AAEjD,SAAO,YAAY,UAAU,kBAAkB,QAAQ;AACrD,UAAM,eAAe,QAAQ,aAAa,YAAY;AACtD,QAAI,WAAW,YAAY,GAAG;AAC5B,oBAAc,KAAK,YAAY;AAAA,IACjC;AAEA,QAAI,gBAAgB,mBAAmB;AACrC;AAAA,IACF;AAEA,UAAM,aAAa,QAAQ,WAAW;AACtC,QAAI,eAAe,aAAa;AAC9B;AAAA,IACF;AAEA,kBAAc;AAAA,EAChB;AAEA,SAAO,cAAc,QAAQ;AAC/B;AAKO,SAAS,oBAAoB,WAA2B;AAC7D,MAAI,cAAc,QAAQ,SAAS;AACnC,QAAM,gBAAgB;AACtB,QAAM,WAAW;AACjB,MAAI,QAAQ;AAEZ,SAAO,QAAQ,UAAU;AACvB,UAAM,qBAAqB;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,QAAI,WAAW,kBAAkB,GAAG;AAClC,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,QAAQ,WAAW;AACtC,QAAI,eAAe,aAAa;AAC9B;AAAA,IACF;AAEA,kBAAc;AACd;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
package/lib/http/index.js CHANGED
@@ -514,7 +514,12 @@ function hasPermissionChecks(maybePermissionedAuth) {
514
514
 
515
515
  // src/http/guards/hasRoleChecks.ts
516
516
  function hasRoleChecks(maybeRoledAuth) {
517
- return typeof maybeRoledAuth === "object" && maybeRoledAuth !== null && ("allowedRoles" in maybeRoledAuth || "forbiddenRoles" in maybeRoledAuth);
517
+ if (typeof maybeRoledAuth !== "object" || maybeRoledAuth === null) {
518
+ return false;
519
+ }
520
+ const hasAllowedRoles = "allowedRoles" in maybeRoledAuth && maybeRoledAuth.allowedRoles instanceof Set && maybeRoledAuth.allowedRoles.size > 0;
521
+ const hasForbiddenRoles = "forbiddenRoles" in maybeRoledAuth && maybeRoledAuth.forbiddenRoles instanceof Set && maybeRoledAuth.forbiddenRoles.size > 0;
522
+ return hasAllowedRoles || hasForbiddenRoles;
518
523
  }
519
524
 
520
525
  // src/http/guards/hasScopeChecks.ts