{"version":3,"file":"env.mjs","names":[],"sources":["../../src/extension/env.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { applyValues } from '../core/args.ts';\nimport { defineInterceptor } from '../core/interceptors.ts';\nimport { thenMaybe } from '../core/results.ts';\nimport type { AnyPadroneBuilder, CommandTypesBase, InterceptorValidateContext } from '../types/index.ts';\nimport type { LoadEnvFilesOptions } from '../util/dotenv.ts';\nimport { loadEnvFiles } from '../util/dotenv.ts';\nimport type { WithAsync } from '../util/type-utils.ts';\n\n// ── Types ────────────────────────────────────────────────────────────────\n\nexport type PadroneEnvOptions = {\n  /** Env modes to load (e.g. `['production']`). Loads `.env.{mode}` files. */\n  modes?: string[];\n  /** Whether to load `.env.local` and `.env.{mode}.local` files. @default true */\n  local?: boolean;\n  /** Directory to search for `.env` files. @default process.cwd() */\n  dir?: string;\n  /** When `true`, file values override `process.env` values. @default false */\n  override?: boolean;\n  /** When `false`, the base `.env` (and `.env.local`) files are not loaded. @default true */\n  base?: boolean;\n};\n\n// ── Helpers ──────────────────────────────────────────────────────────────\n\nfunction isSchema(value: unknown): value is StandardSchemaV1 {\n  return value != null && typeof value === 'object' && '~standard' in value;\n}\n\n// ── Extension ────────────────────────────────────────────────────────────\n\n/**\n * Extension that reads environment variables, validates them against a schema,\n * and merges the transformed values into command arguments.\n *\n * Supports loading `.env` files with mode-based overrides and variable expansion.\n *\n * ```ts\n * // Schema only (reads process.env)\n * .extend(padroneEnv(\n *   z.object({ PORT: z.string() }).transform(e => ({ port: Number(e.PORT) }))\n * ))\n *\n * // Schema + .env file loading\n * .extend(padroneEnv(\n *   z.object({ PORT: z.string() }).transform(e => ({ port: Number(e.PORT) })),\n *   { modes: ['production'] }\n * ))\n *\n * // .env file loading only (no schema validation)\n * .extend(padroneEnv({ modes: ['production'] }))\n * ```\n *\n * Env values have lower precedence than CLI args and stdin, but higher than config files.\n */\nexport function padroneEnv(schema: StandardSchemaV1): <T extends CommandTypesBase>(builder: T) => WithAsync<T>;\nexport function padroneEnv(schema: StandardSchemaV1, options: PadroneEnvOptions): <T extends CommandTypesBase>(builder: T) => WithAsync<T>;\nexport function padroneEnv(options: PadroneEnvOptions): <T extends CommandTypesBase>(builder: T) => WithAsync<T>;\nexport function padroneEnv(\n  schemaOrOptions: StandardSchemaV1 | PadroneEnvOptions,\n  maybeOptions?: PadroneEnvOptions,\n): <T extends CommandTypesBase>(builder: T) => WithAsync<T> {\n  const schema = isSchema(schemaOrOptions) ? schemaOrOptions : undefined;\n  const options = isSchema(schemaOrOptions) ? maybeOptions : schemaOrOptions;\n  const hasFiles = options?.modes !== undefined;\n  const fileOptions: LoadEnvFilesOptions | undefined = hasFiles ? options : undefined;\n  const override = options?.override ?? false;\n\n  const interceptor = defineInterceptor({ id: 'padrone:env', name: 'padrone:env', order: -1000 }, () => ({\n    validate(ctx: InterceptorValidateContext, next) {\n      const processEnv = ctx.runtime.env();\n\n      const applyEnv = (envFromFiles: Record<string, string>) => {\n        const rawEnv = override ? { ...processEnv, ...envFromFiles } : { ...envFromFiles, ...processEnv };\n\n        if (schema) {\n          const envValidated = schema['~standard'].validate(rawEnv);\n          return thenMaybe(envValidated, (result) => {\n            if (result.issues || !result.value) return next();\n            return next({ rawArgs: applyValues(ctx.rawArgs, result.value as Record<string, unknown>) });\n          });\n        }\n\n        // No schema — merge file env values directly into rawArgs\n        if (Object.keys(envFromFiles).length > 0) {\n          return next({ rawArgs: applyValues(ctx.rawArgs, envFromFiles) });\n        }\n        return next();\n      };\n\n      if (hasFiles) {\n        const loaded = loadEnvFiles(fileOptions!, processEnv);\n        return thenMaybe(loaded, applyEnv);\n      }\n\n      return applyEnv({});\n    },\n  }));\n\n  return ((builder: AnyPadroneBuilder) => builder.intercept(interceptor)) as any;\n}\n"],"mappings":";;;;;AA0BA,SAAS,SAAS,OAA2C;CAC3D,OAAO,SAAS,QAAQ,OAAO,UAAU,YAAY,eAAe;AACtE;AA+BA,SAAgB,WACd,iBACA,cAC0D;CAC1D,MAAM,SAAS,SAAS,eAAe,IAAI,kBAAkB,KAAA;CAC7D,MAAM,UAAU,SAAS,eAAe,IAAI,eAAe;CAC3D,MAAM,WAAW,SAAS,UAAU,KAAA;CACpC,MAAM,cAA+C,WAAW,UAAU,KAAA;CAC1E,MAAM,WAAW,SAAS,YAAY;CAEtC,MAAM,cAAc,kBAAkB;EAAE,IAAI;EAAe,MAAM;EAAe,OAAO;CAAM,UAAU,EACrG,SAAS,KAAiC,MAAM;EAC9C,MAAM,aAAa,IAAI,QAAQ,IAAI;EAEnC,MAAM,YAAY,iBAAyC;GACzD,MAAM,SAAS,WAAW;IAAE,GAAG;IAAY,GAAG;GAAa,IAAI;IAAE,GAAG;IAAc,GAAG;GAAW;GAEhG,IAAI,QAEF,OAAO,UADc,OAAO,YAAY,CAAC,SAAS,MACtB,IAAI,WAAW;IACzC,IAAI,OAAO,UAAU,CAAC,OAAO,OAAO,OAAO,KAAK;IAChD,OAAO,KAAK,EAAE,SAAS,YAAY,IAAI,SAAS,OAAO,KAAgC,EAAE,CAAC;GAC5F,CAAC;GAIH,IAAI,OAAO,KAAK,YAAY,CAAC,CAAC,SAAS,GACrC,OAAO,KAAK,EAAE,SAAS,YAAY,IAAI,SAAS,YAAY,EAAE,CAAC;GAEjE,OAAO,KAAK;EACd;EAEA,IAAI,UAEF,OAAO,UADQ,aAAa,aAAc,UACpB,GAAG,QAAQ;EAGnC,OAAO,SAAS,CAAC,CAAC;CACpB,EACF,EAAE;CAEF,SAAS,YAA+B,QAAQ,UAAU,WAAW;AACvE"}