{"version":3,"file":"manifest.mjs","sourceRoot":"","sources":["../../src/manifest/manifest.ts"],"names":[],"mappings":"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","sourcesContent":["import { getErrorMessage } from '@metamask/snaps-sdk';\nimport type { Json } from '@metamask/utils';\nimport { assert, isObject } from '@metamask/utils';\nimport deepmerge from 'deepmerge';\nimport { promises as fs } from 'fs';\nimport pathUtils, { dirname } from 'path';\n\nimport type { SnapManifest } from './validation';\nimport type { ValidatorResults } from './validator';\nimport { hasFixes, isReportFixable, runValidators } from './validator';\nimport type { ValidatorMeta, ValidatorReport } from './validator-types';\nimport * as defaultValidators from './validators';\nimport { deepClone } from '../deep-clone';\nimport { readJsonFile } from '../fs';\nimport { parseJson } from '../json';\nimport type {\n  DeepPartial,\n  ExtendableSnapFiles,\n  UnvalidatedExtendableManifest,\n  UnvalidatedSnapFiles,\n} from '../types';\nimport { NpmSnapFileNames } from '../types';\nimport { readVirtualFile, VirtualFile } from '../virtual-file/node';\n\nconst MANIFEST_SORT_ORDER: Record<keyof SnapManifest, number> = {\n  $schema: 1,\n  extends: 2,\n  version: 3,\n  description: 4,\n  proposedName: 5,\n  repository: 6,\n  source: 7,\n  initialConnections: 8,\n  initialPermissions: 9,\n  platformVersion: 10,\n  manifestVersion: 11,\n};\n\ntype MergedManifest<Type> =\n  Type extends DeepPartial<SnapManifest> ? SnapManifest : Json;\n\n/**\n * Merge two Snap manifests, with the extended manifest taking precedence\n * over the base manifest.\n *\n * @param mainManifest - The main manifest.\n * @param extendedManifest - The extended manifest.\n * @returns The merged manifest.\n */\nfunction mergeManifests<Type>(\n  mainManifest: Type,\n  extendedManifest?: Type,\n): MergedManifest<Type> {\n  if (!extendedManifest) {\n    return mainManifest as MergedManifest<Type>;\n  }\n\n  assert(isObject(mainManifest));\n  assert(isObject(extendedManifest));\n\n  const mergedManifest = deepmerge(extendedManifest, mainManifest);\n  delete mergedManifest.extends;\n\n  return getWritableManifest(mergedManifest) as MergedManifest<Type>;\n}\n\n/**\n * Load a manifest and its extended manifest if it has one.\n *\n * Note: This function does not validate the manifests.\n *\n * @param manifestPath - The path to the manifest file.\n * @param files - A set of already loaded manifest file paths to prevent\n * circular dependencies.\n * @param root - Whether this is the root manifest being loaded. Used for\n * recursive calls, and should not be set by callers.\n * @returns The base and extended manifests.\n */\nexport async function loadManifest(\n  manifestPath: string,\n  files = new Set<string>(),\n  root = true,\n): Promise<UnvalidatedExtendableManifest> {\n  assert(\n    pathUtils.isAbsolute(manifestPath),\n    'The `loadManifest` function must be called with an absolute path.',\n  );\n\n  if (files.has(manifestPath)) {\n    throw new Error(\n      `Failed to load Snap manifest: Circular dependency detected when loading \"${manifestPath}\".`,\n    );\n  }\n\n  const mainManifest = await readJsonFile(manifestPath);\n  files.add(manifestPath);\n\n  if (!isObject(mainManifest.result)) {\n    throw new Error(\n      `Failed to load Snap manifest: The Snap manifest file at \"${manifestPath}\" must contain a JSON object.`,\n    );\n  }\n\n  if (\n    mainManifest.result.extends &&\n    typeof mainManifest.result.extends === 'string'\n  ) {\n    const fileName = pathUtils.basename(manifestPath);\n    if (root && fileName === 'snap.manifest.json') {\n      throw new Error(\n        `Failed to load Snap manifest: The Snap manifest file at \"snap.manifest.json\" cannot extend another manifest.`,\n      );\n    }\n\n    const extendedManifestPath = pathUtils.resolve(\n      pathUtils.dirname(manifestPath),\n      mainManifest.result.extends,\n    );\n\n    const extendedManifest = await loadManifest(\n      extendedManifestPath,\n      files,\n      false,\n    );\n\n    return {\n      mainManifest,\n      extendedManifest: extendedManifest.mergedManifest,\n      mergedManifest: mergeManifests(\n        mainManifest.result,\n        extendedManifest.mergedManifest,\n      ),\n      files,\n    };\n  }\n\n  return {\n    mainManifest,\n    mergedManifest: mainManifest.result,\n    files,\n  };\n}\n\nexport type CheckManifestReport = Omit<ValidatorReport, 'fix'> & {\n  wasFixed?: boolean;\n};\n\n/**\n * The options for the `checkManifest` function.\n */\nexport type CheckManifestOptions = {\n  /**\n   * Whether to auto-magically try to fix errors and then write the manifest to\n   * disk.\n   */\n  updateAndWriteManifest?: boolean;\n\n  /**\n   * The source code of the Snap.\n   */\n  sourceCode?: string;\n\n  /**\n   * The function to use to write the manifest to disk.\n   */\n  writeFileFn?: WriteFileFunction;\n\n  /**\n   * The exports detected by evaluating the bundle. This may be used by one or\n   * more validators to determine whether the Snap is valid.\n   */\n  exports?: string[];\n\n  /**\n   * An object containing the names of the handlers and their respective\n   * permission name. This must be provided to avoid circular dependencies\n   * between `@metamask/snaps-utils` and `@metamask/snaps-rpc-methods`.\n   */\n  handlerEndowments?: Record<string, string | null>;\n\n  /**\n   * Whether the compiler is running in watch mode. This is used to determine\n   * whether to fix warnings or errors only.\n   */\n  watchMode?: boolean;\n};\n\n/**\n * The result from the `checkManifest` function.\n *\n * @property manifest - The fixed manifest object.\n * @property updated - Whether the manifest was written and updated.\n */\nexport type CheckManifestResult = {\n  files?: ExtendableSnapFiles;\n  updated: boolean;\n  reports: CheckManifestReport[];\n};\n\nexport type WriteFileFunction = (path: string, data: string) => Promise<void>;\n\n/**\n * Validates a snap.manifest.json file. Attempts to fix the manifest and write\n * the fixed version to disk if `writeManifest` is true. Throws if validation\n * fails.\n *\n * @param manifestPath - The path to the manifest file.\n * @param options - Additional options for the function.\n * @param options.sourceCode - The source code of the Snap.\n * @param options.writeFileFn - The function to use to write the manifest to\n * disk.\n * @param options.updateAndWriteManifest - Whether to auto-magically try to fix\n * errors and then write the manifest to disk.\n * @param options.exports - The exports detected by evaluating the bundle. This\n * may be used by one or more validators to determine whether the Snap is valid.\n * @param options.handlerEndowments - An object containing the names of the\n * handlers and their respective permission name. This must be provided to avoid\n * circular dependencies between `@metamask/snaps-utils` and\n * `@metamask/snaps-rpc-methods`.\n * @param options.watchMode - Whether the compiler is running in watch mode.\n * This is used to determine whether to fix warnings or errors only.\n * @returns Whether the manifest was updated, and an array of warnings that\n * were encountered during processing of the manifest files.\n */\nexport async function checkManifest(\n  manifestPath: string,\n  {\n    updateAndWriteManifest = true,\n    sourceCode,\n    writeFileFn = fs.writeFile,\n    exports,\n    handlerEndowments,\n    watchMode = false,\n  }: CheckManifestOptions = {},\n): Promise<CheckManifestResult> {\n  const basePath = dirname(manifestPath);\n  const extendableManifest = await loadManifest(manifestPath);\n  const unvalidatedManifest = extendableManifest.mergedManifest;\n\n  const packageFile = await readJsonFile(\n    pathUtils.join(basePath, NpmSnapFileNames.PackageJson),\n  );\n\n  const auxiliaryFilePaths = getSnapFilePaths(\n    unvalidatedManifest,\n    (manifest) => manifest?.source?.files,\n  );\n\n  const localizationFilePaths = getSnapFilePaths(\n    unvalidatedManifest,\n    (manifest) => manifest?.source?.locales,\n  );\n  const localizationFiles =\n    (await getSnapFiles(basePath, localizationFilePaths)) ?? [];\n  for (const localization of localizationFiles) {\n    try {\n      localization.result = parseJson(localization.toString());\n    } catch (error) {\n      assert(error instanceof SyntaxError, error);\n      throw new Error(\n        `Failed to parse localization file \"${localization.path}\" as JSON.`,\n      );\n    }\n  }\n\n  const snapFiles: UnvalidatedSnapFiles = {\n    manifest: extendableManifest,\n    packageJson: packageFile,\n    sourceCode: await getSnapSourceCode(\n      basePath,\n      unvalidatedManifest,\n      sourceCode,\n    ),\n    svgIcon: await getSnapIcon(basePath, unvalidatedManifest),\n    // Intentionally pass null as the encoding here since the files may be binary\n    auxiliaryFiles:\n      (await getSnapFiles(basePath, auxiliaryFilePaths, null)) ?? [],\n    localizationFiles,\n  };\n\n  const validatorResults = await runValidators(\n    snapFiles,\n    Object.values(defaultValidators),\n    { exports, handlerEndowments },\n  );\n\n  let manifestResults: CheckManifestResult = {\n    updated: false,\n    files: validatorResults.files,\n    reports: validatorResults.reports,\n  };\n\n  if (updateAndWriteManifest && hasFixes(manifestResults, watchMode)) {\n    const fixedResults = await runFixes(validatorResults, undefined, watchMode);\n\n    if (fixedResults.updated) {\n      manifestResults = fixedResults;\n\n      assert(manifestResults.files);\n\n      try {\n        await writeFileFn(\n          manifestPath,\n          manifestResults.files.manifest.mainManifest.toString(),\n        );\n      } catch (error) {\n        // Note: This error isn't pushed to the errors array, because it's not an\n        // error in the manifest itself.\n        throw new Error(\n          `Failed to update \"snap.manifest.json\": ${getErrorMessage(error)}`,\n        );\n      }\n    }\n  }\n\n  return manifestResults;\n}\n\n/**\n * Run the algorithm for automatically fixing errors in manifest.\n *\n * The algorithm updates the manifest by fixing all fixable problems,\n * and then run validation again to check if the new manifest is now correct.\n * If not correct, the algorithm will use the manifest from previous iteration\n * and try again `MAX_ATTEMPTS` times to update it before bailing and\n * resulting in failure.\n *\n * @param results - Results of the initial run of validation.\n * @param rules - Optional list of rules to run the fixes with.\n * @param errorsOnly - Whether to only run fixes for errors, not warnings.\n * @returns The updated manifest and whether it was updated.\n */\nexport async function runFixes(\n  results: ValidatorResults,\n  rules?: ValidatorMeta[],\n  errorsOnly = false,\n): Promise<CheckManifestResult> {\n  let shouldRunFixes = true;\n  const MAX_ATTEMPTS = 10;\n\n  assert(results.files);\n\n  let fixResults: ValidatorResults = results;\n  assert(fixResults.files);\n\n  fixResults.files.manifest.mainManifest =\n    fixResults.files.manifest.mainManifest.clone();\n\n  const mergedReports: ValidatorReport[] = deepClone(fixResults.reports);\n\n  for (\n    let attempts = 1;\n    shouldRunFixes && attempts <= MAX_ATTEMPTS;\n    attempts++\n  ) {\n    assert(fixResults.files);\n\n    const fixable = fixResults.reports.filter((report) =>\n      isReportFixable(report, errorsOnly),\n    );\n\n    let { manifest } = fixResults.files;\n    for (const report of fixable) {\n      assert(report.fix);\n      ({ manifest } = await report.fix({ manifest }));\n\n      manifest.mergedManifest = mergeManifests(\n        manifest.mainManifest.result,\n        manifest.extendedManifest,\n      );\n    }\n\n    // The `mainManifest` is always the first manifest loaded, and is the one\n    // that should be updated with fixes. Any manifests that the main manifest\n    // extends will not be updated.\n    // We can revisit this in the future if we want to support fixing extended\n    // manifests as well, but it adds complexity, as we'd need to track which\n    // fixes apply to which manifest.\n    fixResults.files.manifest.mainManifest.value = `${JSON.stringify(\n      getWritableManifest(manifest.mainManifest.result),\n      null,\n      2,\n    )}\\n`;\n    fixResults.files.manifest = manifest;\n    fixResults.files.manifest.mergedManifest = mergeManifests(\n      fixResults.files.manifest.mainManifest.result,\n      fixResults.files.manifest.extendedManifest,\n    );\n\n    fixResults = await runValidators(fixResults.files, rules);\n    shouldRunFixes = hasFixes(fixResults, errorsOnly);\n\n    fixResults.reports\n      .filter(\n        (report) =>\n          !mergedReports.some((mergedReport) => mergedReport.id === report.id),\n      )\n      .forEach((report) => mergedReports.push(report));\n  }\n\n  const allReports: (CheckManifestReport & ValidatorReport)[] =\n    deepClone(mergedReports);\n\n  // Was fixed\n  if (!shouldRunFixes) {\n    for (const report of allReports) {\n      if (report.fix) {\n        report.wasFixed = true;\n        delete report.fix;\n      }\n    }\n\n    return {\n      files: fixResults.files,\n      updated: true,\n      reports: allReports,\n    };\n  }\n\n  for (const report of allReports) {\n    delete report.fix;\n  }\n\n  return {\n    files: results.files,\n    updated: false,\n    reports: allReports,\n  };\n}\n\n/**\n * Given an unvalidated Snap manifest, attempts to extract the location of the\n * bundle source file location and read the file.\n *\n * @param basePath - The path to the folder with the manifest files.\n * @param manifest - The unvalidated Snap manifest file contents.\n * @param sourceCode - Override source code for plugins.\n * @returns The contents of the bundle file, if any.\n */\nexport async function getSnapSourceCode(\n  basePath: string,\n  manifest: Json,\n  sourceCode?: string,\n): Promise<VirtualFile | undefined> {\n  if (!isObject(manifest)) {\n    return undefined;\n  }\n\n  const sourceFilePath = (manifest as Partial<SnapManifest>).source?.location\n    ?.npm?.filePath;\n\n  if (!sourceFilePath) {\n    return undefined;\n  }\n\n  if (sourceCode) {\n    return new VirtualFile({\n      path: pathUtils.join(basePath, sourceFilePath),\n      value: sourceCode,\n    });\n  }\n\n  try {\n    const virtualFile = await readVirtualFile(\n      pathUtils.join(basePath, sourceFilePath),\n      'utf8',\n    );\n    return virtualFile;\n  } catch (error) {\n    throw new Error(\n      `Failed to read snap bundle file: ${getErrorMessage(error)}`,\n    );\n  }\n}\n\n/**\n * Given an unvalidated Snap manifest, attempts to extract the location of the\n * icon and read the file.\n *\n * @param basePath - The path to the folder with the manifest files.\n * @param manifest - The unvalidated Snap manifest file contents.\n * @returns The contents of the icon, if any.\n */\nexport async function getSnapIcon(\n  basePath: string,\n  manifest: Json,\n): Promise<VirtualFile | undefined> {\n  if (!isObject(manifest)) {\n    return undefined;\n  }\n\n  const iconPath = (manifest as Partial<SnapManifest>).source?.location?.npm\n    ?.iconPath;\n\n  if (!iconPath) {\n    return undefined;\n  }\n\n  try {\n    const virtualFile = await readVirtualFile(\n      pathUtils.join(basePath, iconPath),\n      'utf8',\n    );\n    return virtualFile;\n  } catch (error) {\n    throw new Error(`Failed to read snap icon file: ${getErrorMessage(error)}`);\n  }\n}\n\n/**\n * Get an array of paths from an unvalidated Snap manifest.\n *\n * @param manifest - The unvalidated Snap manifest file contents.\n * @param selector - A function that returns the paths to the files.\n * @returns The paths to the files, if any.\n */\nexport function getSnapFilePaths(\n  manifest: Json,\n  selector: (manifest: Partial<SnapManifest>) => string[] | undefined,\n) {\n  if (!isObject(manifest)) {\n    return undefined;\n  }\n\n  const snapManifest = manifest as Partial<SnapManifest>;\n  const paths = selector(snapManifest);\n\n  if (!Array.isArray(paths)) {\n    return undefined;\n  }\n\n  return paths;\n}\n\n/**\n * Given an unvalidated Snap manifest, attempts to extract the files with the\n * given paths and read them.\n *\n * @param basePath - The path to the folder with the manifest files.\n * @param paths - The paths to the files.\n * @param encoding - An optional encoding to pass down to readVirtualFile.\n * @returns A list of auxiliary files and their contents, if any.\n */\nexport async function getSnapFiles(\n  basePath: string,\n  paths: string[] | undefined,\n  encoding: BufferEncoding | null = 'utf8',\n): Promise<VirtualFile[] | undefined> {\n  if (!paths) {\n    return undefined;\n  }\n\n  try {\n    return await Promise.all(\n      paths.map(async (filePath) =>\n        readVirtualFile(pathUtils.join(basePath, filePath), encoding),\n      ),\n    );\n  } catch (error) {\n    throw new Error(`Failed to read snap files: ${getErrorMessage(error)}`);\n  }\n}\n\n/**\n * Sorts the given manifest in our preferred sort order and removes the\n * `repository` field if it is falsy (it may be `null`).\n *\n * @param manifest - The manifest to sort and modify.\n * @returns The disk-ready manifest.\n */\nexport function getWritableManifest(\n  manifest: DeepPartial<SnapManifest>,\n): DeepPartial<SnapManifest> {\n  const { repository, ...remaining } = manifest;\n\n  const keys = Object.keys(\n    repository ? { ...remaining, repository } : remaining,\n  ) as (keyof SnapManifest)[];\n\n  return keys\n    .sort((a, b) => MANIFEST_SORT_ORDER[a] - MANIFEST_SORT_ORDER[b])\n    .reduce<DeepPartial<SnapManifest>>(\n      (result, key) => ({\n        ...result,\n        [key]: manifest[key],\n      }),\n      {},\n    );\n}\n"]}