{"version":3,"file":"printResult-oXnpZu_9.mjs","names":[],"sources":["../src/commands/policy/helpers/buildPolicyEngineClient.ts","../src/commands/policy/helpers/formatPolicyEngineRequestError.ts","../src/commands/policy/helpers/printResult.ts"],"sourcesContent":["import got, { type Got } from 'got';\n\n/**\n * Creates a got client for Policy Engine REST endpoints on the monolith.\n *\n * The CLI appends `v1/...` paths to this base URL, so callers must NOT include\n * a trailing `/v1` (that would produce `/v1/v1/...` and an opaque `400`). We\n * detect and reject that mistake with a clear hint.\n *\n * @param transcendUrl - Transcend API base URL (without `/v1`)\n * @param auth - Transcend API key\n * @returns Configured got instance\n */\nexport function buildPolicyEngineClient(transcendUrl: string, auth: string): Got {\n  const normalized = transcendUrl.replace(/\\/$/, '');\n  if (/(^|\\/)v1$/i.test(normalized)) {\n    throw new Error(\n      `--transcend-url must not include a trailing \"/v1\" (the CLI appends it automatically). ` +\n        `Got \"${transcendUrl}\"; use \"${normalized.replace(/\\/v1$/i, '')}\" instead.`,\n    );\n  }\n  return got.extend({\n    prefixUrl: normalized,\n    headers: {\n      Authorization: `Bearer ${auth}`,\n      accept: 'application/json',\n    },\n  });\n}\n","import { PolicyEngineCliError } from './policyEngineCliError.js';\n\n/** Parsed JSON error body from a Policy Engine API response. */\ninterface PolicyEngineErrorBody {\n  /** Human-readable error message */\n  message?: string;\n}\n\n/** HTTP response metadata on a got HTTPError. */\ninterface PolicyEngineHttpResponse {\n  /** HTTP status code */\n  statusCode?: number;\n  /** Response body (JSON or raw text) */\n  body?: unknown;\n  /** Response headers */\n  headers?: Record<string, string | string[] | undefined>;\n}\n\n/** Shape of a got HTTPError with response metadata. */\ninterface PolicyEngineHttpError {\n  /** HTTP response metadata */\n  response?: PolicyEngineHttpResponse;\n}\n\nconst AUTH_ERROR_MESSAGE = `Authentication failed (401 Unauthorized).\n\nYour Transcend API key is missing, invalid, or does not have permission for this command.\n\nFix:\n- Set a valid API key: export TRANSCEND_API_KEY=<your-key>\n  or pass --auth=<your-key>\n- Ensure the key has the required Policy Engine scopes (e.g. View/Manage/Activate Policy)\n- Confirm you are pointing at the correct environment (--transcend-url)`;\n\nconst NOT_FOUND_MESSAGE = `Resource not found (404 Not Found).\n\nThe requested policy bundle or version does not exist.\n\nFix:\n- Check the --bundle-name value\n- Run \\`transcend policy bundles\\` to see available bundles\n- Run \\`transcend policy versions --bundle-name=<name>\\` to see available versions`;\n\nconst PAYLOAD_TOO_LARGE_MESSAGE = `Policy bundle upload is too large (413 Payload Too Large).\n\nUploaded bundles must be at most 5 KiB compressed and 50 KiB decompressed gzip tarballs containing only manifest.json and .rego files.\n\nFix:\n- Remove unnecessary files from the bundle directory before publishing\n- Ensure the compiled .tar.gz stays within the upload limits`;\n\nconst NETWORK_ERROR_MESSAGE = `Connection to Transcend failed.\n\nThe Policy Engine API could not be reached.\n\nFix:\n- Check your network connection\n- Confirm --transcend-url points at the correct environment\n- Retry the command in a few moments`;\n\n/**\n * Extracts a human-readable message from a Policy Engine API error body.\n *\n * @param body - Raw or parsed response body\n * @returns API message when present\n */\nfunction extractApiMessage(body: unknown): string | undefined {\n  if (typeof body === 'string') {\n    try {\n      const parsed = JSON.parse(body) as PolicyEngineErrorBody;\n      return parsed.message;\n    } catch {\n      return body.length > 0 ? body : undefined;\n    }\n  }\n\n  if (body && typeof body === 'object' && 'message' in body) {\n    const message = (body as PolicyEngineErrorBody).message;\n    if (typeof message === 'string' && message.length > 0) {\n      return message;\n    }\n  }\n\n  return undefined;\n}\n\n/**\n * Reads a single response header value.\n *\n * @param headers - Response headers\n * @param name - Header name\n * @returns Header value when present\n */\nfunction readResponseHeader(\n  headers: Record<string, string | string[] | undefined> | undefined,\n  name: string,\n): string | undefined {\n  if (!headers) {\n    return undefined;\n  }\n\n  const value = headers[name] ?? headers[name.toLowerCase()];\n  if (Array.isArray(value)) {\n    return value[0];\n  }\n\n  return value;\n}\n\n/**\n * Builds a rate-limit error message using response headers when available.\n *\n * @param apiMessage - Message from the response body, when present\n * @param headers - Response headers\n * @returns User-readable rate-limit text\n */\nfunction formatRateLimitMessage(\n  apiMessage: string | undefined,\n  headers: Record<string, string | string[] | undefined> | undefined,\n): string {\n  if (apiMessage) {\n    return apiMessage;\n  }\n\n  const retryAfter = readResponseHeader(headers, 'retry-after');\n  const resetAt = readResponseHeader(headers, 'x-ratelimit-reset');\n\n  let message = `Rate limit exceeded (429 Too Many Requests).\n\nFix:\n- Wait and retry the command`;\n\n  if (retryAfter) {\n    message += `\\n- Retry after ${retryAfter} second(s)`;\n  } else if (resetAt) {\n    message += `\\n- Retry after ${resetAt}`;\n  }\n\n  return message;\n}\n\n/**\n * Maps common HTTP status codes to actionable CLI messages.\n *\n * @param statusCode - HTTP status code\n * @param apiMessage - Message from the API response body, when present\n * @param headers - Response headers\n * @returns User-readable error text\n */\nfunction formatHttpStatusError(\n  statusCode: number,\n  apiMessage?: string,\n  headers?: Record<string, string | string[] | undefined>,\n): string {\n  switch (statusCode) {\n    case 401:\n      return AUTH_ERROR_MESSAGE;\n    case 403:\n      return (\n        apiMessage ??\n        'Access was denied (403 Forbidden). If this persists, contact your Transcend admin.'\n      );\n    case 404:\n      return NOT_FOUND_MESSAGE;\n    case 400:\n      return apiMessage ?? 'The request was invalid. Check your command flags and try again.';\n    case 409:\n      return apiMessage ?? 'The request conflicted with the current policy bundle state.';\n    case 413:\n      return apiMessage ?? PAYLOAD_TOO_LARGE_MESSAGE;\n    case 429:\n      return formatRateLimitMessage(apiMessage, headers);\n    default:\n      if (statusCode >= 500) {\n        return `Transcend server error (${statusCode}). Try again in a few moments. If the problem persists, contact Transcend support.`;\n      }\n      return apiMessage ?? `Request failed with status code ${statusCode}.`;\n  }\n}\n\n/**\n * Returns true when the error looks like a network or timeout failure.\n *\n * @param error - Thrown error\n * @returns Whether the error is likely a connectivity issue\n */\nfunction isNetworkError(error: unknown): boolean {\n  if (!(error instanceof Error)) {\n    return false;\n  }\n\n  const code = (error as NodeJS.ErrnoException).code;\n  if (\n    code === 'ECONNREFUSED' ||\n    code === 'ENOTFOUND' ||\n    code === 'ETIMEDOUT' ||\n    code === 'ECONNRESET'\n  ) {\n    return true;\n  }\n\n  const message = error.message.toLowerCase();\n  return (\n    message.includes('network') ||\n    message.includes('timeout') ||\n    message.includes('econnrefused') ||\n    message.includes('enotfound') ||\n    message.includes('etimedout')\n  );\n}\n\n/**\n * Extracts a useful error message from a failed Policy Engine HTTP request.\n *\n * @param error - The thrown error, typically a got `HTTPError`\n * @returns A message suitable for CLI output\n */\nexport function formatPolicyEngineRequestError(error: unknown): string {\n  if (isNetworkError(error)) {\n    return NETWORK_ERROR_MESSAGE;\n  }\n\n  if (error && typeof error === 'object' && 'response' in error) {\n    const response = (error as PolicyEngineHttpError).response;\n    const statusCode = response?.statusCode;\n    const apiMessage = extractApiMessage(response?.body);\n\n    if (statusCode) {\n      return formatHttpStatusError(statusCode, apiMessage, response?.headers);\n    }\n\n    if (apiMessage) {\n      return apiMessage;\n    }\n  }\n\n  return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * Rethrows a Policy Engine request failure with a user-readable message.\n *\n * @param error - The thrown error, typically a got `HTTPError`\n */\nexport function throwPolicyEngineRequestError(error: unknown): never {\n  throw new PolicyEngineCliError(formatPolicyEngineRequestError(error), { cause: error });\n}\n\n/**\n * Awaits a Policy Engine HTTP request and maps failures to user-readable errors.\n *\n * @param request - Promise returned by a got client call (e.g. `.json()`)\n * @returns Parsed response body\n */\nexport async function policyEngineRequest<T>(request: Promise<T>): Promise<T> {\n  try {\n    return await request;\n  } catch (error) {\n    throwPolicyEngineRequestError(error);\n  }\n}\n","/** Options for printing CLI command output. */\nexport interface PrintResultOptions {\n  /** When true, print raw JSON */\n  json: boolean;\n  /** JSON-serializable payload */\n  data: unknown;\n  /** Table renderer used when json is false */\n  renderTable?: () => string;\n}\n\n/**\n * Prints JSON or a human-readable table to stdout.\n *\n * @param stdout - Process stdout stream\n * @param options - Output options\n */\nexport function printResult(stdout: NodeJS.WriteStream, options: PrintResultOptions): void {\n  if (options.json) {\n    stdout.write(`${JSON.stringify(options.data, null, 2)}\\n`);\n    return;\n  }\n\n  if (options.renderTable) {\n    stdout.write(`${options.renderTable()}\\n`);\n  }\n}\n"],"mappings":"2EAaA,SAAgB,EAAwB,EAAsB,EAAmB,CAC/E,IAAM,EAAa,EAAa,QAAQ,MAAO,GAAG,CAClD,GAAI,aAAa,KAAK,EAAW,CAC/B,MAAU,MACR,8FACU,EAAa,UAAU,EAAW,QAAQ,SAAU,GAAG,CAAC,YACnE,CAEH,OAAO,EAAI,OAAO,CAChB,UAAW,EACX,QAAS,CACP,cAAe,UAAU,IACzB,OAAQ,mBACT,CACF,CAAC,CCuCJ,SAAS,EAAkB,EAAmC,CAC5D,GAAI,OAAO,GAAS,SAClB,GAAI,CAEF,OADe,KAAK,MAAM,EACb,CAAC,aACR,CACN,OAAO,EAAK,OAAS,EAAI,EAAO,IAAA,GAIpC,GAAI,GAAQ,OAAO,GAAS,UAAY,YAAa,EAAM,CACzD,IAAM,EAAW,EAA+B,QAChD,GAAI,OAAO,GAAY,UAAY,EAAQ,OAAS,EAClD,OAAO,GAcb,SAAS,EACP,EACA,EACoB,CACpB,GAAI,CAAC,EACH,OAGF,IAAM,EAAQ,EAAQ,IAAS,EAAQ,EAAK,aAAa,EAKzD,OAJI,MAAM,QAAQ,EAAM,CACf,EAAM,GAGR,EAUT,SAAS,EACP,EACA,EACQ,CACR,GAAI,EACF,OAAO,EAGT,IAAM,EAAa,EAAmB,EAAS,cAAc,CACvD,EAAU,EAAmB,EAAS,oBAAoB,CAE5D,EAAU;;;8BAWd,OANI,EACF,GAAW,mBAAmB,EAAW,YAChC,IACT,GAAW,mBAAmB,KAGzB,EAWT,SAAS,EACP,EACA,EACA,EACQ,CACR,OAAQ,EAAR,CACE,IAAK,KACH,MAAO;;;;;;;;yEACT,IAAK,KACH,OACE,GACA,qFAEJ,IAAK,KACH,MAAO;;;;;;;oFACT,IAAK,KACH,OAAO,GAAc,mEACvB,IAAK,KACH,OAAO,GAAc,+DACvB,IAAK,KACH,OAAO,GAAc;;;;;;8DACvB,IAAK,KACH,OAAO,EAAuB,EAAY,EAAQ,CACpD,QAIE,OAHI,GAAc,IACT,2BAA2B,EAAW,oFAExC,GAAc,mCAAmC,EAAW,IAUzE,SAAS,EAAe,EAAyB,CAC/C,GAAI,EAAE,aAAiB,OACrB,MAAO,GAGT,IAAM,EAAQ,EAAgC,KAC9C,GACE,IAAS,gBACT,IAAS,aACT,IAAS,aACT,IAAS,aAET,MAAO,GAGT,IAAM,EAAU,EAAM,QAAQ,aAAa,CAC3C,OACE,EAAQ,SAAS,UAAU,EAC3B,EAAQ,SAAS,UAAU,EAC3B,EAAQ,SAAS,eAAe,EAChC,EAAQ,SAAS,YAAY,EAC7B,EAAQ,SAAS,YAAY,CAUjC,SAAgB,EAA+B,EAAwB,CACrE,GAAI,EAAe,EAAM,CACvB,MAAO;;;;;;;sCAGT,GAAI,GAAS,OAAO,GAAU,UAAY,aAAc,EAAO,CAC7D,IAAM,EAAY,EAAgC,SAC5C,EAAa,GAAU,WACvB,EAAa,EAAkB,GAAU,KAAK,CAEpD,GAAI,EACF,OAAO,EAAsB,EAAY,EAAY,GAAU,QAAQ,CAGzE,GAAI,EACF,OAAO,EAIX,OAAO,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,CAQ/D,SAAgB,EAA8B,EAAuB,CACnE,MAAM,IAAI,EAAqB,EAA+B,EAAM,CAAE,CAAE,MAAO,EAAO,CAAC,CASzF,eAAsB,EAAuB,EAAiC,CAC5E,GAAI,CACF,OAAO,MAAM,QACN,EAAO,CACd,EAA8B,EAAM,EClPxC,SAAgB,EAAY,EAA4B,EAAmC,CACzF,GAAI,EAAQ,KAAM,CAChB,EAAO,MAAM,GAAG,KAAK,UAAU,EAAQ,KAAM,KAAM,EAAE,CAAC,IAAI,CAC1D,OAGE,EAAQ,aACV,EAAO,MAAM,GAAG,EAAQ,aAAa,CAAC,IAAI"}