import {
  TangleSsoUserCreateError,
  assertBillableBalance,
  createAdminGuard,
  createAuthGuard,
  createBetterAuthSessionCookieMinter,
  createSignedSsoState,
  createTangleSsoHandlers,
  guardResolution,
  parseAdminEmails,
  signSessionCookieValue,
  verifySignedSsoState
} from "../chunk-YRMLYFVR.js";
import "../chunk-PTUMBMVH.js";
import {
  resolveTangleDevOrUserKey
} from "../chunk-JML7WKWU.js";

// src/platform/hub.ts
var TangleBearerMissingError = class extends Error {
  constructor(userId) {
    super(`No Tangle platform link for user ${userId}`);
    this.userId = userId;
    this.name = "TangleBearerMissingError";
  }
  userId;
};
async function resolveUserTangleHubBearer(opts) {
  const resolved = await resolveTangleDevOrUserKey({
    environment: opts.environment,
    env: opts.env,
    getUserApiKey: opts.getUserApiKey
  });
  if (resolved) return { bearer: resolved.apiKey, source: resolved.source };
  throw new TangleBearerMissingError(opts.userId);
}
async function resolveUserTangleHubBearerForUser(opts) {
  return resolveUserTangleHubBearer({
    userId: String(opts.userId),
    environment: opts.environment,
    env: opts.env,
    getUserApiKey: () => opts.getUserApiKey(opts.userId)
  });
}
function isTangleBearerMissingError(error) {
  return error instanceof Error && error.name === "TangleBearerMissingError" && typeof error.userId === "string";
}
function isPlatformHubErrorLike(error) {
  return error instanceof Error && error.name === "PlatformHubError" && typeof error.status === "number";
}
function createHubProxyRoutes(ctx) {
  async function proxy(request, call) {
    const userId = await ctx.requireUserId(request);
    try {
      const bearer = await ctx.getBearer(userId);
      return await call(ctx.createHubClient(bearer));
    } catch (err) {
      if (isTangleBearerMissingError(err)) {
        return Response.json({ error: "tangle_link_required" }, { status: 412 });
      }
      if (isPlatformHubErrorLike(err)) {
        return Response.json({ error: err.message, code: err.code }, { status: err.status });
      }
      throw err;
    }
  }
  return {
    catalog: ({ request }) => proxy(request, async (hub) => Response.json({ catalog: await hub.catalog() })),
    connections: ({ request }) => proxy(request, async (hub) => Response.json({ connections: await hub.listConnections() })),
    connectionDelete: async ({ request, params }) => {
      if (request.method !== "DELETE") {
        return Response.json({ error: "Method not allowed" }, { status: 405 });
      }
      return proxy(request, async (hub) => Response.json(await hub.revokeConnection(params.connectionId)));
    },
    healthchecks: ({ request }) => proxy(request, async (hub) => Response.json({ healthchecks: await hub.listHealthchecks() })),
    authStart: async ({ request }) => {
      if (request.method !== "POST") {
        return Response.json({ error: "Method not allowed" }, { status: 405 });
      }
      const userId = await ctx.requireUserId(request);
      let body;
      try {
        body = await request.json();
      } catch {
        return Response.json({ error: "Invalid JSON body" }, { status: 400 });
      }
      if (!body.providerId || !body.connectorId || !body.returnUrl) {
        return Response.json({ error: "providerId, connectorId, and returnUrl are required" }, { status: 400 });
      }
      try {
        const bearer = await ctx.getBearer(userId);
        const result = await ctx.createHubClient(bearer).startAuth({
          providerId: body.providerId,
          connectorId: body.connectorId,
          returnUrl: body.returnUrl,
          requestedScopes: body.requestedScopes
        });
        return Response.json({ authorizationUrl: result.authorizationUrl, state: result.state });
      } catch (err) {
        if (isTangleBearerMissingError(err)) {
          return Response.json({ error: "tangle_link_required" }, { status: 412 });
        }
        if (isPlatformHubErrorLike(err)) {
          return Response.json({ error: err.message, code: err.code }, { status: err.status });
        }
        throw err;
      }
    }
  };
}

// src/platform/billing.ts
function normalizeTanglePlanTier(plan) {
  return plan === "pro" || plan === "enterprise" ? plan : "free";
}
var PlatformBillingHttpError = class extends Error {
  constructor(status, detail) {
    super(`Platform request failed (${status}): ${detail}`);
    this.status = status;
    this.name = "PlatformBillingHttpError";
  }
  status;
};
function isPlatformBillingHttpError(error) {
  return error instanceof Error && error.name === "PlatformBillingHttpError" && typeof error.status === "number";
}
function createPlatformBillingHttp(opts) {
  const baseUrl = opts.baseUrl.replace(/\/+$/, "");
  if (!baseUrl) throw new Error("PlatformBillingHttpOptions.baseUrl is required");
  if (!opts.productSlug) throw new Error("PlatformBillingHttpOptions.productSlug is required");
  const fetchImpl = opts.fetchImpl ?? fetch;
  const timeoutMs = opts.timeoutMs ?? 1e4;
  function resolveServiceToken() {
    const token = typeof opts.serviceToken === "function" ? opts.serviceToken() : opts.serviceToken;
    if (!token) throw new Error("A platform service token is required for deduct");
    return token;
  }
  async function request(path, init, headers) {
    const res = await fetchImpl(`${baseUrl}${path}`, {
      ...init,
      headers,
      signal: AbortSignal.timeout(timeoutMs)
    });
    if (!res.ok) {
      const body = await res.json().catch(() => null);
      throw new PlatformBillingHttpError(res.status, body?.error?.message ?? res.statusText);
    }
    return res.json();
  }
  function userRead(userApiKey, path) {
    const headers = new Headers();
    headers.set("Authorization", `Bearer ${userApiKey}`);
    return request(path, {}, headers);
  }
  return {
    async getSubscription(userApiKey) {
      const body = await userRead(userApiKey, "/v1/plans/current");
      const sub = body.data?.subscription ?? null;
      return { tier: normalizeTanglePlanTier(sub?.plan), status: sub?.status ?? null };
    },
    async getBalance(userApiKey) {
      const body = await userRead(userApiKey, "/v1/billing/balance");
      return {
        balance: body.data?.balance ?? 0,
        lifetimeSpent: body.data?.lifetimeSpent ?? 0,
        updatedAt: body.data?.updatedAt
      };
    },
    async getUsageByProduct(userApiKey) {
      const body = await userRead(userApiKey, "/v1/billing/usage");
      return (body.data ?? []).map((row) => ({
        product: row.product ?? null,
        totalSpent: row.totalSpent ?? 0,
        count: row.count ?? 0
      }));
    },
    async getProductEntitlement(userApiKey, productId) {
      const slug = encodeURIComponent(productId);
      const body = await userRead(userApiKey, `/v1/billing/product-entitlement?product=${slug}`);
      const data = body.data ?? {};
      const hasSeat = data.hasSeat === true;
      return {
        seatStatus: data.seatStatus ?? "none",
        currentPeriodEnd: data.currentPeriodEnd ?? null,
        lifetimeSpentUsd: data.lifetimeSpentUsd ?? 0,
        hasSeat,
        // Free access only when there is no seat AND the platform says so.
        onFreeTier: !hasSeat && data.onFreeTier === true
      };
    },
    async deduct(input) {
      const headers = new Headers();
      headers.set("Authorization", `Bearer ${resolveServiceToken()}`);
      headers.set("X-Service-Name", opts.productSlug);
      headers.set("Content-Type", "application/json");
      await request("/v1/billing/deduct", {
        method: "POST",
        body: JSON.stringify({
          userId: input.platformUserId,
          amount: input.amountUsd,
          type: input.type,
          product: opts.productSlug,
          description: input.description,
          referenceId: input.referenceId
        })
      }, headers);
    },
    billingUrl() {
      return `${baseUrl}/app/billing`;
    },
    seatCheckoutUrl(productId) {
      return seatCheckoutUrl(baseUrl, productId);
    }
  };
}
function seatCheckoutUrl(baseUrl, productId) {
  const root = baseUrl.replace(/\/+$/, "");
  return `${root}/app/billing/seat/checkout?product=${encodeURIComponent(productId)}`;
}
var DEFAULT_TANGLE_TIER_POLICY = {
  free: { concurrency: 1, overageAllowed: false },
  pro: { concurrency: Number.POSITIVE_INFINITY, overageAllowed: true },
  enterprise: { concurrency: Number.POSITIVE_INFINITY, overageAllowed: true }
};
async function readTangleTierState(http, userApiKey, policy = DEFAULT_TANGLE_TIER_POLICY) {
  if (!userApiKey) {
    return {
      tier: "free",
      subscriptionStatus: null,
      remainingBalanceUsd: 0,
      lifetimeSpentUsd: 0,
      ...policy.free
    };
  }
  const [subscription, balance] = await Promise.all([
    http.getSubscription(userApiKey),
    http.getBalance(userApiKey)
  ]);
  return {
    tier: subscription.tier,
    subscriptionStatus: subscription.status,
    remainingBalanceUsd: balance.balance,
    lifetimeSpentUsd: balance.lifetimeSpent,
    ...policy[subscription.tier]
  };
}
var FREE_TIER_SPEND_CAP_USD = 2;
var DEFAULT_SEAT_BILLING_ENABLED_ENV_VAR = "SEAT_BILLING_ENABLED";
function isSeatBillingEnabled(opts = {}) {
  const env = opts.env ?? (typeof process !== "undefined" ? process.env : void 0);
  if (!env) return false;
  const flag = env[opts.flagEnvVar ?? DEFAULT_SEAT_BILLING_ENABLED_ENV_VAR]?.trim().toLowerCase();
  return flag === "true" || flag === "1" || flag === "on" || flag === "enabled";
}
async function getProductEntitlement(http, userApiKey, productId, flag = true) {
  if (!flag || !userApiKey) return failOpenEntitlement();
  try {
    return await http.getProductEntitlement(userApiKey, productId);
  } catch {
    return failOpenEntitlement();
  }
}
function failOpenEntitlement() {
  return {
    seatStatus: "active",
    currentPeriodEnd: null,
    lifetimeSpentUsd: 0,
    hasSeat: true,
    onFreeTier: false
  };
}
function isProductEntitled(ent) {
  return ent.hasSeat || ent.onFreeTier;
}
function createTanglePlatformBillingClient(http, identity) {
  return {
    resolveIdentity: (userId) => identity.resolveIdentity(userId),
    getPlan: async (apiKey) => (await http.getSubscription(apiKey)).tier,
    getBalance: async (apiKey) => {
      const snapshot = await http.getBalance(apiKey);
      return { balance: snapshot.balance, lifetimeSpent: snapshot.lifetimeSpent };
    },
    getUsageByProduct: (apiKey) => http.getUsageByProduct(apiKey),
    deduct: (input) => http.deduct(input)
  };
}
export {
  DEFAULT_SEAT_BILLING_ENABLED_ENV_VAR,
  DEFAULT_TANGLE_TIER_POLICY,
  FREE_TIER_SPEND_CAP_USD,
  PlatformBillingHttpError,
  TangleBearerMissingError,
  TangleSsoUserCreateError,
  assertBillableBalance,
  createAdminGuard,
  createAuthGuard,
  createBetterAuthSessionCookieMinter,
  createHubProxyRoutes,
  createPlatformBillingHttp,
  createSignedSsoState,
  createTanglePlatformBillingClient,
  createTangleSsoHandlers,
  getProductEntitlement,
  guardResolution,
  isPlatformBillingHttpError,
  isPlatformHubErrorLike,
  isProductEntitled,
  isSeatBillingEnabled,
  isTangleBearerMissingError,
  normalizeTanglePlanTier,
  parseAdminEmails,
  readTangleTierState,
  resolveUserTangleHubBearer,
  resolveUserTangleHubBearerForUser,
  seatCheckoutUrl,
  signSessionCookieValue,
  verifySignedSsoState
};
//# sourceMappingURL=index.js.map