// dist/embeddings/src/index.js
import { createServer } from "node:http";

// dist/src/shared/constants.js
var HONEYCOMB_VERSION = true ? "0.22.0" : "0.0.0-dev";

// dist/embeddings/src/index.js
var EMBED_DIMS = 768;
var MODEL_ID = "nomic-ai/nomic-embed-text-v1.5";
var MODEL_REVISION = "e9b6763023c676ca8431644204f50c2b100d9aab";
var MODEL_QUANTIZATION = "q8";
var DOCUMENT_PREFIX = "search_document: ";
var EMBED_HOST = "127.0.0.1";
var EMBED_PORT = 3851;
function resolveEmbedPort(override, rawEnvPort) {
  if (override !== void 0)
    return override;
  if (rawEnvPort === void 0 || rawEnvPort.trim().length === 0)
    return EMBED_PORT;
  const envPort = Number(rawEnvPort);
  return Number.isInteger(envPort) && envPort >= 0 && envPort < 65536 ? envPort : EMBED_PORT;
}
function embedDaemonInfo() {
  return { version: HONEYCOMB_VERSION, model: MODEL_ID, revision: MODEL_REVISION, dims: EMBED_DIMS };
}
function modelCacheDir(env = process.env) {
  const override = env.HONEYCOMB_EMBED_CACHE_DIR;
  if (override !== void 0 && override.length > 0)
    return override;
  const home = env.HOME ?? env.USERPROFILE ?? process.cwd();
  return `${home}/.honeycomb/embed-models`;
}
var loadTransformers = async () => {
  const moduleSpecifier = "@huggingface/transformers";
  const dynamicImport = new Function("m", "return import(m);");
  return await dynamicImport(moduleSpecifier);
};
var extractor = null;
var warming = null;
async function warmup(env = process.env) {
  if (extractor !== null)
    return;
  if (warming !== null)
    return warming;
  warming = (async () => {
    const transformers = await loadTransformers();
    transformers.env.cacheDir = modelCacheDir(env);
    if ((env.HONEYCOMB_EMBED_OFFLINE ?? "").trim().length > 0) {
      transformers.env.allowRemoteModels = false;
    }
    extractor = await transformers.pipeline("feature-extraction", MODEL_ID, {
      revision: MODEL_REVISION,
      dtype: MODEL_QUANTIZATION
    });
    await extractor(DOCUMENT_PREFIX + "warmup", { pooling: "mean", normalize: true });
  })();
  try {
    await warming;
  } finally {
    warming = null;
  }
}
async function embed(text, env = process.env) {
  if (extractor === null)
    await warmup(env);
  if (extractor === null)
    throw new Error("embed model not available");
  const out = await extractor(DOCUMENT_PREFIX + text, { pooling: "mean", normalize: true });
  const vector = Array.from(out.data);
  if (vector.length !== EMBED_DIMS) {
    throw new Error(`embed dim mismatch: expected ${EMBED_DIMS}, got ${vector.length}`);
  }
  return vector;
}
var WARM_ERROR_MAX = 300;
function redactWarmError(err) {
  const raw = err instanceof Error ? err.message : typeof err === "string" ? err : "warmup failed";
  const redacted = raw.replace(/\bhf_[A-Za-z0-9]+/g, "[redacted]").replace(/(authorization|bearer|token|api[_-]?key|secret|password)\s*[:=]\s*\S+/gi, "$1=[redacted]").replace(/\s+/g, " ").trim();
  return redacted.length > WARM_ERROR_MAX ? `${redacted.slice(0, WARM_ERROR_MAX - 1)}\u2026` : redacted;
}
var EMBED_QUEUE_MAX = 32;
var queuedCount = 0;
var runningCount = 0;
var inferenceChain = Promise.resolve();
function enqueueEmbed(text, env) {
  if (queuedCount >= EMBED_QUEUE_MAX)
    return null;
  queuedCount += 1;
  const run = inferenceChain.then(async () => {
    queuedCount -= 1;
    runningCount += 1;
    await new Promise((r) => setImmediate(r));
    return embed(text, env);
  });
  inferenceChain = run.then(() => void 0, () => void 0);
  return run.finally(() => {
    runningCount -= 1;
  });
}
async function readBody(req, maxBytes = 1e6) {
  const chunks = [];
  let total = 0;
  for await (const chunk of req) {
    const buf = chunk;
    total += buf.length;
    if (total > maxBytes)
      throw new Error("request body too large");
    chunks.push(buf);
  }
  return Buffer.concat(chunks).toString("utf8");
}
function sendJson(res, status, body) {
  const payload = JSON.stringify(body);
  res.writeHead(status, { "content-type": "application/json" });
  res.end(payload);
}
async function startEmbedDaemon(options = {}) {
  const env = options.env ?? process.env;
  const host = options.host ?? env.HONEYCOMB_EMBED_HOST ?? EMBED_HOST;
  const port = resolveEmbedPort(options.port, env.HONEYCOMB_EMBED_PORT);
  let warmFailed = false;
  let warmError = null;
  void warmup(env).catch((err) => {
    warmFailed = true;
    warmError = redactWarmError(err);
    process.stderr.write(`[honeycomb-embed] warmup failed: ${warmError}
`);
  });
  const server = createServer((req, res) => {
    void (async () => {
      try {
        if (req.method === "GET" && (req.url === "/health" || req.url === "/")) {
          sendJson(res, 200, {
            ok: true,
            ready: extractor !== null,
            warmFailed,
            // The redacted warmup-failure reason (null until/unless warmup throws). No secret.
            warmError,
            // ISS-007 additive load signals (no secret — two numbers/bools): whether an inference
            // is queued/running right now, and how deep the FIFO is. The supervisor treats any
            // 200 as live; these exist for doctor/dashboard glanceability.
            busy: queuedCount + runningCount > 0,
            queueDepth: queuedCount + runningCount,
            ...embedDaemonInfo()
          });
          return;
        }
        if (req.method === "POST" && req.url === "/embed") {
          const raw = await readBody(req);
          let text;
          try {
            text = JSON.parse(raw).text;
          } catch {
            sendJson(res, 400, { error: "malformed request body" });
            return;
          }
          if (typeof text !== "string" || text.length === 0) {
            sendJson(res, 400, { error: "missing or empty text" });
            return;
          }
          if (extractor === null) {
            sendJson(res, 503, { error: "model not ready" });
            return;
          }
          const queued = enqueueEmbed(text, env);
          if (queued === null) {
            sendJson(res, 503, { error: "embed queue full" });
            return;
          }
          const vector = await queued;
          sendJson(res, 200, { vector });
          return;
        }
        sendJson(res, 404, { error: "not found" });
      } catch (err) {
        const reason = err instanceof Error ? err.message : "embed failed";
        sendJson(res, 500, { error: reason });
      }
    })();
  });
  await new Promise((resolve, reject) => {
    server.once("error", reject);
    server.listen(port, host, () => {
      server.removeListener("error", reject);
      resolve();
    });
  });
  const bound = server.address();
  const boundPort = typeof bound === "object" && bound !== null ? bound.port : port;
  return {
    address: { host, port: boundPort },
    ready: () => extractor !== null,
    close: () => new Promise((resolve) => {
      server.close(() => resolve());
    })
  };
}
function __resetForTest() {
  extractor = null;
  warming = null;
  loadTransformers = defaultLoadTransformers;
  queuedCount = 0;
  runningCount = 0;
  inferenceChain = Promise.resolve();
}
var defaultLoadTransformers = loadTransformers;
function __setTransformersLoaderForTest(fake) {
  loadTransformers = fake;
}
function __setExtractorForTest(fake) {
  extractor = fake;
}
function isMainEntry() {
  const entry = process.argv[1];
  if (typeof entry !== "string" || entry.length === 0)
    return false;
  try {
    return import.meta.url === new URL(`file://${entry}`).href || import.meta.url.endsWith("/embed-daemon.js");
  } catch {
    return false;
  }
}
if (isMainEntry()) {
  startEmbedDaemon().catch((err) => {
    const message = err instanceof Error ? err.message : String(err);
    process.stderr.write(`[honeycomb-embed] failed to start: ${message}
`);
    process.exitCode = 1;
  });
}
export {
  DOCUMENT_PREFIX,
  EMBED_DIMS,
  EMBED_HOST,
  EMBED_PORT,
  EMBED_QUEUE_MAX,
  MODEL_ID,
  MODEL_QUANTIZATION,
  MODEL_REVISION,
  WARM_ERROR_MAX,
  __resetForTest,
  __setExtractorForTest,
  __setTransformersLoaderForTest,
  embed,
  embedDaemonInfo,
  modelCacheDir,
  redactWarmError,
  resolveEmbedPort,
  startEmbedDaemon,
  warmup
};
