{"version":3,"sources":["../../src/services/BaseService.ts"],"sourcesContent":["import * as https from 'https';\nimport * as http from 'http';\nimport { getCollectorString, CollectionMethod } from '../utils/collector.js';\n\nexport interface BaseServiceConfig {\n  apiKey: string;\n  silent: boolean;\n  debug?: boolean;\n  dryRun?: boolean;\n  baseUrl?: string;\n}\n\nfunction validateBaseUrl(raw: string): void {\n  let url: URL;\n  try {\n    url = new URL(raw);\n  } catch {\n    throw new Error(`Invalid baseUrl: \"${raw}\" is not a valid URL`);\n  }\n  if (!url.hostname) {\n    throw new Error(`baseUrl must include a hostname. Got: \"${raw}\"`);\n  }\n  if (url.protocol === 'https:') { return; }\n  if (url.protocol === 'http:') {\n    const h = url.hostname;\n    if (h === 'localhost' || h === '127.0.0.1' || h === '[::1]') { return; }\n  }\n  throw new Error(\n    `baseUrl must use https:// (got: \"${raw}\"). For local dev, http://localhost is allowed.`\n  );\n}\n\nfunction normalizeBaseUrl(raw: string): string {\n  return raw.replace(/\\/+$/, '');\n}\n\n/**\n * Thrown by {@link BaseService.fetchWithHeaders} on a non-2xx response. Carries the HTTP `status`\n * so callers (e.g. the CLI) can react to it — a 401 vs. a 404 — without parsing the message string.\n */\nexport class HttpError extends Error {\n  constructor(\n    message: string,\n    public readonly status: number\n  ) {\n    super(message);\n    this.name = 'HttpError';\n  }\n}\n\nexport abstract class BaseService {\n  protected apiKey: string;\n  protected silent: boolean;\n  protected debug: boolean;\n  protected dryRun: boolean;\n  protected apiEndpoint: string;\n\n  constructor(config: BaseServiceConfig, endpointPath: string) {\n    this.apiKey = config.apiKey;\n    this.silent = config.silent;\n    this.debug = config.debug || false;\n    this.dryRun = config.dryRun || false;\n\n    const rawBase = config.baseUrl ?? 'https://coolhandlabs.com';\n    validateBaseUrl(rawBase);\n    this.apiEndpoint = normalizeBaseUrl(rawBase) + endpointPath;\n  }\n\n  protected createRequestOptions(payload: any): RequestInit {\n    return {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        'X-API-Key': this.apiKey\n      },\n      body: JSON.stringify(payload)\n    };\n  }\n\n  protected addCollectorToData<T extends Record<string, any>>(\n    data: T,\n    collectionMethod?: CollectionMethod\n  ): T & { collector: string } {\n    return {\n      ...data,\n      collector: getCollectorString(collectionMethod)\n    };\n  }\n\n  protected async sendRequest<T>(payload: any, successMessage: string): Promise<T | null> {\n    if (this.dryRun) {\n      if (!this.silent) {\n        console.log(`🚫 DRY RUN: Skipping API call to ${this.apiEndpoint}`);\n        console.log(`🚫 DRY RUN: Would send payload:`, JSON.stringify(payload, null, 2));\n      }\n      this.log(`🚫 DRY RUN: ${successMessage.replace('✅', '🚫')}`);\n      return null;\n    }\n\n    if (this.debug && !this.silent) {\n      console.log(`[coolhand-node] DEBUG: Sending to ${this.apiEndpoint}`);\n      console.log(`[coolhand-node] DEBUG: Payload size: ${JSON.stringify(payload).length} bytes`);\n    }\n\n    const requestOptions = this.createRequestOptions(payload);\n\n    try {\n      if (typeof fetch !== 'undefined') {\n        const response = await fetch(this.apiEndpoint, requestOptions);\n        return await this.parseJsonResponse<T>(response, successMessage);\n      } else {\n        // Fallback to using https/http modules\n        await this.sendWithHTTPS(payload);\n        this.log(successMessage);\n        return null; // HTTPS fallback doesn't return parsed response\n      }\n    } catch (error) {\n      console.error(`❌ Request error:`, (error as Error).message);\n      return null;\n    }\n  }\n\n  /**\n   * Shared success/failure handling for a `fetch` response, used by both {@link sendRequest} and\n   * {@link sendMultipart}: JSON-parse and log on 2xx, log and resolve to `null` otherwise.\n   */\n  private async parseJsonResponse<T>(response: Response, successMessage: string): Promise<T | null> {\n    if (response.ok) {\n      const result = await response.json() as T;\n      this.log(successMessage);\n      return result;\n    } else {\n      const errorText = await response.text();\n      console.error(`❌ Request failed: ${response.status} - ${errorText}`);\n      return null;\n    }\n  }\n\n  /**\n   * POST a `FormData` body (multipart/form-data) — the upload counterpart to {@link sendRequest}.\n   * Omits `Content-Type` so `fetch` sets the multipart boundary itself. There is no\n   * `sendWithHTTPS`-style fallback for multipart, so this throws when global `fetch` is\n   * unavailable rather than silently returning `null`, which would otherwise be indistinguishable\n   * from a normal API failure. Non-2xx responses and network errors follow {@link sendRequest}'s\n   * convention instead: logged and resolved to `null`.\n   *\n   * @throws Error if global `fetch` is unavailable (requires Node.js 18+).\n   */\n  protected async sendMultipart<T>(formData: FormData, successMessage: string): Promise<T | null> {\n    if (this.dryRun) {\n      if (!this.silent) {\n        console.log(`🚫 DRY RUN: Skipping API call to ${this.apiEndpoint}`);\n      }\n      this.log(`🚫 DRY RUN: ${successMessage.replace('✅', '🚫')}`);\n      return null;\n    }\n\n    if (this.debug && !this.silent) {\n      console.log(`[coolhand-node] DEBUG: Sending multipart to ${this.apiEndpoint}`);\n    }\n\n    if (typeof fetch === 'undefined') {\n      throw new Error(`Upload failed: global fetch is unavailable (requires Node.js 18+)`);\n    }\n\n    try {\n      const response = await fetch(this.apiEndpoint, {\n        method: 'POST',\n        headers: { 'X-API-Key': this.apiKey },\n        body: formData\n      });\n\n      return await this.parseJsonResponse<T>(response, successMessage);\n    } catch (error) {\n      console.error(`❌ Request error:`, (error as Error).message);\n      return null;\n    }\n  }\n\n  private async sendWithHTTPS(payload: any): Promise<void> {\n    return new Promise((resolve, reject) => {\n      const url = new URL(this.apiEndpoint);\n      const postData = JSON.stringify(payload);\n\n      const options = {\n        hostname: url.hostname,\n        port: url.port || (url.protocol === 'https:' ? 443 : 80),\n        path: url.pathname,\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n          'Content-Length': Buffer.byteLength(postData),\n          'X-API-Key': this.apiKey\n        }\n      };\n\n      const req = (url.protocol === 'https:' ? https : http).request(options, (res) => {\n        let data = '';\n        res.on('data', (chunk) => data += chunk);\n        res.on('end', () => {\n          if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {\n            resolve();\n          } else {\n            console.error(`❌ Request failed: ${res.statusCode} - ${data}`);\n            reject(new Error(`HTTP ${res.statusCode}: ${data}`));\n          }\n        });\n      });\n\n      req.on('error', reject);\n      req.write(postData);\n      req.end();\n    });\n  }\n\n  /**\n   * Fetch `url` and return the raw response body text plus headers, throwing on failure. The\n   * shared fetch/error/status-throwing primitive both {@link fetchOrThrow} (discards the headers)\n   * and {@link getJsonWithHeaders} (JSON-parses the body, keeps the headers — e.g. for\n   * `LoggingService#searchLogs` reading pagination totals off X-Total-Count/etc.) sit on top of.\n   *\n   * @param errorPrefix Prefixes thrown error messages, e.g. `\"MCP request failed\"` or\n   *   `\"Feedback request failed\"`, so each caller keeps its own established message wording.\n   * @throws Error if global `fetch` is unavailable (Node.js < 18) or on a network failure.\n   *   {@link HttpError} (with `.status`) on a non-2xx response.\n   */\n  protected async fetchWithHeaders(\n    url: string,\n    init: RequestInit,\n    errorPrefix: string\n  ): Promise<{ text: string; headers: Headers }> {\n    if (typeof fetch === 'undefined') {\n      throw new Error(`${errorPrefix}: global fetch is unavailable (requires Node.js 18+)`);\n    }\n\n    let res: Response;\n    try {\n      res = await fetch(url, init);\n    } catch (err) {\n      throw new Error(`${errorPrefix}: ${(err as Error).message}`, { cause: err });\n    }\n\n    const text = await res.text().catch(() => '');\n    if (!res.ok) {\n      throw new HttpError(`${errorPrefix} (${res.status}): ${text.slice(0, 2000)}`, res.status);\n    }\n    return { text, headers: res.headers };\n  }\n\n  /**\n   * Fetch `url` and return the raw response body text, throwing on failure. A thin wrapper around\n   * {@link fetchWithHeaders} for callers that don't need response headers — currently just\n   * `McpService.mcpCall` (as opposed to {@link sendRequest}'s POST/null-on-error convention).\n   *\n   * @param errorPrefix Prefixes thrown error messages, e.g. `\"MCP request failed\"`, so each\n   *   caller keeps its own established message wording.\n   * @throws Error if global `fetch` is unavailable (Node.js < 18) or on a network failure.\n   *   {@link HttpError} (with `.status`) on a non-2xx response.\n   */\n  protected async fetchOrThrow(url: string, init: RequestInit, errorPrefix: string): Promise<string> {\n    const { text } = await this.fetchWithHeaders(url, init, errorPrefix);\n    return text;\n  }\n\n  /**\n   * GET `url` and JSON-parse the response body, throwing on failure — the shared read-path used\n   * by `FeedbackService`/`LoggingService`'s search/get methods (as opposed to {@link sendRequest}'s\n   * POST/null-on-error convention).\n   *\n   * @param noun Capitalized noun identifying the caller, e.g. `\"Feedback\"` or `\"Log\"` — produces\n   *   `\"<noun> request failed (<status>): ...\"` and `\"<noun> response was not valid JSON: ...\"`\n   *   so each caller keeps its own established message wording.\n   * @throws Error on network failure or a non-JSON body. {@link HttpError} (with `.status`) on a\n   *   non-2xx response.\n   */\n  protected async getJson<T>(url: string, noun: string): Promise<T> {\n    const { body } = await this.getJsonWithHeaders<T>(url, noun);\n    return body;\n  }\n\n  /**\n   * Like {@link getJson}, but also returns the response headers — for endpoints (e.g.\n   * searchLogs) that expose metadata like pagination totals via X-Total-Count/etc. headers\n   * rather than the response body.\n   *\n   * @throws Error on network failure or a non-JSON body. {@link HttpError} (with `.status`) on a\n   *   non-2xx response.\n   */\n  protected async getJsonWithHeaders<T>(url: string, noun: string): Promise<{ body: T; headers: Headers }> {\n    const { text, headers } = await this.fetchWithHeaders(\n      url,\n      { method: 'GET', headers: { Accept: 'application/json', 'X-API-Key': this.apiKey } },\n      `${noun} request failed`\n    );\n\n    try {\n      return { body: JSON.parse(text) as T, headers };\n    } catch {\n      throw new Error(`${noun} response was not valid JSON: ${text.slice(0, 2000)}`);\n    }\n  }\n\n  /**\n   * Build `${this.apiEndpoint}/${id}` as a `URL` for a single-resource GET, guarding against\n   * inputs that WHATWG `URL` parsing would resolve away rather than treat as a path segment:\n   * blank/whitespace-only strings, and dot-segments (`.`/`..`) — `encodeURIComponent` doesn't\n   * escape `.`, so `new URL(...)` still collapses them, silently retargeting the request to this\n   * resource's own `index` route (or, for `..`, an unrelated path entirely) instead of 404ing.\n   * Verifies the built URL's `pathname` still ends with the exact encoded `id` to catch both.\n   *\n   * @param errorMessage Thrown verbatim on a rejected `id`, e.g.\n   *   `\"getFeedback: id must be a non-empty string\"`, so each caller keeps its own wording.\n   * @throws Error if `id` is blank, not a string, or resolves away via dot-segments.\n   */\n  protected buildResourceUrl(id: string, errorMessage: string): URL {\n    if (typeof id !== 'string' || id.trim() === '') {\n      throw new Error(errorMessage);\n    }\n    const encodedId = encodeURIComponent(id);\n    const url = new URL(`${this.apiEndpoint}/${encodedId}`);\n    if (!url.pathname.endsWith(`/${encodedId}`)) {\n      throw new Error(errorMessage);\n    }\n    return url;\n  }\n\n  protected log(...args: any[]): void {\n    if (!this.silent) {\n      console.log(...args);\n    }\n  }\n\n  protected logSeparator(): void {\n    if (!this.silent) {\n      console.log('═'.repeat(60));\n    }\n  }\n\n  public getApiEndpoint(): string {\n    return this.apiEndpoint;\n  }\n}"],"mappings":"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","names":[]}