// Force strict mode and setup for ESM
"use strict";
import {
  isPrivateHost
} from "./chunk-LOY7RWQG.js";
import {
  loadUndici
} from "./chunk-Q3T5KA2V.js";
import {
  getErrorMessage
} from "./chunk-E2BHWIDT.js";
import {
  init_esbuild_shims
} from "./chunk-5O2XNYP6.js";
import {
  __name
} from "./chunk-J2S4EL5Y.js";

// packages/core/src/services/image-generation-service.ts
init_esbuild_shims();

// packages/core/src/extension/network-policy.ts
init_esbuild_shims();
import { promises as dns } from "node:dns";
import { BlockList, isIP } from "node:net";
var blockedAddresses = new BlockList();
var publicIpv6Addresses = new BlockList();
publicIpv6Addresses.addSubnet("2000::", 3, "ipv6");
for (const [address, prefix] of [
  ["0.0.0.0", 8],
  ["10.0.0.0", 8],
  ["100.64.0.0", 10],
  ["127.0.0.0", 8],
  ["169.254.0.0", 16],
  ["172.16.0.0", 12],
  ["192.0.0.0", 24],
  ["192.0.2.0", 24],
  ["192.88.99.0", 24],
  ["192.168.0.0", 16],
  ["198.18.0.0", 15],
  ["198.51.100.0", 24],
  ["203.0.113.0", 24],
  ["224.0.0.0", 4],
  ["240.0.0.0", 4]
]) {
  blockedAddresses.addSubnet(address, prefix, "ipv4");
}
for (const [address, prefix] of [
  ["2001::", 23],
  ["2001:db8::", 32],
  ["2002::", 16],
  ["3fff::", 20]
]) {
  blockedAddresses.addSubnet(address, prefix, "ipv6");
}
async function waitForAbortable(promise, signal) {
  if (!signal) return await promise;
  signal.throwIfAborted();
  return await new Promise((resolve, reject) => {
    let settled = false;
    const finish = /* @__PURE__ */ __name((callback) => {
      if (settled) return;
      settled = true;
      signal.removeEventListener("abort", onAbort);
      callback();
    }, "finish");
    const onAbort = /* @__PURE__ */ __name(() => finish(() => reject(signal.reason)), "onAbort");
    signal.addEventListener("abort", onAbort, { once: true });
    if (signal.aborted) {
      onAbort();
      return;
    }
    promise.then(
      (value) => finish(() => resolve(value)),
      (error) => finish(() => reject(error))
    );
  });
}
__name(waitForAbortable, "waitForAbortable");
function stripIpv6Brackets(hostname) {
  return hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
}
__name(stripIpv6Brackets, "stripIpv6Brackets");
function parseMappedIpv4(address) {
  const suffix = address.toLowerCase().slice("::ffff:".length);
  if (isIP(suffix) === 4) return suffix;
  const parts = suffix.split(":");
  if (parts.length !== 2 || parts.some((part) => !/^[\da-f]{1,4}$/.test(part))) {
    return void 0;
  }
  const upper = Number.parseInt(parts[0], 16);
  const lower = Number.parseInt(parts[1], 16);
  return `${upper >> 8}.${upper & 255}.${lower >> 8}.${lower & 255}`;
}
__name(parseMappedIpv4, "parseMappedIpv4");
function isBlockedAddress(address, family) {
  if (family === 6 && address.toLowerCase().startsWith("::ffff:")) {
    const mapped = parseMappedIpv4(address);
    return mapped === void 0 || isBlockedAddress(mapped, 4);
  }
  if (family === 6 && !publicIpv6Addresses.check(address, "ipv6")) return true;
  return blockedAddresses.check(address, family === 6 ? "ipv6" : "ipv4");
}
__name(isBlockedAddress, "isBlockedAddress");
async function resolveNetworkTarget(value, policy, signal) {
  signal?.throwIfAborted();
  const url = value instanceof URL ? value : new URL(value);
  if (policy !== "public") return { url };
  if (url.protocol !== "https:") {
    throw new Error("Public extension network requests must use HTTPS.");
  }
  if (url.username || url.password) {
    throw new Error(
      "Public extension network requests must not use credentials."
    );
  }
  const hostname = stripIpv6Brackets(url.hostname);
  const literalFamily = isIP(hostname);
  const addresses = literalFamily ? [{ address: hostname, family: literalFamily }] : await waitForAbortable(
    dns.lookup(hostname, { all: true, verbatim: true }),
    signal
  );
  if (addresses.length === 0) {
    throw new Error(`Extension network host did not resolve: ${hostname}`);
  }
  if (addresses.some(({ address, family }) => isBlockedAddress(address, family))) {
    throw new Error(
      `Extension network host resolved to a blocked address: ${hostname}`
    );
  }
  const selected = addresses[0];
  const lookup = /* @__PURE__ */ __name((requestedHostname, options, callback) => {
    if (stripIpv6Brackets(requestedHostname) !== hostname) {
      const error = new Error(
        "Pinned extension lookup hostname mismatch"
      );
      error.code = "ENOTFOUND";
      callback(error, "", 0);
      return;
    }
    if (options.all) {
      callback(null, [selected]);
    } else {
      callback(null, selected.address, selected.family);
    }
  }, "lookup");
  const port = url.port || "443";
  const curlHostname = literalFamily === 6 ? `[${hostname}]` : hostname;
  const curlAddress = selected.family === 6 ? `[${selected.address}]` : selected.address;
  return {
    url,
    lookup,
    curlResolve: `${curlHostname}:${port}:${curlAddress}`
  };
}
__name(resolveNetworkTarget, "resolveNetworkTarget");

// packages/core/src/services/image-generation-service.ts
var GENERATION_TIMEOUT_MS = 24e4;
var DOWNLOAD_TIMEOUT_MS = 12e4;
var MAX_API_RESPONSE_BYTES = 1024 * 1024;
var MAX_IMAGE_BYTES = 10 * 1024 * 1024;
var MAX_DOWNLOAD_REDIRECTS = 3;
var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
var PNG_SIGNATURE = Buffer.from([
  137,
  80,
  78,
  71,
  13,
  10,
  26,
  10
]);
var ResponseSizeLimitError = class extends Error {
  static {
    __name(this, "ResponseSizeLimitError");
  }
};
function normalizeImageGenerationBaseUrl(value) {
  const baseUrl = value?.trim();
  if (!baseUrl) return void 0;
  let parsed;
  try {
    parsed = new URL(baseUrl);
  } catch {
    return void 0;
  }
  if (parsed.protocol !== "https:" || parsed.username || parsed.password || parsed.search || parsed.hash) {
    return void 0;
  }
  return parsed.toString().replace(/\/+$/, "");
}
__name(normalizeImageGenerationBaseUrl, "normalizeImageGenerationBaseUrl");
async function generateImage(request) {
  const fetchFn = request.fetchFn ?? fetch;
  const baseUrl = normalizeImageGenerationBaseUrl(request.baseUrl);
  if (!baseUrl) {
    throw new Error(
      "Image generation baseUrl must be a valid HTTPS URL without credentials, query, or fragment."
    );
  }
  const generationUrl = baseUrl.endsWith(
    "/services/aigc/multimodal-generation/generation"
  ) ? baseUrl : `${baseUrl}/services/aigc/multimodal-generation/generation`;
  const parameters = {
    n: 1,
    prompt_extend: true,
    watermark: false
  };
  if (request.size) {
    parameters["size"] = request.size;
  }
  let response;
  try {
    response = await fetchFn(generationUrl, {
      method: "POST",
      headers: {
        Authorization: `Bearer ${request.apiKey}`,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        model: request.model,
        input: {
          messages: [
            {
              role: "user",
              content: [{ text: request.prompt }]
            }
          ]
        },
        parameters
      }),
      redirect: "error",
      signal: combineWithTimeout(request.signal, GENERATION_TIMEOUT_MS)
    });
  } catch (error) {
    throw new Error(
      `Image generation request failed: ${getErrorMessage(error)}`,
      { cause: error }
    );
  }
  if (!response.ok) {
    let payload2 = {};
    try {
      payload2 = await readJsonResponse(response, MAX_API_RESPONSE_BYTES);
    } catch {
    }
    throw new Error(formatImageGenerationError(response.status, payload2));
  }
  const payload = await readJsonResponse(response, MAX_API_RESPONSE_BYTES);
  const imageUrl = findGeneratedImageUrl(payload);
  if (!imageUrl) {
    throw new Error("Image generation response did not contain an image URL.");
  }
  const bytes = await downloadPng(imageUrl, fetchFn, request.signal);
  const requestId = readString(payload, "request_id", "requestId");
  return {
    bytes,
    mimeType: "image/png",
    ...requestId ? { requestId } : {}
  };
}
__name(generateImage, "generateImage");
async function readJsonResponse(response, maxBytes) {
  const bytes = await readBoundedBody(response, maxBytes);
  if (bytes.length === 0) {
    return {};
  }
  try {
    return JSON.parse(bytes.toString("utf8"));
  } catch {
    throw new Error(
      `Image generation endpoint returned malformed JSON (HTTP ${response.status}).`
    );
  }
}
__name(readJsonResponse, "readJsonResponse");
async function readBoundedBody(response, maxBytes) {
  const contentLength = Number(response.headers.get("content-length"));
  if (Number.isFinite(contentLength) && contentLength > maxBytes) {
    await response.body?.cancel().catch(() => {
    });
    throw new ResponseSizeLimitError(
      `Response exceeds the ${maxBytes}-byte limit.`
    );
  }
  if (!response.body) {
    return Buffer.alloc(0);
  }
  const chunks = [];
  let total = 0;
  const reader = response.body.getReader();
  try {
    for (; ; ) {
      const { done, value } = await reader.read();
      if (done) break;
      total += value.byteLength;
      if (total > maxBytes) {
        throw new ResponseSizeLimitError(
          `Response exceeds the ${maxBytes}-byte limit.`
        );
      }
      chunks.push(value);
    }
  } finally {
    await reader.cancel().catch(() => {
    });
    reader.releaseLock();
  }
  return Buffer.concat(chunks, total);
}
__name(readBoundedBody, "readBoundedBody");
function formatImageGenerationError(status, payload) {
  const code = readString(payload, "code");
  const message = readString(payload, "message");
  const suffix = [code, message].filter(Boolean).join(": ");
  if (status === 429 || /throttl|rate.?limit/i.test(`${code} ${message}`)) {
    return `Image generation rate limit reached${suffix ? ` (${suffix})` : ""}.`;
  }
  if (status === 401 || status === 403 || /access|permission/i.test(code ?? "")) {
    return `Image generation access denied${suffix ? ` (${suffix})` : ""}. Check the API key, endpoint, and model access.`;
  }
  if (/DataInspectionFailed/i.test(code ?? "")) {
    return `The image generation endpoint blocked the prompt during content moderation${message ? `: ${message}` : "."}`;
  }
  return `Image generation failed with HTTP ${status}${suffix ? ` (${suffix})` : ""}.`;
}
__name(formatImageGenerationError, "formatImageGenerationError");
function findGeneratedImageUrl(payload) {
  if (!isRecord(payload)) return void 0;
  const output = payload["output"];
  if (!isRecord(output) || !Array.isArray(output["choices"])) return void 0;
  for (const choice of output["choices"]) {
    if (!isRecord(choice)) continue;
    const message = choice["message"];
    if (!isRecord(message) || !Array.isArray(message["content"])) continue;
    for (const part of message["content"]) {
      if (!isRecord(part)) continue;
      const image = part["image"];
      if (typeof image === "string" && image.trim()) {
        return image.trim();
      }
    }
  }
  return void 0;
}
__name(findGeneratedImageUrl, "findGeneratedImageUrl");
async function downloadPng(imageUrl, fetchFn, signal) {
  const combinedSignal = combineWithTimeout(signal, DOWNLOAD_TIMEOUT_MS);
  let currentTarget = await validateResultUrl(imageUrl, combinedSignal);
  for (let redirectCount = 0; redirectCount <= MAX_DOWNLOAD_REDIRECTS; redirectCount++) {
    let dispatcher;
    if (currentTarget.lookup) {
      const undici = await loadUndici();
      const { Agent } = undici;
      dispatcher = new Agent({ connect: { lookup: currentTarget.lookup } });
    }
    let response;
    try {
      response = await fetchFn(currentTarget.url.toString(), {
        method: "GET",
        headers: { Accept: "image/png" },
        redirect: "manual",
        signal: combinedSignal,
        ...dispatcher ? { dispatcher } : {}
      });
    } catch (error) {
      await dispatcher?.close();
      throw new Error("Generated image download failed before completion.", {
        cause: error
      });
    }
    try {
      if (REDIRECT_STATUSES.has(response.status)) {
        const location = response.headers.get("location");
        await response.body?.cancel().catch(() => {
        });
        if (!location) {
          throw new Error(
            "Generated image redirect is missing a Location header."
          );
        }
        let redirectUrl;
        try {
          redirectUrl = new URL(
            location,
            currentTarget.url.toString()
          ).toString();
        } catch {
          throw new Error("Generated image redirect URL is invalid.");
        }
        currentTarget = await validateResultUrl(redirectUrl, combinedSignal);
        continue;
      }
      if (!response.ok) {
        await response.body?.cancel().catch(() => {
        });
        throw new Error(
          `Generated image download failed with HTTP ${response.status}.`
        );
      }
      let bytes;
      try {
        bytes = await readBoundedBody(response, MAX_IMAGE_BYTES);
      } catch (error) {
        if (error instanceof ResponseSizeLimitError) {
          throw error;
        }
        throw new Error("Generated image download failed before completion.", {
          cause: error
        });
      }
      if (bytes.length < PNG_SIGNATURE.length || !bytes.subarray(0, PNG_SIGNATURE.length).equals(PNG_SIGNATURE)) {
        throw new Error("Downloaded result is not a valid PNG image.");
      }
      return bytes;
    } finally {
      await dispatcher?.close();
    }
  }
  throw new Error(
    `Generated image download exceeded ${MAX_DOWNLOAD_REDIRECTS} redirects.`
  );
}
__name(downloadPng, "downloadPng");
async function validateResultUrl(value, signal) {
  let parsed;
  try {
    parsed = new URL(value);
  } catch {
    throw new Error("Image generation returned an invalid image URL.");
  }
  if (parsed.protocol !== "https:" || parsed.username || parsed.password || isPrivateHost(parsed.toString())) {
    throw new Error(
      "Image generation returned an image URL that is not a safe public HTTPS URL."
    );
  }
  try {
    return await resolveNetworkTarget(parsed, "public", signal);
  } catch (error) {
    signal.throwIfAborted();
    throw new Error(
      "Image generation returned an image URL that is not a safe public HTTPS URL.",
      { cause: error }
    );
  }
}
__name(validateResultUrl, "validateResultUrl");
function combineWithTimeout(signal, timeoutMs) {
  return AbortSignal.any([signal, AbortSignal.timeout(timeoutMs)]);
}
__name(combineWithTimeout, "combineWithTimeout");
function readString(value, ...keys) {
  if (!isRecord(value)) return void 0;
  for (const key of keys) {
    const candidate = value[key];
    if (typeof candidate === "string" && candidate.trim()) {
      return candidate.trim();
    }
  }
  return void 0;
}
__name(readString, "readString");
function isRecord(value) {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}
__name(isRecord, "isRecord");

export {
  resolveNetworkTarget,
  normalizeImageGenerationBaseUrl,
  generateImage
};
/**
 * @license
 * Copyright 2025 Qwen Team
 * SPDX-License-Identifier: Apache-2.0
 */
