{"version":3,"file":"diagnostics.cjs","names":[],"sources":["../src/diagnostics.ts"],"sourcesContent":["import buildDebug from 'debug';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { join, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\nimport { PLUGIN_PREFIX } from '@verdaccio/core';\n\nimport { getSanityCheck } from './sanity-checks';\nimport type { DiagnosticStep, VerifyPluginOptions } from './types';\n\nconst debug = buildDebug('verdaccio:plugin:verifier:diagnostics');\n\n// createRequire needs an absolute path; works in both ESM and CJS contexts\nconst requireModule = createRequire(\n  typeof __filename !== 'undefined' ? __filename : import.meta.url\n);\n\nfunction isValidExport(plugin: any): boolean {\n  return typeof plugin === 'function' || typeof plugin?.default === 'function';\n}\n\nfunction isES6(plugin: any): boolean {\n  return plugin && typeof plugin === 'object' && 'default' in plugin;\n}\n\n/**\n * Resolve the ESM entry point for a directory-based plugin.\n * import() doesn't support directory imports, so we resolve via package.json.\n */\nexport function resolveEntryPoint(dirPath: string): string {\n  const pkgPath = join(dirPath, 'package.json');\n  if (existsSync(pkgPath)) {\n    try {\n      const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n      if (pkg.exports) {\n        const dotExport = pkg.exports['.'];\n        if (typeof dotExport === 'string') {\n          return join(dirPath, dotExport);\n        }\n        if (dotExport?.import?.default) {\n          return join(dirPath, dotExport.import.default);\n        }\n        if (dotExport?.import && typeof dotExport.import === 'string') {\n          return join(dirPath, dotExport.import);\n        }\n        if (dotExport?.default) {\n          return join(dirPath, dotExport.default);\n        }\n      }\n      if (pkg.module) {\n        return join(dirPath, pkg.module);\n      }\n      if (pkg.main) {\n        return join(dirPath, pkg.main);\n      }\n    } catch {\n      // fall through\n    }\n  }\n  return join(dirPath, 'index.js');\n}\n\n/**\n * Try to load a module, falling back from require() to import() for ESM.\n * Handles CJS require(), ESM require() shim errors (bundlers), and\n * ERR_REQUIRE_ESM — always falls through to dynamic import() on any\n * require() failure.\n */\nasync function tryResolve(modulePath: string): Promise<{ module: any; error?: string }> {\n  // Try require() first (fast path for CJS modules)\n  try {\n    return { module: requireModule(modulePath) };\n  } catch (requireErr: any) {\n    debug('require() failed for %o: %s — trying dynamic import', modulePath, requireErr.message);\n  }\n\n  // Fallback to dynamic import() for ESM modules\n  try {\n    let importPath = modulePath;\n    if (existsSync(modulePath) && existsSync(join(modulePath, 'package.json'))) {\n      importPath = resolveEntryPoint(modulePath);\n      debug('resolved ESM entry point: %o', importPath);\n    }\n    const importUrl = importPath.startsWith('/') ? pathToFileURL(importPath).href : importPath;\n    const mod = await import(importUrl);\n    return { module: mod };\n  } catch (importErr: any) {\n    return { module: null, error: importErr.message };\n  }\n}\n\n/**\n * Runs step-by-step diagnostics to identify exactly which phase of\n * plugin loading fails. This replicates the same resolution logic\n * as `asyncLoadPlugin` but tests each step independently.\n */\nexport async function runDiagnostics(options: VerifyPluginOptions): Promise<DiagnosticStep[]> {\n  const {\n    pluginPath,\n    category,\n    pluginConfig = {},\n    sanityCheck: customSanityCheck,\n    prefix = PLUGIN_PREFIX,\n    pluginsFolder,\n  } = options;\n\n  const steps: DiagnosticStep[] = [];\n  const isScoped = pluginPath.startsWith('@') && pluginPath.includes('/');\n  const pluginName = isScoped ? pluginPath : `${prefix}-${pluginPath}`;\n\n  debug('running diagnostics for %o (resolved name: %o)', pluginPath, pluginName);\n\n  // --- Phase 1: Resolve ---\n  let pluginModule: any = null;\n  let resolvedFrom = '';\n\n  // Try plugins folder first\n  if (pluginsFolder) {\n    const absFolder = resolve(pluginsFolder);\n    const pluginDir = join(absFolder, pluginName);\n    debug('checking plugins folder: %o', pluginDir);\n\n    if (!existsSync(absFolder)) {\n      steps.push({\n        phase: 'resolve',\n        pass: false,\n        message: `Plugins folder does not exist: ${absFolder}`,\n      });\n      return steps;\n    }\n\n    if (!existsSync(pluginDir)) {\n      debug('plugin directory not found: %o', pluginDir);\n      steps.push({\n        phase: 'resolve',\n        pass: false,\n        message: `Plugin directory not found: ${pluginDir} — expected a folder named \"${pluginName}\" inside \"${absFolder}\"`,\n      });\n      return steps;\n    }\n\n    const result = await tryResolve(pluginDir);\n    if (result.module) {\n      pluginModule = result.module;\n      resolvedFrom = pluginDir;\n      debug('resolved from plugins folder: %o', pluginDir);\n    } else {\n      const missingDep = parseMissingDependency(result.error ?? '', pluginDir);\n      steps.push({\n        phase: 'resolve',\n        pass: false,\n        message: missingDep\n          ? `Plugin found at ${pluginDir} but has a missing dependency: ${missingDep}`\n          : `Plugin found at ${pluginDir} but failed to load: ${result.error}`,\n      });\n      return steps;\n    }\n  }\n\n  // Try node_modules if not found in plugins folder\n  if (!pluginModule) {\n    const result = await tryResolve(pluginName);\n    if (result.module) {\n      pluginModule = result.module;\n      resolvedFrom = pluginName;\n      debug('resolved from node_modules: %o', pluginName);\n    } else {\n      const missingDep = parseMissingDependency(result.error ?? '', pluginName);\n      steps.push({\n        phase: 'resolve',\n        pass: false,\n        message: missingDep\n          ? `Package \"${pluginName}\" found but has a missing dependency: ${missingDep}`\n          : `Package \"${pluginName}\" not found in node_modules — try: npm install ${pluginName}`,\n      });\n      return steps;\n    }\n  }\n\n  steps.push({\n    phase: 'resolve',\n    pass: true,\n    message: `Module resolved from ${resolvedFrom}`,\n  });\n\n  // --- Phase 2: Export validation ---\n  if (!isValidExport(pluginModule)) {\n    const exportKeys = pluginModule ? Object.keys(pluginModule).join(', ') : 'none';\n    steps.push({\n      phase: 'export',\n      pass: false,\n      message: `Module does not export a function or class (default export). Exported keys: [${exportKeys}]`,\n    });\n    return steps;\n  }\n\n  const moduleType = isES6(pluginModule) ? 'ES6 (default export)' : 'CommonJS (factory function)';\n  steps.push({\n    phase: 'export',\n    pass: true,\n    message: `Valid ${moduleType} plugin export detected`,\n  });\n\n  // --- Phase 3: Instantiation ---\n  let instance: any;\n  try {\n    if (isES6(pluginModule)) {\n      instance = new pluginModule.default(pluginConfig, { config: pluginConfig, logger: console });\n    } else {\n      instance = pluginModule(pluginConfig, { config: pluginConfig, logger: console });\n    }\n  } catch (err: any) {\n    steps.push({\n      phase: 'instantiate',\n      pass: false,\n      message: `Plugin threw during instantiation: ${err.message}`,\n    });\n    return steps;\n  }\n\n  if (!instance || (typeof instance !== 'object' && typeof instance !== 'function')) {\n    steps.push({\n      phase: 'instantiate',\n      pass: false,\n      message: `Plugin constructor/factory returned ${instance === null ? 'null' : typeof instance} instead of an object`,\n    });\n    return steps;\n  }\n\n  steps.push({\n    phase: 'instantiate',\n    pass: true,\n    message: 'Plugin instantiated successfully',\n  });\n\n  // --- Phase 4: Sanity check ---\n  const sanityCheck = customSanityCheck ?? getSanityCheck(category);\n  const passed = sanityCheck(instance);\n\n  if (!passed) {\n    const methods = Object.getOwnPropertyNames(Object.getPrototypeOf(instance) ?? {})\n      .filter((m) => m !== 'constructor')\n      .concat(Object.keys(instance));\n    const unique = [...new Set(methods)];\n\n    steps.push({\n      phase: 'sanity-check',\n      pass: false,\n      message: `Plugin does not implement the required methods for category \"${category}\". Available methods: [${unique.join(', ')}]`,\n    });\n    return steps;\n  }\n\n  steps.push({\n    phase: 'sanity-check',\n    pass: true,\n    message: `Plugin passes sanity check for category \"${category}\"`,\n  });\n\n  return steps;\n}\n\n/**\n * When a MODULE_NOT_FOUND error is about a transitive dependency\n * (not the plugin itself), extract the missing module name.\n */\nfunction parseMissingDependency(message: string, pluginPath: string): string | null {\n  const match = message.match(/Cannot find module '([^']+)'/);\n  if (match && match[1] && !match[1].includes(pluginPath)) {\n    return match[1];\n  }\n  return null;\n}\n"],"mappings":";;;;;;;;;;AAWA,IAAM,WAAA,GAAA,MAAA,SAAmB,uCAAuC;AAGhE,IAAM,iBAAA,GAAA,YAAA,eACJ,OAAO,eAAe,cAAc,aAAA,CAAA,EAAyB,GAC/D;AAEA,SAAS,cAAc,QAAsB;CAC3C,OAAO,OAAO,WAAW,cAAc,OAAO,QAAQ,YAAY;AACpE;AAEA,SAAS,MAAM,QAAsB;CACnC,OAAO,UAAU,OAAO,WAAW,YAAY,aAAa;AAC9D;;;;;AAMA,SAAgB,kBAAkB,SAAyB;CACzD,MAAM,WAAA,GAAA,UAAA,MAAe,SAAS,cAAc;CAC5C,KAAA,GAAA,QAAA,YAAe,OAAO,GACpB,IAAI;EACF,MAAM,MAAM,KAAK,OAAA,GAAA,QAAA,cAAmB,SAAS,OAAO,CAAC;EACrD,IAAI,IAAI,SAAS;GACf,MAAM,YAAY,IAAI,QAAQ;GAC9B,IAAI,OAAO,cAAc,UACvB,QAAA,GAAA,UAAA,MAAY,SAAS,SAAS;GAEhC,IAAI,WAAW,QAAQ,SACrB,QAAA,GAAA,UAAA,MAAY,SAAS,UAAU,OAAO,OAAO;GAE/C,IAAI,WAAW,UAAU,OAAO,UAAU,WAAW,UACnD,QAAA,GAAA,UAAA,MAAY,SAAS,UAAU,MAAM;GAEvC,IAAI,WAAW,SACb,QAAA,GAAA,UAAA,MAAY,SAAS,UAAU,OAAO;EAE1C;EACA,IAAI,IAAI,QACN,QAAA,GAAA,UAAA,MAAY,SAAS,IAAI,MAAM;EAEjC,IAAI,IAAI,MACN,QAAA,GAAA,UAAA,MAAY,SAAS,IAAI,IAAI;CAEjC,QAAQ,CAER;CAEF,QAAA,GAAA,UAAA,MAAY,SAAS,UAAU;AACjC;;;;;;;AAQA,eAAe,WAAW,YAA8D;CAEtF,IAAI;EACF,OAAO,EAAE,QAAQ,cAAc,UAAU,EAAE;CAC7C,SAAS,YAAiB;EACxB,QAAM,uDAAuD,YAAY,WAAW,OAAO;CAC7F;CAGA,IAAI;EACF,IAAI,aAAa;EACjB,KAAA,GAAA,QAAA,YAAe,UAAU,MAAA,GAAA,QAAA,aAAA,GAAA,UAAA,MAAqB,YAAY,cAAc,CAAC,GAAG;GAC1E,aAAa,kBAAkB,UAAU;GACzC,QAAM,gCAAgC,UAAU;EAClD;EAGA,OAAO,EAAE,QAAQ,OAFC,WAAW,WAAW,GAAG,IAAA,QAAA,GAAA,SAAA,eAAkB,UAAU,EAAE,QAAA,OAAO,aAE3D;CACvB,SAAS,WAAgB;EACvB,OAAO;GAAE,QAAQ;GAAM,OAAO,UAAU;EAAQ;CAClD;AACF;;;;;;AAOA,eAAsB,eAAe,SAAyD;CAC5F,MAAM,EACJ,YACA,UACA,eAAe,CAAC,GAChB,aAAa,mBACb,SAAS,gBAAA,eACT,kBACE;CAEJ,MAAM,QAA0B,CAAC;CAEjC,MAAM,aADW,WAAW,WAAW,GAAG,KAAK,WAAW,SAAS,GAAG,IACxC,aAAa,GAAG,OAAO,GAAG;CAExD,QAAM,kDAAkD,YAAY,UAAU;CAG9E,IAAI,eAAoB;CACxB,IAAI,eAAe;CAGnB,IAAI,eAAe;EACjB,MAAM,aAAA,GAAA,UAAA,SAAoB,aAAa;EACvC,MAAM,aAAA,GAAA,UAAA,MAAiB,WAAW,UAAU;EAC5C,QAAM,+BAA+B,SAAS;EAE9C,IAAI,EAAA,GAAA,QAAA,YAAY,SAAS,GAAG;GAC1B,MAAM,KAAK;IACT,OAAO;IACP,MAAM;IACN,SAAS,kCAAkC;GAC7C,CAAC;GACD,OAAO;EACT;EAEA,IAAI,EAAA,GAAA,QAAA,YAAY,SAAS,GAAG;GAC1B,QAAM,kCAAkC,SAAS;GACjD,MAAM,KAAK;IACT,OAAO;IACP,MAAM;IACN,SAAS,+BAA+B,UAAU,8BAA8B,WAAW,YAAY,UAAU;GACnH,CAAC;GACD,OAAO;EACT;EAEA,MAAM,SAAS,MAAM,WAAW,SAAS;EACzC,IAAI,OAAO,QAAQ;GACjB,eAAe,OAAO;GACtB,eAAe;GACf,QAAM,oCAAoC,SAAS;EACrD,OAAO;GACL,MAAM,aAAa,uBAAuB,OAAO,SAAS,IAAI,SAAS;GACvE,MAAM,KAAK;IACT,OAAO;IACP,MAAM;IACN,SAAS,aACL,mBAAmB,UAAU,iCAAiC,eAC9D,mBAAmB,UAAU,uBAAuB,OAAO;GACjE,CAAC;GACD,OAAO;EACT;CACF;CAGA,IAAI,CAAC,cAAc;EACjB,MAAM,SAAS,MAAM,WAAW,UAAU;EAC1C,IAAI,OAAO,QAAQ;GACjB,eAAe,OAAO;GACtB,eAAe;GACf,QAAM,kCAAkC,UAAU;EACpD,OAAO;GACL,MAAM,aAAa,uBAAuB,OAAO,SAAS,IAAI,UAAU;GACxE,MAAM,KAAK;IACT,OAAO;IACP,MAAM;IACN,SAAS,aACL,YAAY,WAAW,wCAAwC,eAC/D,YAAY,WAAW,iDAAiD;GAC9E,CAAC;GACD,OAAO;EACT;CACF;CAEA,MAAM,KAAK;EACT,OAAO;EACP,MAAM;EACN,SAAS,wBAAwB;CACnC,CAAC;CAGD,IAAI,CAAC,cAAc,YAAY,GAAG;EAChC,MAAM,aAAa,eAAe,OAAO,KAAK,YAAY,EAAE,KAAK,IAAI,IAAI;EACzE,MAAM,KAAK;GACT,OAAO;GACP,MAAM;GACN,SAAS,gFAAgF,WAAW;EACtG,CAAC;EACD,OAAO;CACT;CAEA,MAAM,aAAa,MAAM,YAAY,IAAI,yBAAyB;CAClE,MAAM,KAAK;EACT,OAAO;EACP,MAAM;EACN,SAAS,SAAS,WAAW;CAC/B,CAAC;CAGD,IAAI;CACJ,IAAI;EACF,IAAI,MAAM,YAAY,GACpB,WAAW,IAAI,aAAa,QAAQ,cAAc;GAAE,QAAQ;GAAc,QAAQ;EAAQ,CAAC;OAE3F,WAAW,aAAa,cAAc;GAAE,QAAQ;GAAc,QAAQ;EAAQ,CAAC;CAEnF,SAAS,KAAU;EACjB,MAAM,KAAK;GACT,OAAO;GACP,MAAM;GACN,SAAS,sCAAsC,IAAI;EACrD,CAAC;EACD,OAAO;CACT;CAEA,IAAI,CAAC,YAAa,OAAO,aAAa,YAAY,OAAO,aAAa,YAAa;EACjF,MAAM,KAAK;GACT,OAAO;GACP,MAAM;GACN,SAAS,uCAAuC,aAAa,OAAO,SAAS,OAAO,SAAS;EAC/F,CAAC;EACD,OAAO;CACT;CAEA,MAAM,KAAK;EACT,OAAO;EACP,MAAM;EACN,SAAS;CACX,CAAC;CAMD,IAAI,EAHgB,qBAAqB,sBAAA,eAAe,QAAQ,GACrC,QAEtB,GAAQ;EACX,MAAM,UAAU,OAAO,oBAAoB,OAAO,eAAe,QAAQ,KAAK,CAAC,CAAC,EAC7E,QAAQ,MAAM,MAAM,aAAa,EACjC,OAAO,OAAO,KAAK,QAAQ,CAAC;EAC/B,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC;EAEnC,MAAM,KAAK;GACT,OAAO;GACP,MAAM;GACN,SAAS,gEAAgE,SAAS,yBAAyB,OAAO,KAAK,IAAI,EAAE;EAC/H,CAAC;EACD,OAAO;CACT;CAEA,MAAM,KAAK;EACT,OAAO;EACP,MAAM;EACN,SAAS,4CAA4C,SAAS;CAChE,CAAC;CAED,OAAO;AACT;;;;;AAMA,SAAS,uBAAuB,SAAiB,YAAmC;CAClF,MAAM,QAAQ,QAAQ,MAAM,8BAA8B;CAC1D,IAAI,SAAS,MAAM,MAAM,CAAC,MAAM,GAAG,SAAS,UAAU,GACpD,OAAO,MAAM;CAEf,OAAO;AACT"}