{"version":3,"file":"declaredApi.cjs","names":["path","fs","isDoomApi","declaredApisOf"],"sources":["../../../src/adapters/testing/declaredApi.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { declaredApisOf, type DoomApi, type DoomApiScope, isDoomApi } from '../../schemas/packageApi.ts';\n\n/**\n * The one thing about a package API that only a running test can check.\n *\n * Vibe-Lint already reads the manifest statically: it proves the base path is\n * kebab-case, that the declared entry exists, that it exports `api`, and that\n * the built entry is in the files allowlist (`packageApiManifest`,\n * `packageApiEntry`). None of that reads the value, so none of it notices when\n * the routes and the manifest stop agreeing about where they are mounted.\n *\n * That disagreement is silent and total: `doompi sync` generates the route\n * module from the manifest, every client URL is built from the manifest, and\n * the routes answer under a different prefix, so nothing lands. The package's\n * own tests keep passing, because they call the app directly.\n *\n * The caller imports its own `api` normally and hands it over, so this needs\n * neither a dynamic import nor a build of the package under test.\n */\n\nexport interface DeclaredApiReport {\n  basePath: string;\n  scope: DoomApiScope;\n  /** The built module a host would import, as the manifest names it. */\n  dist: string;\n}\n\nexport interface DeclaredApiExpectation {\n  /** The package directory holding the package.json that declares the API. */\n  packageRoot: string;\n  /** The `api` this package exports from its declared entry. */\n  api: DoomApi;\n  scope: DoomApiScope;\n}\n\n/**\n * Asserts the manifest and the routes agree, and reports what a host would mount.\n *\n * Throws rather than returning a verdict: each failure names the one thing to\n * fix, which is more use than a boolean to whoever reads it.\n */\nexport function assertDeclaredApi(expectation: DeclaredApiExpectation): DeclaredApiReport {\n  const { api, packageRoot, scope } = expectation;\n  const manifestPath = path.join(packageRoot, 'package.json');\n  const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as Record<string, unknown>;\n  const packageName = typeof manifest.name === 'string' ? manifest.name : packageRoot;\n\n  if (!isDoomApi(api)) {\n    throw new Error(\n      `${packageName} exported something that is not a DoomApi: it needs a non-empty basePath and a start().`,\n    );\n  }\n  const declared = declaredApisOf(packageRoot, manifest);\n  const block = declared.find((candidate) => candidate[scope] !== undefined);\n  if (!block) {\n    throw new Error(\n      `${packageName} declares no ${scope} API in its doompiApi manifest, so no host of that scope mounts these routes.`,\n    );\n  }\n  if (block.basePath !== api.basePath) {\n    throw new Error(\n      `${packageName} serves '${api.basePath}' but its manifest mounts the ${scope} API at '${block.basePath}'. ` +\n        'Every client URL is built from the manifest, so no request would reach these routes.',\n    );\n  }\n  return { basePath: block.basePath, scope, dist: block[scope]?.dist ?? '' };\n}\n"],"mappings":"wLA2CA,SAAgB,EAAkB,EAAwD,CACxF,GAAM,CAAE,MAAK,cAAa,SAAU,EAC9B,EAAeA,EAAAA,QAAK,KAAK,EAAa,cAAc,EACpD,EAAW,KAAK,MAAMC,EAAAA,QAAG,aAAa,EAAc,MAAM,CAAC,EAC3D,EAAc,OAAO,EAAS,MAAS,SAAW,EAAS,KAAO,EAExE,GAAI,CAACC,EAAAA,UAAU,CAAG,EAChB,MAAU,MACR,GAAG,EAAY,wFACjB,EAGF,IAAM,EADWC,EAAAA,eAAe,EAAa,CACxB,CAAC,CAAC,KAAM,GAAc,EAAU,KAAW,IAAA,EAAS,EACzE,GAAI,CAAC,EACH,MAAU,MACR,GAAG,EAAY,eAAe,EAAM,8EACtC,EAEF,GAAI,EAAM,WAAa,EAAI,SACzB,MAAU,MACR,GAAG,EAAY,WAAW,EAAI,SAAS,gCAAgC,EAAM,WAAW,EAAM,SAAS,wFAEzG,EAEF,MAAO,CAAE,SAAU,EAAM,SAAU,QAAO,KAAM,EAAM,EAAM,EAAE,MAAQ,EAAG,CAC3E"}