'use strict';

var ed25519 = require('@noble/ed25519');
var sha512 = require('@noble/hashes/sha512');
var createClient = require('openapi-fetch');
var readline = require('readline');
var crypto2 = require('crypto');
var fs = require('fs');
var os = require('os');
var path = require('path');
var fflate = require('fflate');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

function _interopNamespace(e) {
  if (e && e.__esModule) return e;
  var n = Object.create(null);
  if (e) {
    Object.keys(e).forEach(function (k) {
      if (k !== 'default') {
        var d = Object.getOwnPropertyDescriptor(e, k);
        Object.defineProperty(n, k, d.get ? d : {
          enumerable: true,
          get: function () { return e[k]; }
        });
      }
    });
  }
  n.default = e;
  return Object.freeze(n);
}

var ed25519__namespace = /*#__PURE__*/_interopNamespace(ed25519);
var createClient__default = /*#__PURE__*/_interopDefault(createClient);
var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
var crypto2__namespace = /*#__PURE__*/_interopNamespace(crypto2);
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
var os__namespace = /*#__PURE__*/_interopNamespace(os);
var path__namespace = /*#__PURE__*/_interopNamespace(path);

var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __esm = (fn, res) => function __init() {
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};

// src/lib/crypto/ed25519.ts
var ed25519_exports = {};
__export(ed25519_exports, {
  generateKeypair: () => generateKeypair,
  sha256Hex: () => sha256Hex,
  signDigest: () => signDigest,
  verifyDigest: () => verifyDigest
});
function bytesToB64(bytes) {
  return Buffer.from(bytes).toString("base64");
}
function b64ToBytes(b64) {
  return new Uint8Array(Buffer.from(b64, "base64"));
}
function bytesToHex(bytes) {
  return Buffer.from(bytes).toString("hex");
}
function hexToBytes(hex) {
  return new Uint8Array(Buffer.from(hex, "hex"));
}
async function generateKeypair() {
  const privateKey = ed25519__namespace.utils.randomSecretKey();
  const publicKey = await ed25519__namespace.getPublicKeyAsync(privateKey);
  const fingerprint = await computeFingerprint(publicKey);
  return {
    privateKeyB64: bytesToB64(privateKey),
    publicKeyB64: bytesToB64(publicKey),
    fingerprintSha256: fingerprint
  };
}
async function computeFingerprint(publicKey) {
  const hash = await crypto.subtle.digest("SHA-256", toArrayBufferView(publicKey));
  return bytesToHex(new Uint8Array(hash));
}
async function signDigest(privateKeyB64, digestHex) {
  const privateKey = b64ToBytes(privateKeyB64);
  const message = hexToBytes(digestHex);
  const signature = await ed25519__namespace.signAsync(message, privateKey);
  return bytesToB64(signature);
}
async function verifyDigest(publicKeyB64, digestHex, signatureB64) {
  const publicKey = b64ToBytes(publicKeyB64);
  const message = hexToBytes(digestHex);
  const signature = b64ToBytes(signatureB64);
  return ed25519__namespace.verifyAsync(signature, message, publicKey);
}
async function sha256Hex(data) {
  const hash = await crypto.subtle.digest("SHA-256", toArrayBufferView(data));
  return bytesToHex(new Uint8Array(hash));
}
function toArrayBufferView(bytes) {
  const buffer = new ArrayBuffer(bytes.byteLength);
  const view = new Uint8Array(buffer);
  view.set(bytes);
  return view;
}
var init_ed25519 = __esm({
  "src/lib/crypto/ed25519.ts"() {
    ed25519__namespace.hashes.sha512 = sha512.sha512;
  }
});

// src/lib/marketplace-install.ts
init_ed25519();
var MarketplaceApiError = class extends Error {
  status;
  body;
  constructor(status, body, message) {
    super(message);
    this.name = "MarketplaceApiError";
    this.status = status;
    this.body = body;
  }
};
function createMarketplaceClient(options) {
  const headers = {};
  if (options.token) {
    headers.Authorization = `Bearer ${options.token}`;
  }
  return createClient__default.default({
    baseUrl: options.apiUrl,
    headers
  });
}
function unwrap(result) {
  if (result.data !== void 0) {
    return result.data;
  }
  const status = result.response.status;
  const body = result.error;
  const message = extractErrorMessage(body) ?? `Marketplace API request failed (${status})`;
  throw new MarketplaceApiError(status, body, message);
}
function extractErrorMessage(body) {
  if (!body || typeof body !== "object") return null;
  const record = body;
  if (typeof record.error === "string") return record.error;
  if (typeof record.message === "string") return record.message;
  return null;
}

// src/lib/marketplace-install.ts
var KNOWN_REVIEW_STATUSES = [
  "none",
  "auto_approved",
  "pending_review",
  "approved",
  "rejected"
];
function normalizeReviewStatus(value) {
  if (typeof value !== "string") return null;
  return KNOWN_REVIEW_STATUSES.includes(value) ? value : null;
}
async function resolveLatestVersion(options) {
  const { listingId, apiUrl, token } = options;
  const clientOpts = token !== void 0 ? { apiUrl, token } : { apiUrl };
  const client = createMarketplaceClient(clientOpts);
  const result = await client.GET("/listings/{id}/versions/latest", {
    params: { path: { id: listingId } }
  });
  let body;
  try {
    body = unwrap(result);
  } catch (err) {
    if (err instanceof MarketplaceApiError) {
      throw new Error(
        `Failed to resolve latest version for "${listingId}": ${err.status} ${err.message}`
      );
    }
    throw err;
  }
  return {
    versionId: body.versionId,
    listingId: body.listingId,
    version: body.version,
    sha256: body.sha256,
    publisherHandle: body.publisherHandle,
    signature: body.signature ?? null,
    signingKey: body.signingKey ?? null,
    downloadUrl: body.downloadUrl,
    expiresAt: body.expiresAt,
    publishedAt: body.publishedAt ?? null,
    changelog: body.changelog ?? null,
    minFlowstateVersion: body.minFlowstateVersion ?? null,
    reviewStatus: normalizeReviewStatus(body.reviewStatus),
    featured: body.featured === true
  };
}
async function downloadBundle(options) {
  const { downloadUrl, apiUrl, token, fetchImpl = globalThis.fetch } = options;
  const url = isAbsoluteUrl(downloadUrl) ? downloadUrl : joinUrl(apiUrl, downloadUrl);
  const headers = {};
  if (token) {
    headers.Authorization = `Bearer ${token}`;
  }
  const response = await fetchImpl(url, { method: "GET", headers });
  if (!response.ok) {
    let body = "";
    try {
      body = await response.text();
    } catch {
    }
    throw new Error(
      `Bundle download failed: ${response.status} ${response.statusText}${body ? ` \u2014 ${body}` : ""}`
    );
  }
  const arrayBuffer = await response.arrayBuffer();
  return new Uint8Array(arrayBuffer);
}
async function verifyBundle(options) {
  const { bytes, expectedSha256, signature, signingKey } = options;
  const actualSha256 = await sha256Hex(bytes);
  if (actualSha256 !== expectedSha256) {
    return {
      ok: false,
      reason: `SHA-256 mismatch. Expected ${expectedSha256}, got ${actualSha256}`
    };
  }
  if (!signature || !signingKey) {
    return { ok: true };
  }
  if (signature.algorithm !== "ed25519") {
    return {
      ok: false,
      reason: `Unsupported signature algorithm: ${signature.algorithm}`
    };
  }
  const valid = await verifyDigest(signingKey.publicKeyB64, actualSha256, signature.signatureB64);
  if (!valid) {
    return {
      ok: false,
      reason: "ed25519 signature verification failed. The bundle may be tampered or the publisher key has rotated."
    };
  }
  return { ok: true };
}
function isAbsoluteUrl(url) {
  return /^https?:\/\//i.test(url);
}
function joinUrl(base, relative) {
  const trimmedBase = base.replace(/\/+$/, "");
  const trimmedRel = relative.replace(/^\/+/, "");
  const baseLastSegment = trimmedBase.split("/").pop() ?? "";
  const relFirstSegment = trimmedRel.split("/")[0] ?? "";
  if (baseLastSegment && baseLastSegment === relFirstSegment) {
    const dedupedRel = trimmedRel.slice(relFirstSegment.length).replace(/^\/+/, "");
    return `${trimmedBase}/${dedupedRel}`;
  }
  return `${trimmedBase}/${trimmedRel}`;
}
function parsePermissions(manifest) {
  if (!manifest || typeof manifest !== "object") {
    return [];
  }
  const record = manifest;
  const value = record.permissions;
  if (!Array.isArray(value)) {
    return [];
  }
  return value.filter((p) => typeof p === "string");
}
async function promptPermissions(options) {
  const { permissions, autoAccept = false, prompter = defaultPrompter, logger = console } = options;
  if (permissions.length === 0) {
    return true;
  }
  const formatted = formatPermissions(permissions);
  if (autoAccept) {
    logger.log(`Auto-accepted permissions:
${formatted}`);
    return true;
  }
  const message = `This plugin requests the following permissions:
${formatted}

Accept? [y/N] `;
  return prompter(message);
}
function formatPermissions(permissions) {
  return permissions.map((p) => `  - ${p}`).join("\n");
}
async function defaultPrompter(message) {
  const rl = readline__namespace.createInterface({
    input: process.stdin,
    output: process.stdout
  });
  try {
    const answer = await new Promise((resolve) => {
      rl.question(message, resolve);
    });
    return /^y(es)?$/i.test(answer.trim());
  } finally {
    rl.close();
  }
}
var MARKETPLACE_DIR = path__namespace.join(os__namespace.homedir(), ".flowstate", "marketplace");
var PACKAGES_DIR = path__namespace.join(MARKETPLACE_DIR, "packages");
var INSTALLED_JSON = path__namespace.join(MARKETPLACE_DIR, "installed.json");
function resolveInstallRoot(opts) {
  if (opts.kind === "connector") {
    if (!opts.instanceName) {
      throw new Error(
        "resolveInstallRoot: instanceName is required for kind:connector. Pass --instance <name> or set FLOWSTATE_INSTANCE."
      );
    }
    return path__namespace.join(os__namespace.homedir(), ".flowstate", "instances", opts.instanceName, "plugins");
  }
  return PACKAGES_DIR;
}
function installedJsonForRoot(packagesRoot) {
  if (packagesRoot === PACKAGES_DIR) {
    return INSTALLED_JSON;
  }
  return path__namespace.join(packagesRoot, "..", "installed.json");
}
function readInstalledRegistry() {
  return readInstalledRegistryAt(INSTALLED_JSON);
}
function readInstalledRegistryAt(jsonPath) {
  try {
    const content = fs__namespace.readFileSync(jsonPath, "utf-8");
    return JSON.parse(content);
  } catch (err) {
    if (err.code === "ENOENT") {
      return { packages: {} };
    }
    throw err;
  }
}
function writeInstalledRegistryAt(jsonPath, parentDir, registry) {
  fs__namespace.mkdirSync(parentDir, { recursive: true });
  fs__namespace.writeFileSync(jsonPath, JSON.stringify(registry, null, 2));
}
async function installPlugin(options) {
  const { archivePath, skipVerify = false, kind = "app", instanceName } = options;
  const packagesRoot = resolveInstallRoot(
    instanceName !== void 0 ? { kind, instanceName } : { kind }
  );
  const registryPath = installedJsonForRoot(packagesRoot);
  if (!fs__namespace.existsSync(archivePath)) {
    throw new Error(`Archive not found: ${archivePath}`);
  }
  const archiveBytes = new Uint8Array(fs__namespace.readFileSync(archivePath));
  if (!skipVerify) {
    const checksumPath = `${archivePath}.sha256`;
    if (fs__namespace.existsSync(checksumPath)) {
      const checksumContent = fs__namespace.readFileSync(checksumPath, "utf-8").trim();
      const expectedDigest = checksumContent.split(/\s+/)[0];
      const actualDigest = crypto2__namespace.createHash("sha256").update(archiveBytes).digest("hex");
      if (actualDigest !== expectedDigest) {
        throw new Error(
          `SHA-256 checksum mismatch.
  Expected: ${expectedDigest}
  Actual:   ${actualDigest}`
        );
      }
    }
  }
  if (!skipVerify) {
    const sigPath = `${archivePath}.sig`;
    if (fs__namespace.existsSync(sigPath)) {
      const signatureB64 = fs__namespace.readFileSync(sigPath, "utf-8").trim();
      const actualDigest = crypto2__namespace.createHash("sha256").update(archiveBytes).digest("hex");
      const extracted2 = fflate.unzipSync(archiveBytes);
      const manifestBytes2 = extracted2["flowstate.plugin.json"];
      if (!manifestBytes2) {
        throw new Error("Archive missing flowstate.plugin.json");
      }
      const manifest2 = JSON.parse(Buffer.from(manifestBytes2).toString("utf-8"));
      if (manifest2._integrity?.publicKeyB64) {
        const { verifyDigest: verifyDigest2 } = await Promise.resolve().then(() => (init_ed25519(), ed25519_exports));
        const valid = await verifyDigest2(
          manifest2._integrity.publicKeyB64,
          actualDigest,
          signatureB64
        );
        if (!valid) {
          throw new Error("ed25519 signature verification failed. Archive may be tampered.");
        }
      }
    }
  }
  const extracted = fflate.unzipSync(archiveBytes);
  const manifestBytes = extracted["flowstate.plugin.json"];
  if (!manifestBytes) {
    throw new Error("Archive missing flowstate.plugin.json");
  }
  const manifest = JSON.parse(Buffer.from(manifestBytes).toString("utf-8"));
  const { id, version } = manifest;
  if (!id || !version) {
    throw new Error('Manifest missing required "id" or "version" field');
  }
  const installDir = path__namespace.join(packagesRoot, id, version);
  fs__namespace.mkdirSync(installDir, { recursive: true });
  for (const [entryName, entryData] of Object.entries(extracted)) {
    const entryPath = path__namespace.join(installDir, entryName);
    fs__namespace.mkdirSync(path__namespace.dirname(entryPath), { recursive: true });
    fs__namespace.writeFileSync(entryPath, entryData);
  }
  const currentLink = path__namespace.join(packagesRoot, id, "current");
  try {
    fs__namespace.unlinkSync(currentLink);
  } catch {
  }
  fs__namespace.symlinkSync(version, currentLink);
  const relPath = kind === "connector" ? `${id}/current` : `packages/${id}/current`;
  const registry = readInstalledRegistryAt(registryPath);
  registry.packages[id] = {
    type: "plugin",
    version,
    installedAt: (/* @__PURE__ */ new Date()).toISOString(),
    enabled: true,
    path: relPath
  };
  writeInstalledRegistryAt(registryPath, path__namespace.dirname(registryPath), registry);
  return { id, version, installDir };
}
function uninstallPlugin(pluginId, options = {}) {
  const { purge = false, kind = "app", instanceName } = options;
  const packagesRoot = resolveInstallRoot(
    instanceName !== void 0 ? { kind, instanceName } : { kind }
  );
  const registryPath = installedJsonForRoot(packagesRoot);
  const packageDir = path__namespace.join(packagesRoot, pluginId);
  const versionsBefore = listInstalledVersions(pluginId, packagesRoot);
  const existed = fs__namespace.existsSync(packageDir) || versionsBefore.length > 0;
  let purged = false;
  let devManifestRemoved = false;
  if (!existed) {
    return {
      removed: false,
      purged: false,
      versionsBefore: [],
      versionsAfter: [],
      devManifestRemoved: false
    };
  }
  if (purge) {
    fs__namespace.rmSync(packageDir, { recursive: true, force: true });
    purged = true;
    if (kind !== "connector") {
      const devManifestPath = path__namespace.join(MARKETPLACE_DIR, "dev-manifests", `${pluginId}.json`);
      if (fs__namespace.existsSync(devManifestPath)) {
        try {
          fs__namespace.unlinkSync(devManifestPath);
          devManifestRemoved = true;
        } catch {
        }
      }
    }
  } else {
    const currentLink = path__namespace.join(packageDir, "current");
    try {
      fs__namespace.unlinkSync(currentLink);
    } catch {
    }
    const remaining = listInstalledVersions(pluginId, packagesRoot);
    if (remaining.length === 0) {
      fs__namespace.rmSync(packageDir, { recursive: true, force: true });
    }
  }
  const registry = readInstalledRegistryAt(registryPath);
  if (registry.packages[pluginId]) {
    delete registry.packages[pluginId];
    writeInstalledRegistryAt(registryPath, path__namespace.dirname(registryPath), registry);
  }
  return {
    removed: true,
    purged,
    versionsBefore,
    versionsAfter: listInstalledVersions(pluginId, packagesRoot),
    devManifestRemoved
  };
}
function purgePlugin(pluginId, kind = "app", instanceName) {
  return uninstallPlugin(
    pluginId,
    instanceName !== void 0 ? { purge: true, kind, instanceName } : { purge: true, kind }
  );
}
function listInstalledVersions(pluginId, packagesRoot = PACKAGES_DIR) {
  const packageDir = path__namespace.join(packagesRoot, pluginId);
  if (!fs__namespace.existsSync(packageDir)) {
    return [];
  }
  let entries;
  try {
    entries = fs__namespace.readdirSync(packageDir, { withFileTypes: true });
  } catch {
    return [];
  }
  const versions = [];
  for (const entry of entries) {
    if (entry.name === "current") continue;
    if (!entry.isDirectory()) continue;
    if (!/^\d+(?:\.\d+)*(?:[-+].*)?$/.test(entry.name)) continue;
    versions.push(entry.name);
  }
  versions.sort((a, b) => compareVersions(b, a));
  return versions;
}
function compareVersions(a, b) {
  const parse = (v) => {
    const cleaned = v.replace(/^v/, "").split(/[-+]/)[0] ?? "0.0.0";
    return cleaned.split(".").map((p) => Number.parseInt(p, 10)).map((n) => Number.isFinite(n) ? n : 0);
  };
  const av = parse(a);
  const bv = parse(b);
  const len = Math.max(av.length, bv.length);
  for (let i = 0; i < len; i++) {
    const ai = av[i] ?? 0;
    const bi = bv[i] ?? 0;
    if (ai !== bi) return ai - bi;
  }
  return 0;
}
function rollbackToVersion(pluginId, options = {}) {
  const { targetVersion, kind = "app", instanceName } = options;
  const packagesRoot = resolveInstallRoot(
    instanceName !== void 0 ? { kind, instanceName } : { kind }
  );
  const registryPath = installedJsonForRoot(packagesRoot);
  const packageDir = path__namespace.join(packagesRoot, pluginId);
  if (!fs__namespace.existsSync(packageDir)) {
    throw new Error(`Plugin "${pluginId}" is not installed`);
  }
  const versions = listInstalledVersions(pluginId, packagesRoot);
  if (versions.length === 0) {
    throw new Error(`Plugin "${pluginId}" has no on-disk versions to roll back to`);
  }
  const registry = readInstalledRegistryAt(registryPath);
  const entry = registry.packages[pluginId];
  const currentVersion = entry?.version ?? null;
  let target;
  if (targetVersion) {
    if (!versions.includes(targetVersion)) {
      throw new Error(
        `Version "${targetVersion}" is not installed for plugin "${pluginId}". Available versions: ${versions.join(", ")}`
      );
    }
    target = targetVersion;
  } else {
    if (currentVersion) {
      const prior = versions.find((v) => v !== currentVersion);
      if (!prior) {
        throw new Error(
          `No prior version available to roll back to for plugin "${pluginId}" (only ${currentVersion} on disk)`
        );
      }
      target = prior;
    } else {
      target = versions[1] ?? versions[0] ?? "";
      if (!target) {
        throw new Error(`No versions on disk for plugin "${pluginId}"`);
      }
    }
  }
  const currentLink = path__namespace.join(packageDir, "current");
  try {
    fs__namespace.unlinkSync(currentLink);
  } catch {
  }
  fs__namespace.symlinkSync(target, currentLink);
  const relPath = kind === "connector" ? `${pluginId}/current` : `packages/${pluginId}/current`;
  registry.packages[pluginId] = {
    type: entry?.type ?? "plugin",
    version: target,
    installedAt: (/* @__PURE__ */ new Date()).toISOString(),
    enabled: entry?.enabled ?? true,
    path: relPath
  };
  writeInstalledRegistryAt(registryPath, path__namespace.dirname(registryPath), registry);
  return {
    pluginId,
    previousVersion: currentVersion,
    rolledBackTo: target,
    availableVersions: versions
  };
}
function getUserConfigPath() {
  return path__namespace.join(os__namespace.homedir(), ".flowstate", "config.json");
}
function readRawUserConfig() {
  const configPath = getUserConfigPath();
  try {
    const content = fs__namespace.readFileSync(configPath, "utf-8");
    const parsed = JSON.parse(content);
    if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
      return parsed;
    }
    return {};
  } catch (err) {
    const code = err.code;
    if (code === "ENOENT") return {};
    return {};
  }
}
function readUserConfig() {
  const raw = readRawUserConfig();
  const out = {};
  if (typeof raw.telemetry === "boolean") {
    out.telemetry = raw.telemetry;
  }
  if (typeof raw.lastUpdateCheckAt === "string") {
    out.lastUpdateCheckAt = raw.lastUpdateCheckAt;
  }
  return out;
}
function updateUserConfig(update) {
  const configPath = getUserConfigPath();
  const configDir = path__namespace.dirname(configPath);
  const raw = readRawUserConfig();
  const next = { ...raw };
  if ("telemetry" in update && update.telemetry !== void 0) {
    next.telemetry = update.telemetry;
  }
  if ("lastUpdateCheckAt" in update && update.lastUpdateCheckAt !== void 0) {
    next.lastUpdateCheckAt = update.lastUpdateCheckAt;
  }
  fs__namespace.mkdirSync(configDir, { recursive: true, mode: 448 });
  fs__namespace.writeFileSync(configPath, JSON.stringify(next, null, 2), { mode: 384 });
  return readUserConfig();
}
function isTelemetryEnabled() {
  const cfg = readUserConfig();
  return cfg.telemetry === true;
}
function getLastUpdateCheckAt() {
  const cfg = readUserConfig();
  if (!cfg.lastUpdateCheckAt) return null;
  const parsed = new Date(cfg.lastUpdateCheckAt);
  return Number.isFinite(parsed.getTime()) ? parsed : null;
}
function markUpdateCheckCompleted(now = /* @__PURE__ */ new Date()) {
  updateUserConfig({ lastUpdateCheckAt: now.toISOString() });
}

// src/lib/telemetry.ts
async function recordInstallTelemetry(options) {
  const {
    listingId,
    version,
    apiUrl,
    token,
    enabled,
    logger = console,
    createClient: createClient2 = createMarketplaceClient
  } = options;
  const optedIn = enabled === void 0 ? isTelemetryEnabled() : enabled;
  if (!optedIn) {
    return { sent: false, reason: "opt-out" };
  }
  try {
    const clientOpts = token !== void 0 ? { apiUrl, token } : { apiUrl };
    const client = createClient2(clientOpts);
    const result = await client.POST("/listings/{id}/install", {
      params: { path: { id: listingId } }
    });
    if (result.error !== void 0 || !result.response.ok) {
      const status = result.response.status;
      const err = new MarketplaceApiError(
        status,
        result.error,
        `Install telemetry ping failed with HTTP ${status}`
      );
      logger.warn(`[telemetry] install ping failed for ${listingId}@${version}: ${err.message}`);
      return { sent: false, reason: "error", error: err };
    }
    return { sent: true };
  } catch (err) {
    const error = err instanceof Error ? err : new Error(String(err));
    logger.warn(`[telemetry] install ping threw for ${listingId}@${version}: ${error.message}`);
    return { sent: false, reason: "error", error };
  }
}

exports.downloadBundle = downloadBundle;
exports.getLastUpdateCheckAt = getLastUpdateCheckAt;
exports.getUserConfigPath = getUserConfigPath;
exports.installPlugin = installPlugin;
exports.isTelemetryEnabled = isTelemetryEnabled;
exports.listInstalledVersions = listInstalledVersions;
exports.markUpdateCheckCompleted = markUpdateCheckCompleted;
exports.parsePermissions = parsePermissions;
exports.promptPermissions = promptPermissions;
exports.purgePlugin = purgePlugin;
exports.readInstalledRegistry = readInstalledRegistry;
exports.readInstalledRegistryAt = readInstalledRegistryAt;
exports.readUserConfig = readUserConfig;
exports.recordInstallTelemetry = recordInstallTelemetry;
exports.resolveInstallRoot = resolveInstallRoot;
exports.resolveLatestVersion = resolveLatestVersion;
exports.rollbackToVersion = rollbackToVersion;
exports.uninstallPlugin = uninstallPlugin;
exports.updateUserConfig = updateUserConfig;
exports.verifyBundle = verifyBundle;
//# sourceMappingURL=marketplace-lib.js.map
//# sourceMappingURL=marketplace-lib.js.map