{"version":3,"sources":["../../src/config/microfrontends/utils/index.ts","../../src/config/microfrontends/utils/find-config.ts","../../src/config/constants.ts","../../src/config/microfrontends/utils/infer-microfrontends-location.ts","../../src/config/errors.ts"],"sourcesContent":["export { findConfig } from './find-config';\nexport { inferMicrofrontendsLocation } from './infer-microfrontends-location';\n","import fs from 'node:fs';\nimport { join } from 'node:path';\nimport { CONFIGURATION_FILENAMES } from '../../constants';\n\nexport function findConfig({ dir }: { dir: string }): string | null {\n  for (const filename of CONFIGURATION_FILENAMES) {\n    const maybeConfig = join(dir, filename);\n    if (fs.existsSync(maybeConfig)) {\n      return maybeConfig;\n    }\n  }\n\n  return null;\n}\n","export const CONFIGURATION_FILENAMES = [\n  'microfrontends.jsonc',\n  'microfrontends.json',\n] as const;\n","import { dirname } from 'node:path';\nimport { readFileSync } from 'node:fs';\nimport { parse } from 'jsonc-parser';\nimport fg from 'fast-glob';\nimport type { Config } from '../../schema/types';\nimport { CONFIGURATION_FILENAMES } from '../../constants';\nimport { MicrofrontendError } from '../../errors';\n\n// cache the path to default configuration to avoid having to walk the file system multiple times\nconst configCache: Record<string, string> = {};\n\ninterface FindDefaultMicrofrontendPackageArgs {\n  repositoryRoot: string;\n  applicationName: string;\n}\n\n/**\n * Given a repository root and a package name, find the path to the package.json file with the\n * given name.\n *\n * This method uses globby to find all package.json files and then reads them in parallel\n */\nfunction findPackageWithMicrofrontendsConfig({\n  repositoryRoot,\n  applicationName,\n}: FindDefaultMicrofrontendPackageArgs): string | null {\n  try {\n    // eslint-disable-next-line import/no-named-as-default-member\n    const microfrontendsJsonPaths = fg.globSync(\n      `**/{${CONFIGURATION_FILENAMES.join(',')}}`,\n      {\n        cwd: repositoryRoot,\n        absolute: true,\n        onlyFiles: true,\n        followSymbolicLinks: false,\n        ignore: ['**/node_modules/**', '**/.git/**'],\n      },\n    );\n\n    const matchingPaths: string[] = [];\n    for (const microfrontendsJsonPath of microfrontendsJsonPaths) {\n      try {\n        const microfrontendsJsonContent = readFileSync(\n          microfrontendsJsonPath,\n          'utf-8',\n        );\n        const microfrontendsJson = parse(microfrontendsJsonContent) as Config;\n\n        if (microfrontendsJson.applications[applicationName]) {\n          matchingPaths.push(microfrontendsJsonPath);\n        } else {\n          for (const [_, app] of Object.entries(\n            microfrontendsJson.applications,\n          )) {\n            if (app.packageName === applicationName) {\n              matchingPaths.push(microfrontendsJsonPath);\n            }\n          }\n        }\n      } catch (error) {\n        // malformed json most likely, skip this file\n      }\n    }\n\n    if (matchingPaths.length > 1) {\n      throw new MicrofrontendError(\n        `Found multiple \\`microfrontends.json\\` files in the repository referencing the application \"${applicationName}\", but only one is allowed.\\n${matchingPaths.join('\\n  • ')}`,\n        { type: 'config', subtype: 'inference_failed' },\n      );\n    }\n\n    if (matchingPaths.length === 0) {\n      throw new MicrofrontendError(\n        `Could not find a \\`microfrontends.json\\` file in the repository that contains \"applications.${applicationName}\". Microfrontends defined in separate repositories are not supported yet.`,\n        { type: 'config', subtype: 'inference_failed' },\n      );\n    }\n\n    const [packageJsonPath] = matchingPaths as [string];\n    return dirname(packageJsonPath);\n  } catch (error) {\n    return null;\n  }\n}\n\n/**\n * Given a repository root and a package name, find the path to the package directory with\n * a microfrontends config that contains the given name in its applications.\n */\nexport function inferMicrofrontendsLocation(\n  opts: FindDefaultMicrofrontendPackageArgs,\n): string {\n  // cache this with name to support multiple configurations in the same repository\n  const cacheKey = `${opts.repositoryRoot}-${opts.applicationName}`;\n\n  // Check if we have a cached result\n  if (configCache[cacheKey]) {\n    return configCache[cacheKey];\n  }\n\n  const result = findPackageWithMicrofrontendsConfig(opts);\n\n  if (!result) {\n    throw new MicrofrontendError(\n      `Could not infer the location of the \\`microfrontends.json\\` file for application \"${opts.applicationName}\" starting in directory \"${opts.repositoryRoot}\".`,\n      { type: 'config', subtype: 'inference_failed' },\n    );\n  }\n\n  // Cache the result\n  configCache[cacheKey] = result;\n  return result;\n}\n","export type MicrofrontendErrorType =\n  | 'config'\n  | 'packageJson'\n  | 'vercelJson'\n  | 'application'\n  | 'unknown';\n\nexport type MicrofrontendErrorSubtype =\n  | 'not_found'\n  | 'inference_failed'\n  | 'not_found_in_env'\n  | 'invalid_asset_prefix'\n  | 'invalid_main_path'\n  | 'does_not_match_schema'\n  | 'unable_to_read_file'\n  | 'unsupported_validation_env'\n  | 'unsupported_version'\n  | 'invalid_path'\n  | 'invalid_permissions'\n  | 'invalid_syntax'\n  | 'missing_microfrontend_config_path'\n  | 'unsupported_operation';\n\n// A mapping of error types to their subtypes.\ninterface TypeToSubtype {\n  application:\n    | 'invalid_asset_prefix'\n    | 'invalid_path'\n    | 'multiple_package_managers'\n    | 'not_found';\n  config:\n    | 'conflicting_paths'\n    | 'depcrecated_field'\n    | 'does_not_match_schema'\n    | 'invalid_main_path'\n    | 'invalid_preview_deployment_suffix'\n    | 'multiple_default_applications'\n    | 'no_default_application'\n    | 'not_found_in_env'\n    | 'not_found'\n    | 'inference_failed'\n    | 'unable_to_read_file'\n    | 'invalid_syntax'\n    | 'invalid_permissions'\n    | 'unsupported_operation'\n    | 'unsupported_validation_env'\n    | 'unsupported_version';\n  packageJson:\n    | 'missing_field_name'\n    | 'unable_to_read_file'\n    | 'invalid_permissions'\n    | 'invalid_syntax';\n  vercelJson:\n    | 'missing_field_microfrontend_config_path'\n    | 'unable_to_read_file'\n    | 'invalid_permissions'\n    | 'invalid_syntax';\n  unknown: never;\n}\n\nexport type MicrofrontendErrorSource =\n  | '@vercel/microfrontends'\n  | '@vercel/microfrontends/next'\n  | 'fs'\n  | 'ajv';\n\nexport interface MicrofrontendErrorOptions<T extends MicrofrontendErrorType> {\n  cause?: unknown;\n  source?: MicrofrontendErrorSource;\n  type?: T;\n  subtype?: TypeToSubtype[T];\n}\n\ninterface HandleOptions {\n  fileName?: string;\n}\n\nexport class MicrofrontendError<\n  T extends MicrofrontendErrorType = 'unknown',\n> extends Error {\n  public source: MicrofrontendErrorSource;\n  public type: T;\n  public subtype?: TypeToSubtype[T];\n\n  constructor(message: string, opts?: MicrofrontendErrorOptions<T>) {\n    super(message, { cause: opts?.cause });\n    this.name = 'MicrofrontendsError';\n    this.source = opts?.source ?? '@vercel/microfrontends';\n    this.type = opts?.type ?? ('unknown' as T);\n    this.subtype = opts?.subtype;\n    Error.captureStackTrace(this, MicrofrontendError);\n  }\n\n  isKnown(): boolean {\n    return this.type !== 'unknown';\n  }\n\n  isUnknown(): boolean {\n    return !this.isKnown();\n  }\n\n  /**\n   * Converts an error to a MicrofrontendsError.\n   * @param original - The original error to convert.\n   * @returns The converted MicrofrontendsError.\n   */\n  static convert(\n    original: Error,\n    opts?: HandleOptions,\n  ): MicrofrontendError<MicrofrontendErrorType> {\n    if (opts?.fileName) {\n      const err = MicrofrontendError.convertFSError(original, opts.fileName);\n      if (err) {\n        return err;\n      }\n    }\n\n    if (\n      original.message.includes(\n        'Code generation from strings disallowed for this context',\n      )\n    ) {\n      return new MicrofrontendError(original.message, {\n        type: 'config',\n        subtype: 'unsupported_validation_env',\n        source: 'ajv',\n      });\n    }\n\n    // unknown catch-all\n    return new MicrofrontendError(original.message);\n  }\n\n  static convertFSError(\n    original: Error,\n    fileName: string,\n  ): MicrofrontendError<MicrofrontendErrorType> | null {\n    if (original instanceof Error && 'code' in original) {\n      if (original.code === 'ENOENT') {\n        return new MicrofrontendError(`Could not find \"${fileName}\"`, {\n          type: 'config',\n          subtype: 'unable_to_read_file',\n          source: 'fs',\n        });\n      }\n      if (original.code === 'EACCES') {\n        return new MicrofrontendError(\n          `Permission denied while accessing \"${fileName}\"`,\n          {\n            type: 'config',\n            subtype: 'invalid_permissions',\n            source: 'fs',\n          },\n        );\n      }\n    }\n\n    if (original instanceof SyntaxError) {\n      return new MicrofrontendError(\n        `Failed to parse \"${fileName}\": Invalid JSON format.`,\n        {\n          type: 'config',\n          subtype: 'invalid_syntax',\n          source: 'fs',\n        },\n      );\n    }\n\n    return null;\n  }\n\n  /**\n   * Handles an unknown error and returns a MicrofrontendsError instance.\n   * @param err - The error to handle.\n   * @returns A MicrofrontendsError instance.\n   */\n  static handle(\n    err: unknown,\n    opts?: HandleOptions,\n  ): MicrofrontendError<MicrofrontendErrorType> {\n    if (err instanceof MicrofrontendError) {\n      return err as MicrofrontendError<MicrofrontendErrorType>;\n    }\n\n    // handle Error instances\n    if (err instanceof Error) {\n      return MicrofrontendError.convert(err, opts);\n    }\n\n    // handle object errors\n    if (typeof err === 'object' && err !== null) {\n      if ('message' in err && typeof err.message === 'string') {\n        return MicrofrontendError.convert(new Error(err.message), opts);\n      }\n    }\n\n    return new MicrofrontendError('An unknown error occurred');\n  }\n}\n"],"mappings":"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","names":["fs","import_node_path","import_node_fs","fg"]}