import {
  SignJWT,
  exportJWK,
  generateKeyPair
} from "./chunk-D6EKRYGP.js";
import "./chunk-AQ2CLRU3.js";

// ../@emulators/workos/dist/index.js
import { AsyncLocalStorage } from "async_hooks";
import { readFileSync } from "fs";
import { fileURLToPath } from "url";
import { dirname, join } from "path";
var tenantContext = new AsyncLocalStorage();
function createErrorHandler(documentationUrl) {
  return async (c, next) => {
    if (documentationUrl) {
      c.set("docsUrl", documentationUrl);
    }
    await next();
  };
}
var errorHandler = createErrorHandler();
var isDebug = typeof process !== "undefined" && (process.env.DEBUG === "1" || process.env.DEBUG === "true" || process.env.EMULATE_DEBUG === "1");
function authLax() {
  const v = process.env.EMULATE_AUTH_LAX;
  return v === "1" || v === "true";
}
function authFlagEnabled(...flags) {
  return flags.some((f) => {
    const v = process.env[f];
    return v === "1" || v === "true";
  });
}
function requireAuthWhen(...flags) {
  return async (c, next) => {
    if (!authLax() && authFlagEnabled(...flags) && !c.get("authUser")) {
      const docsUrl = c.get("docsUrl") ?? "https://github.com/Vinniai/agent-emulate#readme";
      return c.json({ message: "Requires authentication", documentation_url: docsUrl }, 401);
    }
    await next();
  };
}
var __dirname = dirname(fileURLToPath(import.meta.url));
var FONTS = {
  "geist-sans.woff2": readFileSync(join(__dirname, "fonts", "geist-sans.woff2")),
  "GeistPixel-Square.woff2": readFileSync(join(__dirname, "fonts", "GeistPixel-Square.woff2"))
};
var FAVICON = readFileSync(join(__dirname, "fonts", "favicon.ico"));
var DEFAULT_THEME = {
  slug: "default",
  name: "Emulator",
  scheme: "dark",
  bg: "oklch(0.145 0 0)",
  surface: "oklch(0.205 0 0)",
  border: "oklch(1 0 0 / 10%)",
  text: "oklch(0.985 0 0)",
  muted: "oklch(0.708 0 0)",
  accent: "oklch(0.922 0 0)",
  accentText: "oklch(0.205 0 0)",
  font: "'Geist',-apple-system,BlinkMacSystemFont,sans-serif",
  radius: "0.625rem"
};
var THEMES = {
  google: {
    slug: "google",
    name: "Google",
    scheme: "light",
    bg: "#ffffff",
    surface: "#ffffff",
    border: "#dadce0",
    text: "#202124",
    muted: "#5f6368",
    accent: "#1a73e8",
    accentText: "#ffffff",
    font: "'Google Sans',Roboto,Arial,sans-serif",
    radius: "4px"
  },
  microsoft: {
    slug: "microsoft",
    name: "Microsoft",
    scheme: "light",
    bg: "#ffffff",
    surface: "#ffffff",
    border: "#d1d1d1",
    text: "#1b1b1b",
    muted: "#605e5c",
    accent: "#0067b8",
    accentText: "#ffffff",
    font: "'Segoe UI',-apple-system,sans-serif",
    radius: "2px"
  },
  apple: {
    slug: "apple",
    name: "Apple",
    scheme: "light",
    bg: "#ffffff",
    surface: "#ffffff",
    border: "#d2d2d7",
    text: "#1d1d1f",
    muted: "#6e6e73",
    accent: "#0066cc",
    accentText: "#ffffff",
    font: "-apple-system,'SF Pro Text',Helvetica,sans-serif",
    radius: "12px"
  },
  github: {
    slug: "github",
    name: "GitHub",
    scheme: "light",
    bg: "#ffffff",
    surface: "#ffffff",
    border: "#d1d9e0",
    text: "#1f2328",
    muted: "#59636e",
    accent: "#1f883d",
    accentText: "#ffffff",
    font: "-apple-system,'Mona Sans','Segoe UI',Helvetica,sans-serif",
    radius: "6px"
  },
  okta: {
    slug: "okta",
    name: "Okta",
    scheme: "light",
    bg: "#f9f9f9",
    surface: "#ffffff",
    border: "#e1e1e1",
    text: "#1d1d21",
    muted: "#6e6e78",
    accent: "#3f59e4",
    accentText: "#ffffff",
    font: "'Aeonik',-apple-system,sans-serif",
    radius: "4px"
  },
  slack: {
    slug: "slack",
    name: "Slack",
    scheme: "light",
    bg: "#ffffff",
    surface: "#ffffff",
    border: "#dddddd",
    text: "#1d1c1d",
    muted: "#616061",
    accent: "#4a154b",
    accentText: "#ffffff",
    font: "Lato,-apple-system,sans-serif",
    radius: "8px"
  },
  salesforce: {
    slug: "salesforce",
    name: "Salesforce",
    scheme: "light",
    bg: "#f4f6f9",
    surface: "#ffffff",
    border: "#c9c9c9",
    text: "#080707",
    muted: "#54698d",
    accent: "#0070d2",
    accentText: "#ffffff",
    font: "'Salesforce Sans',-apple-system,sans-serif",
    radius: "4px"
  },
  workos: {
    slug: "workos",
    name: "WorkOS",
    scheme: "light",
    bg: "#ffffff",
    surface: "#ffffff",
    border: "#e4e4e7",
    text: "#18181b",
    muted: "#6b7280",
    accent: "#6363f1",
    accentText: "#ffffff",
    font: "'Inter',-apple-system,sans-serif",
    radius: "8px"
  },
  clerk: {
    slug: "clerk",
    name: "Clerk",
    scheme: "light",
    bg: "#ffffff",
    surface: "#ffffff",
    border: "#eeeef0",
    text: "#212126",
    muted: "#747686",
    accent: "#6c47ff",
    accentText: "#ffffff",
    font: "'Inter',-apple-system,sans-serif",
    radius: "8px"
  },
  hubspot: {
    slug: "hubspot",
    name: "HubSpot",
    scheme: "light",
    bg: "#f5f8fa",
    surface: "#ffffff",
    border: "#cbd6e2",
    text: "#33475b",
    muted: "#516f90",
    accent: "#ff7a59",
    accentText: "#ffffff",
    font: "'Lexend Deca',-apple-system,sans-serif",
    radius: "6px"
  },
  stripe: {
    slug: "stripe",
    name: "Stripe",
    scheme: "light",
    bg: "#ffffff",
    surface: "#ffffff",
    border: "#e6e6e6",
    text: "#1a1f36",
    muted: "#697386",
    accent: "#635bff",
    accentText: "#ffffff",
    font: "-apple-system,'Helvetica Neue',sans-serif",
    radius: "8px"
  },
  vercel: {
    slug: "vercel",
    name: "Vercel",
    scheme: "light",
    bg: "#ffffff",
    surface: "#ffffff",
    border: "#eaeaea",
    text: "#171717",
    muted: "#888888",
    accent: "#171717",
    accentText: "#ffffff",
    font: "'Geist',-apple-system,sans-serif",
    radius: "6px"
  },
  resend: {
    slug: "resend",
    name: "Resend",
    scheme: "dark",
    bg: "#000000",
    surface: "#0c0c0c",
    border: "#262626",
    text: "#fafafa",
    muted: "#a3a3a3",
    accent: "#ffffff",
    accentText: "#000000",
    font: "-apple-system,'Inter',sans-serif",
    radius: "8px"
  },
  nango: {
    slug: "nango",
    name: "Nango",
    scheme: "light",
    bg: "#ffffff",
    surface: "#ffffff",
    border: "#e5e7eb",
    text: "#111827",
    muted: "#6b7280",
    accent: "#467df4",
    accentText: "#ffffff",
    font: "'Inter',-apple-system,sans-serif",
    radius: "8px"
  },
  simpro: {
    slug: "simpro",
    name: "Simpro",
    scheme: "light",
    bg: "#ffffff",
    surface: "#ffffff",
    border: "#dde3ea",
    text: "#1f2d3d",
    muted: "#5b6b7b",
    accent: "#0a8a3f",
    accentText: "#ffffff",
    font: "-apple-system,'Open Sans',sans-serif",
    radius: "4px"
  }
};
function getTheme(service) {
  if (!service) return DEFAULT_THEME;
  return THEMES[service.toLowerCase()] ?? DEFAULT_THEME;
}
function themeOverrideCss(theme) {
  if (theme.slug === "default") return "";
  return `
body{background:${theme.bg};color:${theme.text};font-family:${theme.font};}
.emu-bar{background:${theme.scheme === "dark" ? "#000" : "#1b1b1f"};border-bottom-color:rgba(255,255,255,.08);color:#ffd166;}
.emu-bar-title{color:#fff;font-family:${theme.font};}
.emu-bar-links a{color:#bdbdbd;}
.emu-bar-links a:hover{color:#fff;}
.content-inner{background:${theme.surface};border:1px solid ${theme.border};border-radius:${theme.radius};padding:32px 28px;box-shadow:0 1px 3px rgba(0,0,0,.08);}
.card-title{color:${theme.text};font-family:${theme.font};font-weight:600;}
.card-subtitle{color:${theme.muted};}
.user-btn{background:${theme.surface};border:1px solid ${theme.border};color:${theme.text};border-radius:${theme.radius};}
.user-btn:hover{border-color:${theme.accent};background:${theme.scheme === "dark" ? "rgba(255,255,255,.04)" : "rgba(0,0,0,.02)"};}
.avatar{background:${theme.accent};color:${theme.accentText};font-family:${theme.font};}
.user-login{color:${theme.text};}
.user-meta{color:${theme.muted};}
.user-email{color:${theme.muted};opacity:.8;}
.powered-by{color:${theme.muted};}
.powered-by a{color:${theme.accent};}
.error-title{font-family:${theme.font};}
.error-msg{color:${theme.muted};}
`.trim();
}
var google = `<svg viewBox="0 0 48 48" width="42" height="42" aria-hidden="true"><path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"/><path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"/><path fill="#FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"/><path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"/></svg>`;
var microsoft = `<svg viewBox="0 0 23 23" width="36" height="36" aria-hidden="true"><path fill="#f25022" d="M1 1h10v10H1z"/><path fill="#7fba00" d="M12 1h10v10H12z"/><path fill="#00a4ef" d="M1 12h10v10H1z"/><path fill="#ffb900" d="M12 12h10v10H12z"/></svg>`;
var apple = `<svg viewBox="0 0 24 24" width="40" height="40" fill="#000" aria-hidden="true"><path d="M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701"/></svg>`;
var github = `<svg viewBox="0 0 24 24" width="40" height="40" fill="#1f2328" aria-hidden="true"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>`;
var okta = `<svg viewBox="0 0 24 24" width="38" height="38" fill="#00297a" aria-hidden="true"><path d="M12 0C5.385 0 0 5.385 0 12s5.385 12 12 12 12-5.385 12-12S18.615 0 12 0zm0 18c-3.309 0-6-2.691-6-6s2.691-6 6-6 6 2.691 6 6-2.691 6-6 6z"/></svg>`;
var slack = `<svg viewBox="0 0 122.8 122.8" width="36" height="36" aria-hidden="true"><path d="M25.8 77.6c0 7.1-5.8 12.9-12.9 12.9S0 84.7 0 77.6s5.8-12.9 12.9-12.9h12.9v12.9zm6.5 0c0-7.1 5.8-12.9 12.9-12.9s12.9 5.8 12.9 12.9v32.3c0 7.1-5.8 12.9-12.9 12.9s-12.9-5.8-12.9-12.9V77.6z" fill="#36C5F0"/><path d="M45.2 25.8c-7.1 0-12.9-5.8-12.9-12.9S38.1 0 45.2 0s12.9 5.8 12.9 12.9v12.9H45.2zm0 6.5c7.1 0 12.9 5.8 12.9 12.9s-5.8 12.9-12.9 12.9H12.9C5.8 58.1 0 52.3 0 45.2s5.8-12.9 12.9-12.9h32.3z" fill="#2EB67D"/><path d="M97 45.2c0-7.1 5.8-12.9 12.9-12.9s12.9 5.8 12.9 12.9-5.8 12.9-12.9 12.9H97V45.2zm-6.5 0c0 7.1-5.8 12.9-12.9 12.9s-12.9-5.8-12.9-12.9V12.9C64.7 5.8 70.5 0 77.6 0s12.9 5.8 12.9 12.9v32.3z" fill="#ECB22E"/><path d="M77.6 97c7.1 0 12.9 5.8 12.9 12.9s-5.8 12.9-12.9 12.9-12.9-5.8-12.9-12.9V97h12.9zm0-6.5c-7.1 0-12.9-5.8-12.9-12.9s5.8-12.9 12.9-12.9h32.3c7.1 0 12.9 5.8 12.9 12.9s-5.8 12.9-12.9 12.9H77.6z" fill="#E01E5A"/></svg>`;
var salesforce = `<svg viewBox="0 0 24 24" width="46" height="46" fill="#00A1E0" aria-hidden="true"><path d="M9.9 6.2c.72-.78 1.79-1.3 2.96-1.3 1.55 0 2.92.86 3.64 2.16.62-.28 1.31-.43 2.03-.43 2.3 0 4.17 1.88 4.17 4.2s-1.87 4.2-4.17 4.2c-.28 0-.56-.03-.83-.08-.62 1.11-1.81 1.86-3.17 1.86-.5 0-.98-.1-1.42-.29-.63 1.4-2.03 2.38-3.66 2.38-1.66 0-3.1-1.01-3.71-2.46-.23.05-.47.07-.71.07C1.55 16.61 0 15.04 0 13.11c0-1.29.69-2.42 1.72-3.04-.13-.39-.2-.81-.2-1.24 0-2.2 1.79-3.99 4-3.99 1.29 0 2.45.62 3.18 1.57.04-.07.08-.14.2-.21z"/></svg>`;
var hubspot = `<svg viewBox="0 0 24 24" width="40" height="40" fill="#FF7A59" aria-hidden="true"><path d="M18 7.32V5.13a1.74 1.74 0 1 0-1.16 0v2.19a5.05 5.05 0 0 0-2.4.98L7.97 3.43a1.95 1.95 0 1 0-.92 1.21l6.32 4.91a5.06 5.06 0 0 0 .08 5.71l-1.92 1.92a1.63 1.63 0 0 0-.47-.07 1.65 1.65 0 1 0 1.65 1.65 1.63 1.63 0 0 0-.07-.47l1.9-1.9a5.06 5.06 0 1 0 3.46-9.07zm-1.55 7.6a2.64 2.64 0 1 1 2.64-2.64 2.64 2.64 0 0 1-2.64 2.64z"/></svg>`;
var vercel = `<svg viewBox="0 0 24 24" width="34" height="34" fill="#000" aria-hidden="true"><path d="M12 2 24 22H0z"/></svg>`;
var clerk = `<svg viewBox="0 0 40 40" width="40" height="40" aria-hidden="true"><rect width="40" height="40" rx="9" fill="#6C47FF"/><circle cx="20" cy="16.5" r="4.2" fill="#fff"/><path d="M13 28a7.6 7.6 0 0 1 14 0z" fill="#fff"/></svg>`;
var workos = `<svg viewBox="0 0 40 40" width="40" height="40" aria-hidden="true"><rect width="40" height="40" rx="9" fill="#6363F1"/><path d="M10 14l3 12 3-9 3 9 3-12" fill="none" stroke="#fff" stroke-width="2.2" stroke-linejoin="round" stroke-linecap="round"/><path d="M25 20a4.5 4.5 0 1 0 4.5 4.5" fill="none" stroke="#fff" stroke-width="2.2" stroke-linecap="round"/></svg>`;
var LOGOS = {
  google,
  microsoft,
  apple,
  github,
  okta,
  slack,
  salesforce,
  hubspot,
  vercel,
  clerk,
  workos
};
function getLogo(service) {
  if (!service) return null;
  return LOGOS[service.toLowerCase()] ?? null;
}
function escapeHtml(s) {
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
}
function escapeAttr(s) {
  return escapeHtml(s).replace(/'/g, "&#39;");
}
var CSS = `
@font-face{
  font-family:'Geist';font-style:normal;font-weight:100 900;font-display:swap;
  src:url('/_emulate/fonts/geist-sans.woff2') format('woff2');
}
:root{
  color-scheme:dark;
  /* ElevenLabs UI \u2014 neutral dark (OKLCH). Values already avoid pure #000/#fff. */
  --bg:oklch(0.145 0 0);
  --fg:oklch(0.985 0 0);
  --card:oklch(0.205 0 0);
  --elevated:oklch(0.269 0 0);
  --muted:oklch(0.269 0 0);
  --muted-fg:oklch(0.708 0 0);
  --faint-fg:oklch(0.556 0 0);
  --border:oklch(1 0 0 / 10%);
  --border-strong:oklch(1 0 0 / 16%);
  --ring:oklch(0.556 0 0);
  --primary:oklch(0.922 0 0);
  --primary-fg:oklch(0.205 0 0);
  --danger:oklch(0.704 0.191 22.216);
  --radius:0.625rem;
  --radius-sm:0.375rem;
  --radius-lg:0.875rem;
  --radius-pill:999px;
  --space-xs:0.25rem;--space-sm:0.5rem;--space-md:0.75rem;
  --space-lg:1rem;--space-xl:1.5rem;--space-2xl:2rem;--space-3xl:3rem;
  --text-xs:0.75rem;--text-sm:0.8125rem;--text-md:0.875rem;
  --text-base:1rem;--text-lg:1.25rem;--text-xl:1.5rem;
  --font-sans:'Geist',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
  --font-mono:ui-monospace,'SF Mono',SFMono-Regular,Menlo,Consolas,monospace;
}
*{box-sizing:border-box;margin:0;padding:0}
body{
  font-family:var(--font-sans);font-size:var(--text-md);line-height:1.55;
  background:var(--bg);color:var(--fg);min-height:100vh;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
}
::selection{background:var(--primary);color:var(--primary-fg);}

.emu-bar{
  border-bottom:1px solid var(--border);padding:var(--space-md) var(--space-xl);
  display:flex;align-items:center;gap:var(--space-md);
  font-size:var(--text-sm);color:var(--muted-fg);
}
.emu-bar-title{font-weight:600;color:var(--fg);letter-spacing:-0.01em;}
.emu-badge{
  display:inline-flex;align-items:center;gap:var(--space-xs);
  font-size:var(--text-xs);font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  padding:3px 10px;border-radius:var(--radius-pill);
  background:var(--primary);color:var(--primary-fg);
  white-space:nowrap;flex-shrink:0;
}
.emu-badge::before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor;}
.emu-watermark{
  position:fixed;bottom:var(--space-lg);right:var(--space-lg);z-index:9999;pointer-events:none;
  font-size:var(--text-xs);font-weight:600;letter-spacing:.1em;text-transform:uppercase;
  padding:5px 11px;border-radius:var(--radius-sm);
  background:color-mix(in oklch,var(--bg) 72%,transparent);
  color:var(--muted-fg);border:1px solid var(--border-strong);
  backdrop-filter:blur(6px);
}
.emu-bar-links{margin-left:auto;display:flex;gap:var(--space-xl);}
.emu-bar-links a{
  color:var(--muted-fg);font-size:var(--text-sm);text-decoration:none;transition:color .15s;
}
.emu-bar-links a:hover{color:var(--fg);}
.emu-bar-links a .full{display:inline;}
.emu-bar-links a .short{display:none;}
@media(max-width:600px){
  .emu-bar-links a .full{display:none;}
  .emu-bar-links a .short{display:inline;}
}

.content{
  display:flex;align-items:center;justify-content:center;
  min-height:calc(100vh - 50px);padding:var(--space-2xl) var(--space-lg);
}
.content-inner{width:100%;max-width:420px;}
.brand-logo{display:flex;justify-content:center;margin-bottom:var(--space-xl);}
.brand-logo svg{display:block;}
.card-branded{text-align:center;}
.card-branded .card-title{text-align:center;}
.card-branded .card-subtitle{text-align:center;}
.card-branded .user-form{text-align:left;}
.card-title{
  font-size:var(--text-lg);font-weight:600;letter-spacing:-0.02em;
  margin-bottom:var(--space-xs);color:var(--fg);
}
.card-subtitle{color:var(--muted-fg);font-size:var(--text-sm);margin-bottom:var(--space-xl);line-height:1.5;}
.powered-by{
  position:fixed;bottom:0;left:0;right:0;
  text-align:center;padding:var(--space-md);font-size:var(--text-xs);color:var(--faint-fg);
}
.powered-by a{color:var(--muted-fg);text-decoration:none;transition:color .15s;}
.powered-by a:hover{color:var(--fg);}

.error-title{color:var(--danger);font-size:var(--text-lg);font-weight:600;margin-bottom:var(--space-sm);letter-spacing:-0.01em;}
.error-msg{color:var(--muted-fg);font-size:var(--text-md);line-height:1.5;}
.error-card{text-align:center;}

.user-form{margin-bottom:var(--space-sm);}
.user-form:last-of-type{margin-bottom:0;}
.user-btn{
  width:100%;display:flex;align-items:center;gap:var(--space-md);
  padding:var(--space-md);border:1px solid var(--border);border-radius:var(--radius);
  background:var(--card);color:inherit;cursor:pointer;text-align:left;
  font:inherit;transition:border-color .15s,background .15s;
}
.user-btn:hover{border-color:var(--border-strong);background:var(--elevated);}
.avatar{
  width:36px;height:36px;border-radius:50%;
  background:var(--elevated);color:var(--fg);font-weight:600;font-size:var(--text-md);
  display:flex;align-items:center;justify-content:center;flex-shrink:0;
}
.user-text{min-width:0;}
.user-login{font-weight:600;font-size:var(--text-md);display:block;color:var(--fg);}
.user-meta{color:var(--muted-fg);font-size:var(--text-xs);margin-top:1px;}
.user-email{font-size:var(--text-xs);color:var(--faint-fg);word-break:break-all;margin-top:1px;}

.settings-layout{
  max-width:920px;margin:0 auto;padding:var(--space-3xl) var(--space-xl);
  display:flex;gap:var(--space-3xl);
}
.settings-sidebar{width:200px;flex-shrink:0;}
.settings-sidebar a{
  display:block;padding:6px 10px;border-radius:var(--radius-sm);color:var(--muted-fg);
  text-decoration:none;font-size:var(--text-sm);transition:color .15s,background .15s;
}
.settings-sidebar a:hover{color:var(--fg);background:var(--muted);}
.settings-sidebar a.active{color:var(--fg);font-weight:600;background:var(--muted);}
.settings-main{flex:1;min-width:0;}

.s-card{
  padding:var(--space-xl) 0;margin-bottom:var(--space-lg);border-bottom:1px solid var(--border);
}
.s-card:last-child{border-bottom:none;}
.s-card-header{display:flex;align-items:center;gap:var(--space-md);margin-bottom:var(--space-lg);}
.s-icon{
  width:40px;height:40px;border-radius:var(--radius);
  background:var(--elevated);display:flex;align-items:center;justify-content:center;
  font-size:var(--text-base);font-weight:600;color:var(--muted-fg);flex-shrink:0;
}
.s-title{font-size:var(--text-lg);font-weight:600;color:var(--fg);letter-spacing:-0.01em;}
.s-subtitle{font-size:var(--text-xs);color:var(--muted-fg);margin-top:2px;}
.section-heading{
  font-size:var(--text-md);font-weight:600;margin-bottom:var(--space-md);color:var(--fg);
  display:flex;align-items:center;justify-content:space-between;
}
.perm-list{list-style:none;}
.perm-list li{padding:5px 0;font-size:var(--text-sm);display:flex;align-items:center;gap:var(--space-sm);color:var(--muted-fg);}
.check{color:var(--fg);}
.org-row{
  display:flex;align-items:center;gap:var(--space-sm);padding:7px 0;
  border-bottom:1px solid var(--border);font-size:var(--text-sm);
}
.org-row:last-child{border-bottom:none;}
.org-icon{
  width:22px;height:22px;border-radius:var(--radius-sm);background:var(--elevated);
  display:flex;align-items:center;justify-content:center;
  font-size:var(--text-xs);font-weight:600;color:var(--muted-fg);flex-shrink:0;
}
.org-name{font-weight:600;color:var(--fg);}
.badge{
  font-size:var(--text-xs);padding:2px 8px;border-radius:var(--radius-sm);font-weight:500;
  background:var(--muted);color:var(--muted-fg);border:1px solid var(--border);
}
.badge-granted{background:var(--elevated);color:var(--fg);}
.badge-denied{background:color-mix(in oklch,var(--danger) 18%,var(--bg));color:var(--danger);border-color:color-mix(in oklch,var(--danger) 30%,transparent);}
.badge-requested{background:var(--muted);color:var(--muted-fg);}
.btn-revoke{
  display:inline-block;padding:5px 14px;border-radius:var(--radius-sm);
  border:1px solid var(--border);background:transparent;color:var(--danger);
  font-size:var(--text-xs);font-weight:600;cursor:pointer;transition:border-color .15s;
}
.btn-revoke:hover{border-color:var(--danger);}
.info-text{color:var(--muted-fg);font-size:var(--text-xs);line-height:1.5;margin-top:var(--space-md);}
.app-link{
  display:flex;align-items:center;gap:var(--space-md);padding:var(--space-md);
  border:1px solid var(--border);border-radius:var(--radius);background:var(--card);
  text-decoration:none;color:inherit;margin-bottom:var(--space-sm);transition:border-color .15s,background .15s;
}
.app-link:hover{border-color:var(--border-strong);background:var(--elevated);}
.app-link-name{font-weight:600;font-size:var(--text-md);color:var(--fg);}
.app-link-scopes{font-size:var(--text-xs);color:var(--muted-fg);margin-top:1px;}
.empty{color:var(--muted-fg);text-align:center;padding:var(--space-3xl) 0;font-size:var(--text-md);}

.inspector-layout{max-width:960px;margin:0 auto;padding:var(--space-3xl) var(--space-xl);}
.inspector-tabs{
  display:flex;flex-wrap:wrap;gap:var(--space-xs);margin-bottom:var(--space-2xl);
  padding:var(--space-xs);background:var(--card);border:1px solid var(--border);
  border-radius:var(--radius);width:fit-content;max-width:100%;
}
.inspector-tabs a{
  padding:6px 14px;border-radius:var(--radius-sm);text-decoration:none;
  font-size:var(--text-sm);color:var(--muted-fg);transition:color .15s,background .15s;
}
.inspector-tabs a:hover{color:var(--fg);}
.inspector-tabs a.active{color:var(--fg);font-weight:600;background:var(--elevated);}
.inspector-section{margin-bottom:var(--space-2xl);}
.inspector-section h2{
  font-size:var(--text-lg);font-weight:600;color:var(--fg);
  margin-bottom:var(--space-md);letter-spacing:-0.01em;
}
.inspector-section h3{
  font-size:var(--text-md);font-weight:600;color:var(--muted-fg);
  margin:var(--space-xl) 0 var(--space-sm);
}
.inspector-table{width:100%;border-collapse:collapse;margin-bottom:var(--space-md);}
.inspector-table th,.inspector-table td{
  text-align:left;padding:var(--space-sm) var(--space-md);border-bottom:1px solid var(--border);
  font-size:var(--text-sm);
}
.inspector-table th{color:var(--faint-fg);font-weight:600;font-size:var(--text-xs);text-transform:uppercase;letter-spacing:.06em;}
.inspector-table td{color:var(--fg);}
.inspector-table tbody tr{transition:background .12s;}
.inspector-table tbody tr:hover{background:var(--card);}
.inspector-empty{color:var(--muted-fg);text-align:center;padding:var(--space-xl) 0;font-size:var(--text-sm);}

/* Live activity feed (renderActivityCard) \u2014 token-driven so it stays cohesive
   with the dark control plane instead of the old hard-coded light values. */
.act-pulse{
  width:9px;height:9px;border-radius:50%;background:var(--fg);flex-shrink:0;
  position:relative;
}
.act-pulse::after{
  content:"";position:absolute;inset:-4px;border-radius:50%;
  border:1px solid var(--fg);opacity:.5;animation:act-ping 1.8s ease-out infinite;
}
@keyframes act-ping{0%{transform:scale(.6);opacity:.5}80%,100%{transform:scale(1.6);opacity:0}}
@media(prefers-reduced-motion:reduce){.act-pulse::after{animation:none;}}
.act-status.is-live{color:var(--fg);}
.act-status.is-error{color:var(--danger);}
.act-mono{font-family:var(--font-mono);font-size:var(--text-xs);color:var(--muted-fg);white-space:nowrap;}
.act-fields{font-size:var(--text-xs);color:var(--muted-fg);}
.act-json-btn{
  font:inherit;font-size:var(--text-xs);padding:2px 9px;border:1px solid var(--border);
  border-radius:var(--radius-sm);background:transparent;color:var(--muted-fg);
  cursor:pointer;transition:border-color .15s,color .15s;
}
.act-json-btn:hover{border-color:var(--border-strong);color:var(--fg);}
.act-detail-cell{background:var(--card);padding:var(--space-sm) var(--space-md);}
.act-detail-cell pre{
  margin:0;font-family:var(--font-mono);font-size:var(--text-xs);line-height:1.5;
  color:var(--muted-fg);white-space:pre-wrap;word-break:break-word;max-height:300px;overflow:auto;
}
.inspector-table tbody tr.act-row-new td{background:color-mix(in oklch,var(--elevated) 80%,transparent);transition:background .9s;}

.checkout-layout{display:flex;min-height:calc(100vh - 50px);}
.checkout-summary{
  flex:1;background:var(--card);padding:var(--space-3xl) var(--space-2xl) var(--space-3xl) 10%;
  display:flex;flex-direction:column;justify-content:center;border-right:1px solid var(--border);
}
.checkout-form-side{
  flex:1;background:var(--bg);padding:var(--space-3xl) 10% var(--space-3xl) var(--space-2xl);
  display:flex;flex-direction:column;justify-content:center;
}
.checkout-merchant{display:flex;align-items:center;gap:var(--space-md);margin-bottom:6px;}
.checkout-merchant-name{font-size:var(--text-md);font-weight:600;color:var(--fg);}
.checkout-test-badge{
  font-size:var(--text-xs);font-weight:600;letter-spacing:.04em;text-transform:uppercase;
  background:var(--muted);color:var(--muted-fg);padding:2px 8px;border-radius:var(--radius-sm);
}
.checkout-total{font-size:var(--text-xl);font-weight:700;color:var(--fg);margin:var(--space-sm) 0 var(--space-2xl);letter-spacing:-0.02em;}
.checkout-line-item{display:flex;align-items:center;gap:var(--space-md);padding:var(--space-lg) 0;border-bottom:1px solid var(--border);}
.checkout-line-item:first-child{border-top:1px solid var(--border);}
.checkout-item-icon{
  width:40px;height:40px;border-radius:var(--radius-sm);background:var(--elevated);
  display:flex;align-items:center;justify-content:center;flex-shrink:0;
  font-size:var(--text-md);font-weight:600;color:var(--muted-fg);
}
.checkout-item-details{flex:1;min-width:0;}
.checkout-item-name{font-size:var(--text-md);font-weight:600;color:var(--fg);}
.checkout-item-qty{font-size:var(--text-xs);color:var(--muted-fg);margin-top:2px;}
.checkout-item-price{font-size:var(--text-md);font-weight:600;color:var(--fg);text-align:right;white-space:nowrap;}
.checkout-item-unit{font-size:var(--text-xs);color:var(--muted-fg);text-align:right;margin-top:2px;}
.checkout-totals{margin-top:var(--space-xl);}
.checkout-totals-row{display:flex;justify-content:space-between;padding:6px 0;font-size:var(--text-sm);color:var(--muted-fg);}
.checkout-totals-row.total{border-top:1px solid var(--border);margin-top:var(--space-sm);padding-top:var(--space-lg);font-size:var(--text-md);font-weight:600;color:var(--fg);}
.checkout-form-section{margin-bottom:var(--space-xl);}
.checkout-form-label{font-size:var(--text-sm);font-weight:600;color:var(--fg);margin-bottom:var(--space-sm);display:block;}
.checkout-input{
  width:100%;padding:var(--space-md);border:1px solid var(--border);border-radius:var(--radius-sm);
  background:var(--card);color:var(--fg);font:inherit;font-size:var(--text-md);
  transition:border-color .15s;outline:none;
}
.checkout-input:focus{border-color:var(--ring);}
.checkout-input::placeholder{color:var(--faint-fg);}
.checkout-card-box{border:1px solid var(--border);border-radius:var(--radius-sm);padding:var(--space-lg);background:var(--card);}
.checkout-card-row{display:flex;gap:var(--space-md);margin-top:var(--space-md);}
.checkout-card-row .checkout-input{flex:1;}
.checkout-sim-note{font-size:var(--text-xs);color:var(--muted-fg);margin-top:var(--space-md);text-align:center;font-style:italic;}
.checkout-pay-btn{
  width:100%;padding:var(--space-lg);border:none;border-radius:var(--radius);
  background:var(--primary);color:var(--primary-fg);font:inherit;font-size:var(--text-md);font-weight:600;
  cursor:pointer;transition:opacity .15s;
}
.checkout-pay-btn:hover{opacity:.9;}
.checkout-cancel{text-align:center;margin-top:var(--space-lg);}
.checkout-cancel a{color:var(--muted-fg);text-decoration:none;font-size:var(--text-sm);transition:color .15s;}
.checkout-cancel a:hover{color:var(--fg);}
@media(max-width:768px){
  .checkout-layout{flex-direction:column;}
  .checkout-summary{padding:var(--space-2xl) var(--space-xl);border-right:none;border-bottom:1px solid var(--border);}
  .checkout-form-side{padding:var(--space-2xl) var(--space-xl);}
}
`;
var POWERED_BY = `<div class="powered-by">Powered by <a href="https://github.com/Vinniai/agent-emulate#readme" target="_blank" rel="noopener">agent-emulate</a></div>`;
var WATERMARK = `<div class="emu-watermark" aria-hidden="true">agent-emulate</div>`;
function emuBar(service) {
  const title = service ? `${escapeHtml(service)} Emulator` : "Emulator";
  return `<div class="emu-bar">
  <span class="emu-bar-title">${title}</span>
  <span class="emu-badge" title="This is a local emulator, not the real provider">Emulated</span>
  <nav class="emu-bar-links">
    <a href="https://github.com/Vinniai/agent-emulate/issues" target="_blank" rel="noopener"><span class="full">Report Issue</span><span class="short">Report</span></a>
    <a href="https://github.com/Vinniai/agent-emulate" target="_blank" rel="noopener"><span class="full">Source Code</span><span class="short">Source</span></a>
    <a href="https://github.com/Vinniai/agent-emulate#readme" target="_blank" rel="noopener"><span class="full">Learn More</span><span class="short">Learn</span></a>
  </nav>
</div>`;
}
function head(title, service) {
  const themeCss = themeOverrideCss(getTheme(service));
  const themeStyle = themeCss ? `<style>${themeCss}</style>` : "";
  return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<link rel="icon" href="/_emulate/favicon.ico"/>
<title>${escapeHtml(title)} | agent-emulate</title>
<style>${CSS}</style>${themeStyle}
</head>`;
}
function renderCardPage(title, subtitle, body, service) {
  const logo = getLogo(service);
  const logoHtml = logo ? `<div class="brand-logo">${logo}</div>` : "";
  return `${head(title, service)}
<body>
${emuBar(service)}
<div class="content">
  <div class="content-inner${logo ? " card-branded" : ""}">
    ${logoHtml}
    <div class="card-title">${escapeHtml(title)}</div>
    <div class="card-subtitle">${subtitle}</div>
    ${body}
  </div>
</div>
${POWERED_BY}
${WATERMARK}
</body></html>`;
}
function renderErrorPage(title, message, service) {
  const logo = getLogo(service);
  const logoHtml = logo ? `<div class="brand-logo">${logo}</div>` : "";
  return `${head(title, service)}
<body>
${emuBar(service)}
<div class="content">
  <div class="content-inner error-card">
    ${logoHtml}
    <div class="error-title">${escapeHtml(title)}</div>
    <div class="error-msg">${escapeHtml(message)}</div>
  </div>
</div>
${POWERED_BY}
${WATERMARK}
</body></html>`;
}
function renderSettingsPage(title, sidebarHtml, bodyHtml, service) {
  return `${head(title, service)}
<body>
${emuBar(service)}
<div class="settings-layout">
  <nav class="settings-sidebar">${sidebarHtml}</nav>
  <div class="settings-main">${bodyHtml}</div>
</div>
${POWERED_BY}
${WATERMARK}
</body></html>`;
}
function renderUserButton(opts) {
  const hiddens = Object.entries(opts.hiddenFields).map(([k, v]) => `<input type="hidden" name="${escapeAttr(k)}" value="${escapeAttr(v)}"/>`).join("");
  const nameLine = opts.name ? `<div class="user-meta">${escapeHtml(opts.name)}</div>` : "";
  const emailLine = opts.email ? `<div class="user-email">${escapeHtml(opts.email)}</div>` : "";
  return `<form class="user-form" method="post" action="${escapeAttr(opts.formAction)}">
${hiddens}
<button type="submit" class="user-btn">
  <span class="avatar">${escapeHtml(opts.letter)}</span>
  <span class="user-text">
    <span class="user-login">${escapeHtml(opts.login)}</span>
    ${nameLine}${emailLine}
  </span>
</button>
</form>`;
}
var RING_SIZE = 200;
var ActivityBus = class {
  buffer = [];
  subscribers = /* @__PURE__ */ new Set();
  publish(event) {
    this.buffer.push(event);
    if (this.buffer.length > RING_SIZE) this.buffer.splice(0, this.buffer.length - RING_SIZE);
    for (const cb of this.subscribers) {
      try {
        cb(event);
      } catch {
      }
    }
  }
  subscribe(cb) {
    this.subscribers.add(cb);
    return () => this.subscribers.delete(cb);
  }
  recent(limit = 50, service) {
    const filtered = service ? this.buffer.filter((e) => e.service === service) : this.buffer;
    return filtered.slice(-limit).reverse();
  }
};
var activityBus = globalThis.__emulate_activity_bus__ ?? (globalThis.__emulate_activity_bus__ = new ActivityBus());
var privateKey;
var jwkData;
var kid = "workos-emulator-key-1";
async function ensureKeys() {
  if (privateKey) return;
  const { privateKey: priv, publicKey: pub } = await generateKeyPair("RS256", {
    extractable: true
  });
  privateKey = priv;
  jwkData = await exportJWK(pub);
  jwkData.kid = kid;
  jwkData.use = "sig";
  jwkData.alg = "RS256";
}
async function getJWKS() {
  await ensureKeys();
  return { keys: [jwkData] };
}
async function signJWT(payload, options) {
  await ensureKeys();
  return new SignJWT(payload).setProtectedHeader({ alg: "RS256", kid }).setIssuedAt().setIssuer(options.issuer).setExpirationTime(options.expiresIn ?? "1h").sign(privateKey);
}
function discoveryRoutes(app, baseUrl) {
  app.get("/sso/jwks/:clientId", async (c) => {
    return c.json(await getJWKS());
  });
  app.get("/.well-known/openid-configuration", (c) => {
    const base = baseUrl.replace(/\/$/, "");
    return c.json({
      issuer: `${base}/`,
      authorization_endpoint: `${base}/user_management/authorize`,
      token_endpoint: `${base}/user_management/authenticate/code`,
      jwks_uri: `${base}/sso/jwks/default`,
      response_types_supported: ["code"],
      grant_types_supported: ["authorization_code", "refresh_token"],
      subject_types_supported: ["public"],
      id_token_signing_alg_values_supported: ["RS256"]
    });
  });
}
function invitationRoutes(app, ws, webhooks) {
  app.post("/user_management/invitations", async (c) => {
    const body = await c.req.json();
    const orgId = body.organizationId ?? body.organization_id ?? "";
    const role = body.roleSlug ?? body.role_slug ?? void 0;
    const invitation = ws.insertInvitation(body.email, orgId, role);
    webhooks.dispatch("user_invitation.created", void 0, { invitation }, "workos").catch(() => {
    });
    return c.json(invitation);
  });
  app.get("/user_management/invitations", (c) => {
    const orgId = c.req.query("organization_id") ?? c.req.query("organizationId") ?? "";
    const data = ws.listInvitations(orgId);
    return c.json({ data, list_metadata: { after: null, before: null } });
  });
  app.delete("/user_management/invitations/:invitationId", (c) => {
    const found = ws.revokeInvitation(c.req.param("invitationId"));
    if (!found) return c.json({ error: "invitation_not_found" }, 404);
    return c.body(null, 204);
  });
}
function randomId(prefix) {
  const bytes = new Uint8Array(12);
  crypto.getRandomValues(bytes);
  const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
  return `${prefix}_${hex}`;
}
function randomHex(bytes) {
  const arr = new Uint8Array(bytes);
  crypto.getRandomValues(arr);
  return Array.from(arr).map((b) => b.toString(16).padStart(2, "0")).join("");
}
function now() {
  return (/* @__PURE__ */ new Date()).toISOString();
}
var SERVICE_LABEL = "WorkOS";
function buildUserObject(user) {
  return {
    id: user.id,
    email: user.email,
    first_name: user.first_name,
    last_name: user.last_name,
    email_verified: user.email_verified,
    profile_picture_url: user.profile_picture_url,
    created_at: user.created_at,
    updated_at: user.updated_at,
    object: "user"
  };
}
async function verifyPKCE(codeVerifier, codeChallenge, method) {
  if (method === "S256") {
    const encoder = new TextEncoder();
    const digest = await crypto.subtle.digest("SHA-256", encoder.encode(codeVerifier));
    const computed = btoa(String.fromCharCode(...new Uint8Array(digest))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
    return computed === codeChallenge;
  }
  return codeVerifier === codeChallenge;
}
async function handleCodeExchange(ws, baseUrl, body) {
  const authCode = ws.consumeAuthCode(body.code);
  if (!authCode) {
    return { error: "invalid_grant", error_description: "Invalid or expired code", status: 400 };
  }
  if (authCode.code_challenge && body.code_verifier) {
    const valid = await verifyPKCE(body.code_verifier, authCode.code_challenge, authCode.code_challenge_method);
    if (!valid) {
      return { error: "invalid_grant", error_description: "PKCE verification failed", status: 400 };
    }
  }
  const user = ws.getUser(authCode.user_id);
  if (!user) return { error: "user_not_found", status: 404 };
  const session = ws.createSession(user.id, authCode.organization_id);
  const accessToken = await signJWT(
    { sub: user.id, sid: session.id, org_id: authCode.organization_id, email: user.email },
    { issuer: `${baseUrl}/user_management/${body.client_id}` }
  );
  const refreshToken = ws.createRefreshToken(user.id, session.id, authCode.organization_id);
  return {
    access_token: accessToken,
    refresh_token: refreshToken,
    user: buildUserObject(user),
    organization_id: authCode.organization_id ?? null
  };
}
function oauthRoutes(app, ws, baseUrl) {
  app.get("/user_management/authorize", (c) => {
    const clientId = c.req.query("client_id") ?? "";
    const redirectUri = c.req.query("redirect_uri") ?? "";
    const state = c.req.query("state") ?? "";
    const codeChallenge = c.req.query("code_challenge");
    const codeChallengeMethod = c.req.query("code_challenge_method");
    const users = ws.allUsers();
    if (users.length === 0) {
      return c.html(
        renderErrorPage(
          "No users seeded",
          "Add users to the workos section of emulate.config.yaml to emulate sign-in.",
          SERVICE_LABEL
        ),
        400
      );
    }
    const forcePicker = c.req.query("prompt") === "select_account";
    if (users.length === 1 && !forcePicker) {
      const user = users[0];
      const memberships = ws.getUserMemberships(user.id);
      const orgId = memberships[0]?.organization_id;
      const code = ws.createAuthCode(clientId, user.id, redirectUri, {
        organizationId: orgId,
        codeChallenge,
        codeChallengeMethod
      });
      const url = new URL(redirectUri);
      url.searchParams.set("code", code);
      if (state) url.searchParams.set("state", state);
      return c.redirect(url.toString());
    }
    const buttons = users.map((u) => {
      const memberships = ws.getUserMemberships(u.id);
      const orgNames = memberships.map((m) => ws.getOrg(m.organization_id)?.name ?? m.organization_id).join(", ");
      const fullName = `${u.first_name ?? ""} ${u.last_name ?? ""}`.trim();
      return renderUserButton({
        letter: (u.email[0] ?? "?").toUpperCase(),
        login: u.email,
        name: orgNames ? `${fullName ? fullName + " \xB7 " : ""}${orgNames}` : fullName || void 0,
        formAction: "/user_management/authorize/callback",
        hiddenFields: {
          user_id: u.id,
          client_id: clientId,
          redirect_uri: redirectUri,
          state,
          code_challenge: codeChallenge ?? "",
          code_challenge_method: codeChallengeMethod ?? ""
        }
      });
    }).join("\n");
    return c.html(renderCardPage("Sign in with WorkOS", "Select a test user to continue.", buttons, SERVICE_LABEL));
  });
  app.post("/user_management/authorize/callback", async (c) => {
    const body = await c.req.parseBody();
    const userId = body.user_id;
    const clientId = body.client_id;
    const redirectUri = body.redirect_uri;
    const state = body.state;
    const codeChallenge = body.code_challenge || void 0;
    const codeChallengeMethod = body.code_challenge_method || void 0;
    const user = ws.getUser(userId);
    if (!user) return c.json({ error: "User not found" }, 404);
    const memberships = ws.getUserMemberships(user.id);
    const orgId = memberships[0]?.organization_id;
    const code = ws.createAuthCode(clientId, user.id, redirectUri, {
      organizationId: orgId,
      codeChallenge,
      codeChallengeMethod
    });
    const url = new URL(redirectUri);
    url.searchParams.set("code", code);
    if (state) url.searchParams.set("state", state);
    return c.redirect(url.toString());
  });
  app.post("/user_management/authenticate", async (c) => {
    const body = await c.req.json();
    const grantType = body.grant_type ?? "authorization_code";
    if (grantType === "authorization_code") {
      const result = await handleCodeExchange(ws, baseUrl, {
        client_id: body.client_id,
        code: body.code,
        code_verifier: body.code_verifier
      });
      if ("error" in result) return c.json({ error: result.error }, result.status);
      return c.json(result);
    }
    if (grantType === "refresh_token") {
      const tokenValue = body.refresh_token ?? body.refreshToken;
      const entry = ws.consumeRefreshToken(tokenValue);
      if (!entry) return c.json({ error: "invalid_grant", error_description: "Invalid or expired refresh token" }, 401);
      const user = ws.getUser(entry.user_id);
      if (!user) return c.json({ error: "user_not_found" }, 404);
      const accessToken = await signJWT(
        { sub: user.id, sid: entry.session_id, org_id: entry.organization_id, email: user.email },
        { issuer: `${baseUrl}/user_management/${body.client_id}` }
      );
      const newRefreshToken = ws.createRefreshToken(user.id, entry.session_id, entry.organization_id);
      return c.json({
        access_token: accessToken,
        refresh_token: newRefreshToken,
        user: buildUserObject(user),
        organization_id: entry.organization_id ?? null
      });
    }
    if (grantType === "urn:workos:oauth:grant-type:organization-selection") {
      const pendingToken = body.pending_authentication_token ?? body.pendingAuthenticationToken;
      const orgId = body.organization_id ?? body.organizationId;
      if (!pendingToken)
        return c.json({ error: "invalid_grant", error_description: "Missing pending_authentication_token" }, 400);
      if (!orgId) return c.json({ error: "invalid_grant", error_description: "Missing organization_id" }, 400);
      const pending = ws.consumePendingAuthToken(pendingToken);
      if (!pending)
        return c.json({ error: "invalid_grant", error_description: "Invalid or expired pending token" }, 400);
      const user = ws.getUser(pending.user_id);
      if (!user) return c.json({ error: "user_not_found" }, 404);
      const session = ws.createSession(user.id, orgId);
      const accessToken = await signJWT(
        { sub: user.id, sid: session.id, org_id: orgId, email: user.email },
        { issuer: `${baseUrl}/user_management/${body.client_id}` }
      );
      const newRefreshToken = ws.createRefreshToken(user.id, session.id, orgId);
      return c.json({
        access_token: accessToken,
        refresh_token: newRefreshToken,
        user: buildUserObject(user),
        organization_id: orgId
      });
    }
    if (grantType === "password") {
      const user = ws.findUserByEmail(body.username ?? body.email);
      if (!user) return c.json({ error: "invalid_credentials", error_description: "User not found" }, 401);
      const password = body.password;
      if (user.password && user.password !== password) {
        return c.json({ error: "invalid_credentials", error_description: "Incorrect password" }, 401);
      }
      const memberships = ws.getUserMemberships(user.id);
      if (memberships.length > 1) {
        const pendingToken = `pat_${randomHex(16)}`;
        ws.setPendingAuthToken(pendingToken, {
          code: pendingToken,
          client_id: body.client_id,
          user_id: user.id,
          redirect_uri: "",
          expires_at: Date.now() + 10 * 60 * 1e3
        });
        return c.json(
          {
            code: "organization_selection_required",
            message: "User belongs to multiple organizations",
            pending_authentication_token: pendingToken,
            user: { id: user.id, email: user.email }
          },
          400
        );
      }
      const orgId = memberships[0]?.organization_id;
      const session = ws.createSession(user.id, orgId);
      const accessToken = await signJWT(
        { sub: user.id, sid: session.id, org_id: orgId, email: user.email },
        { issuer: `${baseUrl}/user_management/${body.client_id}` }
      );
      const newRefreshToken = ws.createRefreshToken(user.id, session.id, orgId);
      return c.json({
        access_token: accessToken,
        refresh_token: newRefreshToken,
        user: buildUserObject(user),
        organization_id: orgId ?? null
      });
    }
    return c.json({ error: "unsupported_grant_type" }, 400);
  });
  app.post("/user_management/authenticate/code", async (c) => {
    const body = await c.req.json();
    const result = await handleCodeExchange(ws, baseUrl, body);
    if ("error" in result) return c.json({ error: result.error }, result.status);
    return c.json(result);
  });
  app.post("/user_management/authenticate/password", async (c) => {
    const body = await c.req.json();
    const user = ws.findUserByEmail(body.email);
    if (!user) return c.json({ error: "invalid_credentials", error_description: "User not found" }, 401);
    if (user.password && user.password !== body.password) {
      return c.json({ error: "invalid_credentials", error_description: "Incorrect password" }, 401);
    }
    const memberships = ws.getUserMemberships(user.id);
    if (memberships.length > 1) {
      const pendingToken = `pat_${randomHex(16)}`;
      ws.setPendingAuthToken(pendingToken, {
        code: pendingToken,
        client_id: body.client_id,
        user_id: user.id,
        redirect_uri: "",
        expires_at: Date.now() + 10 * 60 * 1e3
      });
      return c.json(
        {
          code: "organization_selection_required",
          message: "User belongs to multiple organizations",
          pending_authentication_token: pendingToken,
          user: { id: user.id, email: user.email }
        },
        400
      );
    }
    const orgId = memberships[0]?.organization_id;
    const session = ws.createSession(user.id, orgId);
    const accessToken = await signJWT(
      { sub: user.id, sid: session.id, org_id: orgId, email: user.email },
      { issuer: `${baseUrl}/user_management/${body.client_id}` }
    );
    const refreshToken = ws.createRefreshToken(user.id, session.id, orgId);
    return c.json({
      access_token: accessToken,
      refresh_token: refreshToken,
      user: buildUserObject(user),
      organization_id: orgId ?? null
    });
  });
  app.post("/user_management/authenticate/organization_selection", async (c) => {
    const body = await c.req.json();
    const pending = ws.consumePendingAuthToken(body.pending_authentication_token);
    if (!pending) {
      return c.json({ error: "invalid_grant", error_description: "Invalid or expired pending token" }, 400);
    }
    const user = ws.getUser(pending.user_id);
    if (!user) return c.json({ error: "user_not_found" }, 404);
    const session = ws.createSession(user.id, body.organization_id);
    const accessToken = await signJWT(
      { sub: user.id, sid: session.id, org_id: body.organization_id, email: user.email },
      { issuer: `${baseUrl}/user_management/${body.client_id}` }
    );
    const refreshToken = ws.createRefreshToken(user.id, session.id, body.organization_id);
    return c.json({
      access_token: accessToken,
      refresh_token: refreshToken,
      user: buildUserObject(user),
      organization_id: body.organization_id
    });
  });
  app.post("/user_management/authenticate/refresh", async (c) => {
    const body = await c.req.json();
    const tokenValue = body.refresh_token ?? body.refreshToken;
    if (!tokenValue) return c.json({ error: "invalid_grant" }, 400);
    const entry = ws.consumeRefreshToken(tokenValue);
    if (!entry) return c.json({ error: "invalid_grant", error_description: "Invalid or expired refresh token" }, 401);
    const user = ws.getUser(entry.user_id);
    if (!user) return c.json({ error: "user_not_found" }, 404);
    const accessToken = await signJWT(
      { sub: user.id, sid: entry.session_id, org_id: entry.organization_id, email: user.email },
      { issuer: `${baseUrl}/user_management/${body.client_id}` }
    );
    const newRefreshToken = ws.createRefreshToken(user.id, entry.session_id, entry.organization_id);
    return c.json({ access_token: accessToken, refresh_token: newRefreshToken });
  });
}
function emitWorkOSEvent(webhooks, event, data) {
  webhooks.dispatch(
    event,
    void 0,
    { id: `event_${randomHex(16)}`, event, data, created_at: (/* @__PURE__ */ new Date()).toISOString() },
    "workos"
  ).catch(() => {
  });
}
function orgObject(o) {
  return {
    object: "organization",
    id: o.id,
    name: o.name,
    slug: o.slug,
    created_at: o.created_at,
    updated_at: o.updated_at
  };
}
function organizationRoutes(app, ws, webhooks) {
  app.get("/user_management/organizations", (c) => {
    return c.json({ data: ws.allOrgs().map(orgObject), list_metadata: { after: null, before: null } });
  });
  app.post("/user_management/organizations", async (c) => {
    const body = await c.req.json().catch(() => ({}));
    if (!body.name) return c.json({ code: "validation_error", message: "name is required" }, 422);
    const org = ws.insertOrganization({ name: body.name });
    const payload = orgObject(org);
    emitWorkOSEvent(webhooks, "organization.created", payload);
    return c.json(payload, 201);
  });
  app.get("/user_management/organizations/:organizationId", (c) => {
    const org = ws.getOrg(c.req.param("organizationId"));
    if (!org) return c.json({ code: "entity_not_found", message: "Organization not found" }, 404);
    return c.json(orgObject(org));
  });
}
function sessionRoutes(app, ws) {
  app.get("/user_management/sessions/:sessionId", (c) => {
    const session = ws.getSession(c.req.param("sessionId"));
    if (!session) return c.json({ code: "entity_not_found", message: "Session not found" }, 404);
    return c.json({ object: "session", ...session });
  });
  app.delete("/user_management/sessions/:sessionId", (c) => {
    ws.revokeSession(c.req.param("sessionId"));
    return c.body(null, 204);
  });
}
function membershipObject(m, orgName) {
  return {
    ...m,
    object: "organization_membership",
    organizationId: m.organization_id,
    organizationName: orgName
  };
}
function userObject(u) {
  return {
    object: "user",
    id: u.id,
    email: u.email,
    email_verified: u.email_verified,
    first_name: u.first_name,
    last_name: u.last_name,
    profile_picture_url: u.profile_picture_url,
    created_at: u.created_at,
    updated_at: u.updated_at
  };
}
function userRoutes(app, ws, webhooks) {
  app.get("/user_management/users", (c) => {
    const email = c.req.query("email");
    const users = ws.allUsers().filter((u) => email ? u.email === email : true);
    return c.json({ data: users.map(userObject), list_metadata: { after: null, before: null } });
  });
  app.post("/user_management/users", async (c) => {
    const body = await c.req.json().catch(() => ({}));
    if (!body.email) return c.json({ code: "validation_error", message: "email is required" }, 422);
    const user = ws.insertUser({
      email: body.email,
      password: body.password,
      first_name: body.first_name ?? null,
      last_name: body.last_name ?? null,
      email_verified: body.email_verified
    });
    const payload = userObject(user);
    emitWorkOSEvent(webhooks, "user.created", payload);
    return c.json(payload, 201);
  });
  app.get("/user_management/users/:userId", (c) => {
    const user = ws.getUser(c.req.param("userId"));
    if (!user) return c.json({ code: "entity_not_found", message: "User not found" }, 404);
    return c.json(userObject(user));
  });
  app.put("/user_management/users/:userId", async (c) => {
    const patch = await c.req.json();
    const updated = ws.updateUser(c.req.param("userId"), patch);
    if (!updated) return c.json({ code: "entity_not_found", message: "User not found" }, 404);
    const payload = userObject(updated);
    emitWorkOSEvent(webhooks, "user.updated", payload);
    return c.json(payload);
  });
  app.delete("/user_management/users/:userId", (c) => {
    const userId = c.req.param("userId");
    const existing = ws.getUser(userId);
    const ok = ws.deleteUser(userId);
    if (!ok || !existing) return c.json({ code: "entity_not_found", message: "User not found" }, 404);
    emitWorkOSEvent(webhooks, "user.deleted", userObject(existing));
    return c.body(null, 204);
  });
  app.post("/user_management/organization_memberships", async (c) => {
    const body = await c.req.json().catch(() => ({}));
    if (!body.user_id || !body.organization_id) {
      return c.json({ code: "validation_error", message: "user_id and organization_id are required" }, 422);
    }
    if (!ws.getUser(body.user_id)) return c.json({ code: "entity_not_found", message: "User not found" }, 404);
    const org = ws.getOrg(body.organization_id);
    if (!org) return c.json({ code: "entity_not_found", message: "Organization not found" }, 404);
    const m = ws.insertMembership(body.user_id, body.organization_id, body.role_slug ?? "member");
    const payload = membershipObject(m, org.name);
    emitWorkOSEvent(webhooks, "organization_membership.created", payload);
    return c.json(payload, 201);
  });
  app.get("/user_management/organization_memberships/:membershipId", (c) => {
    const m = ws.getMembership(c.req.param("membershipId"));
    if (!m) return c.json({ code: "entity_not_found", message: "Membership not found" }, 404);
    return c.json(membershipObject(m, ws.getOrg(m.organization_id)?.name ?? m.organization_id));
  });
  app.delete("/user_management/organization_memberships/:membershipId", (c) => {
    const membershipId = c.req.param("membershipId");
    const existing = ws.getMembership(membershipId);
    const ok = ws.deactivateMembership(membershipId);
    if (!ok || !existing) return c.json({ code: "entity_not_found", message: "Membership not found" }, 404);
    emitWorkOSEvent(
      webhooks,
      "organization_membership.deleted",
      membershipObject({ ...existing, status: "inactive" }, ws.getOrg(existing.organization_id)?.name ?? existing.organization_id)
    );
    return c.body(null, 204);
  });
  app.get("/user_management/users/:userId/organization_memberships", (c) => {
    const userId = c.req.param("userId");
    const statusFilter = c.req.query("statuses[]") ?? "active";
    const memberships = ws.getUserMemberships(userId);
    const filtered = statusFilter === "active" ? memberships.filter((m) => m.status === "active") : memberships;
    const data = filtered.map((m) => ({
      ...m,
      organizationId: m.organization_id,
      organizationName: ws.getOrg(m.organization_id)?.name ?? m.organization_id
    }));
    return c.json({ data, list_metadata: { after: null, before: null } });
  });
  app.get("/user_management/organization_memberships", (c) => {
    const userId = c.req.query("user_id");
    const statusFilter = c.req.query("statuses[]") ?? "active";
    const memberships = userId ? ws.getUserMemberships(userId) : [];
    const filtered = statusFilter === "active" ? memberships.filter((m) => m.status === "active") : memberships;
    const data = filtered.map((m) => ({
      ...m,
      organizationId: m.organization_id,
      organizationName: ws.getOrg(m.organization_id)?.name ?? m.organization_id
    }));
    return c.json({ data, list_metadata: { after: null, before: null } });
  });
}
function webhookRoutes(app) {
  app.post("/webhooks/test", async (c) => {
    const body = await c.req.json();
    const target = body.target;
    if (!target) {
      return c.json({ error: "No webhook target. Pass target in body." }, 400);
    }
    const payload = {
      id: `evt_${Date.now()}`,
      event: body.event,
      data: body.data,
      created_at: (/* @__PURE__ */ new Date()).toISOString()
    };
    const secret = "whsec_test_emulator";
    const encoder = new TextEncoder();
    const key = await crypto.subtle.importKey("raw", encoder.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, [
      "sign"
    ]);
    const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(JSON.stringify(payload)));
    const sigHex = Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join("");
    try {
      const resp = await fetch(target, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "workos-signature": `t=${Math.floor(Date.now() / 1e3)},v1=${sigHex}`
        },
        body: JSON.stringify(payload)
      });
      return c.json({ delivered: true, status: resp.status, event: body.event });
    } catch (err) {
      return c.json({ delivered: false, error: err instanceof Error ? err.message : "Delivery failed" }, 502);
    }
  });
}
var KEY = {
  users: "workos_users",
  orgs: "workos_orgs",
  memberships: "workos_memberships",
  invitations: "workos_invitations",
  oauthClients: "workos_oauth_clients",
  authCodes: "workos_auth_codes",
  sessions: "workos_sessions",
  refreshTokens: "workos_refresh_tokens",
  init: "_workos_init"
};
function getWorkOSStore(store) {
  if (!store.getData(KEY.init)) {
    store.setData(KEY.users, /* @__PURE__ */ new Map());
    store.setData(KEY.orgs, /* @__PURE__ */ new Map());
    store.setData(KEY.memberships, /* @__PURE__ */ new Map());
    store.setData(KEY.invitations, /* @__PURE__ */ new Map());
    store.setData(KEY.oauthClients, /* @__PURE__ */ new Map());
    store.setData(KEY.authCodes, /* @__PURE__ */ new Map());
    store.setData(KEY.sessions, /* @__PURE__ */ new Map());
    store.setData(KEY.refreshTokens, /* @__PURE__ */ new Map());
    store.setData(KEY.init, true);
  }
  const users = store.getData(KEY.users);
  const orgs = store.getData(KEY.orgs);
  const memberships = store.getData(KEY.memberships);
  const invitations = store.getData(KEY.invitations);
  const oauthClients = store.getData(KEY.oauthClients);
  const authCodes = store.getData(KEY.authCodes);
  const sessions = store.getData(KEY.sessions);
  const refreshTokens = store.getData(KEY.refreshTokens);
  return {
    // --- Users ---
    insertUser(data) {
      const id = data.id ?? randomId("user");
      const user = {
        id,
        email: data.email,
        email_verified: data.email_verified ?? true,
        first_name: data.first_name ?? null,
        last_name: data.last_name ?? null,
        profile_picture_url: data.profile_picture_url ?? null,
        password: data.password,
        created_at: now(),
        updated_at: now()
      };
      users.set(id, user);
      return user;
    },
    findUserByEmail(email) {
      for (const u of users.values()) {
        if (u.email === email) return u;
      }
      return void 0;
    },
    getUser(id) {
      return users.get(id);
    },
    allUsers() {
      return [...users.values()];
    },
    updateUser(id, patch) {
      const user = users.get(id);
      if (!user) return void 0;
      const next = {
        ...user,
        ...patch,
        id: user.id,
        created_at: user.created_at,
        updated_at: now()
      };
      users.set(id, next);
      return next;
    },
    deleteUser(id) {
      return users.delete(id);
    },
    // --- Organizations ---
    insertOrganization(data) {
      const id = data.id ?? randomId("org");
      const org = {
        id,
        name: data.name,
        slug: data.slug ?? data.name.toLowerCase().replace(/\s+/g, "-"),
        created_at: now(),
        updated_at: now()
      };
      orgs.set(id, org);
      return org;
    },
    findOrgBySlug(slug) {
      for (const o of orgs.values()) {
        if (o.slug === slug) return o;
      }
      return void 0;
    },
    getOrg(id) {
      return orgs.get(id);
    },
    allOrgs() {
      return [...orgs.values()];
    },
    // --- Memberships ---
    insertMembership(userId, organizationId, role = "member") {
      const id = randomId("om");
      const m = {
        id,
        user_id: userId,
        organization_id: organizationId,
        role: { slug: role },
        status: "active",
        created_at: now(),
        updated_at: now()
      };
      memberships.set(id, m);
      return m;
    },
    getUserMemberships(userId) {
      return [...memberships.values()].filter((m) => m.user_id === userId && m.status === "active");
    },
    allMemberships() {
      return [...memberships.values()];
    },
    getMembership(id) {
      return memberships.get(id);
    },
    deactivateMembership(id) {
      const m = memberships.get(id);
      if (!m) return false;
      m.status = "inactive";
      m.updated_at = now();
      return true;
    },
    // --- Auth Codes ---
    createAuthCode(clientId, userId, redirectUri, opts) {
      const code = randomHex(20);
      authCodes.set(code, {
        code,
        client_id: clientId,
        user_id: userId,
        organization_id: opts?.organizationId,
        redirect_uri: redirectUri,
        code_challenge: opts?.codeChallenge,
        code_challenge_method: opts?.codeChallengeMethod,
        expires_at: Date.now() + 10 * 60 * 1e3
      });
      return code;
    },
    consumeAuthCode(code) {
      const entry = authCodes.get(code);
      if (!entry) return null;
      authCodes.delete(code);
      if (Date.now() > entry.expires_at) return null;
      return entry;
    },
    setPendingAuthToken(token, entry) {
      authCodes.set(`pending_${token}`, entry);
    },
    consumePendingAuthToken(token) {
      const entry = authCodes.get(`pending_${token}`);
      if (!entry || Date.now() > entry.expires_at) return null;
      authCodes.delete(`pending_${token}`);
      return entry;
    },
    // --- Sessions ---
    createSession(userId, organizationId) {
      const id = randomId("session");
      const s = {
        id,
        user_id: userId,
        organization_id: organizationId,
        created_at: now(),
        revoked: false
      };
      sessions.set(id, s);
      return s;
    },
    getSession(sessionId) {
      const s = sessions.get(sessionId);
      if (!s || s.revoked) return void 0;
      return s;
    },
    revokeSession(sessionId) {
      const s = sessions.get(sessionId);
      if (!s) return false;
      s.revoked = true;
      return true;
    },
    // --- Refresh Tokens ---
    createRefreshToken(userId, sessionId, organizationId) {
      const token = `r_workos_${randomHex(32)}`;
      refreshTokens.set(token, { token, user_id: userId, organization_id: organizationId, session_id: sessionId });
      return token;
    },
    consumeRefreshToken(token) {
      const entry = refreshTokens.get(token);
      if (!entry) return null;
      return entry;
    },
    // --- Invitations ---
    insertInvitation(email, organizationId, roleSlug) {
      const id = randomId("inv");
      const inv = {
        id,
        email,
        organization_id: organizationId,
        role_slug: roleSlug ?? null,
        status: "pending",
        created_at: now(),
        updated_at: now(),
        expires_at: new Date(Date.now() + 7 * 24 * 60 * 60 * 1e3).toISOString()
      };
      invitations.set(id, inv);
      return inv;
    },
    listInvitations(organizationId) {
      return [...invitations.values()].filter((i) => i.organization_id === organizationId && i.status === "pending");
    },
    revokeInvitation(invitationId) {
      const inv = invitations.get(invitationId);
      if (!inv) return false;
      inv.status = "revoked";
      inv.updated_at = now();
      return true;
    },
    // --- OAuth Clients ---
    insertOAuthClient(data) {
      oauthClients.set(data.client_id, data);
    },
    getOAuthClient(clientId) {
      return oauthClients.get(clientId);
    },
    allOAuthClients() {
      return [...oauthClients.values()];
    }
  };
}
var SERVICE_LABEL2 = "WorkOS";
function timeAgo(isoDate) {
  const seconds = Math.floor((Date.now() - new Date(isoDate).getTime()) / 1e3);
  if (seconds < 60) return "just now";
  if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;
  if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`;
  return `${Math.floor(seconds / 86400)}d ago`;
}
function statusBadge(status) {
  const cls = status === "active" || status === "pending" ? "badge-granted" : "badge-denied";
  return `<span class="badge ${cls}">${escapeHtml(status)}</span>`;
}
function roleBadge(role) {
  return `<span class="badge badge-requested">${escapeHtml(role)}</span>`;
}
function inspectorRoutes(ctx) {
  const { app, store } = ctx;
  const ws = () => getWorkOSStore(store);
  app.get("/", (c) => {
    const tab = c.req.query("tab") ?? "users";
    const w = ws();
    const users = w.allUsers();
    const orgs = [];
    const orgIds = /* @__PURE__ */ new Set();
    for (const u of users) {
      for (const m of w.getUserMemberships(u.id)) {
        orgIds.add(m.organization_id);
      }
    }
    const allInvitations = [];
    const sidebar = `
<a href="/?tab=users"${tab === "users" ? ' class="active"' : ""}>Users (${users.length})</a>
<a href="/?tab=orgs"${tab === "orgs" ? ' class="active"' : ""}>Organizations</a>
<a href="/?tab=memberships"${tab === "memberships" ? ' class="active"' : ""}>Memberships</a>
<a href="/?tab=invitations"${tab === "invitations" ? ' class="active"' : ""}>Invitations</a>`;
    let bodyHtml = "";
    if (tab === "users") {
      const rows = users.length === 0 ? `<tr><td colspan="5" class="inspector-empty">No users seeded yet.</td></tr>` : users.map(
        (u) => `
<tr>
  <td><span class="org-icon" style="display:inline-flex;width:28px;height:28px;font-size:.75rem">${escapeHtml((u.first_name?.[0] ?? u.email[0]).toUpperCase())}</span></td>
  <td><span style="color:#33ff00;font-weight:600">${escapeHtml(u.email)}</span></td>
  <td>${escapeHtml([u.first_name, u.last_name].filter(Boolean).join(" ") || "\u2014")}</td>
  <td>${u.email_verified ? '<span class="badge badge-granted">verified</span>' : '<span class="badge badge-denied">unverified</span>'}</td>
  <td style="color:#1a8c00;font-size:.75rem">${timeAgo(u.created_at)}</td>
</tr>`
      ).join("");
      bodyHtml = `
<div class="inspector-section">
  <h2>Users</h2>
  <table class="inspector-table">
    <thead><tr><th></th><th>Email</th><th>Name</th><th>Verified</th><th>Created</th></tr></thead>
    <tbody>${rows}</tbody>
  </table>
</div>`;
    }
    if (tab === "orgs") {
      const orgMap = /* @__PURE__ */ new Map();
      for (const u of users) {
        for (const m of w.getUserMemberships(u.id)) {
          if (!orgMap.has(m.organization_id)) {
            const org = w.getOrg(m.organization_id);
            if (org) {
              orgMap.set(org.id, { name: org.name, slug: org.slug, memberCount: 0, createdAt: org.created_at });
            }
          }
          const entry = orgMap.get(m.organization_id);
          if (entry) entry.memberCount++;
        }
      }
      const rows = orgMap.size === 0 ? `<tr><td colspan="4" class="inspector-empty">No organizations found.</td></tr>` : [...orgMap.entries()].map(
        ([id, org]) => `
<tr>
  <td><span class="org-icon" style="display:inline-flex;width:28px;height:28px;font-size:.75rem">${escapeHtml(org.name[0].toUpperCase())}</span></td>
  <td><span style="color:#33ff00;font-weight:600">${escapeHtml(org.name)}</span><br><span style="color:#1a8c00;font-size:.75rem">${escapeHtml(org.slug)}</span></td>
  <td style="color:#1a8c00">${escapeHtml(id)}</td>
  <td>${org.memberCount} member${org.memberCount !== 1 ? "s" : ""}</td>
</tr>`
      ).join("");
      bodyHtml = `
<div class="inspector-section">
  <h2>Organizations</h2>
  <table class="inspector-table">
    <thead><tr><th></th><th>Name / Slug</th><th>ID</th><th>Members</th></tr></thead>
    <tbody>${rows}</tbody>
  </table>
</div>`;
    }
    if (tab === "memberships") {
      const rows = [];
      for (const u of users) {
        for (const m of w.getUserMemberships(u.id)) {
          const org = w.getOrg(m.organization_id);
          rows.push(`
<tr>
  <td><span style="color:#33ff00;font-weight:600">${escapeHtml(u.email)}</span></td>
  <td>${escapeHtml(org?.name ?? m.organization_id)}</td>
  <td>${roleBadge(m.role.slug)}</td>
  <td>${statusBadge(m.status)}</td>
  <td style="color:#1a8c00;font-size:.75rem">${timeAgo(m.created_at)}</td>
</tr>`);
        }
      }
      const tableRows = rows.length === 0 ? `<tr><td colspan="5" class="inspector-empty">No memberships found.</td></tr>` : rows.join("");
      bodyHtml = `
<div class="inspector-section">
  <h2>Memberships</h2>
  <table class="inspector-table">
    <thead><tr><th>User</th><th>Organization</th><th>Role</th><th>Status</th><th>Created</th></tr></thead>
    <tbody>${tableRows}</tbody>
  </table>
</div>`;
    }
    if (tab === "invitations") {
      const allOrgs = /* @__PURE__ */ new Set();
      for (const u of users) {
        for (const m of w.getUserMemberships(u.id)) {
          allOrgs.add(m.organization_id);
        }
      }
      const invs = [...allOrgs].flatMap((orgId) => w.listInvitations(orgId));
      const rows = invs.length === 0 ? `<tr><td colspan="5" class="inspector-empty">No pending invitations.</td></tr>` : invs.map((inv) => {
        const org = w.getOrg(inv.organization_id);
        return `
<tr>
  <td><span style="color:#33ff00;font-weight:600">${escapeHtml(inv.email)}</span></td>
  <td>${escapeHtml(org?.name ?? inv.organization_id)}</td>
  <td>${inv.role_slug ? roleBadge(inv.role_slug) : "\u2014"}</td>
  <td>${statusBadge(inv.status)}</td>
  <td style="color:#1a8c00;font-size:.75rem">${timeAgo(inv.created_at)}</td>
</tr>`;
      }).join("");
      bodyHtml = `
<div class="inspector-section">
  <h2>Invitations</h2>
  <table class="inspector-table">
    <thead><tr><th>Email</th><th>Organization</th><th>Role</th><th>Status</th><th>Sent</th></tr></thead>
    <tbody>${rows}</tbody>
  </table>
</div>`;
    }
    const stats = `${users.length} users \xB7 ${orgIds.size} orgs`;
    return c.html(
      renderSettingsPage(
        `WorkOS Inspector`,
        sidebar,
        `<div class="s-card">
  <div class="s-card-header">
    <div class="s-icon">W</div>
    <div>
      <div class="s-title">WorkOS User Management</div>
      <div class="s-subtitle">${stats}</div>
    </div>
  </div>
  ${bodyHtml}
</div>`,
        SERVICE_LABEL2
      )
    );
  });
}
function seedFromConfig(store, _baseUrl, config) {
  const ws = getWorkOSStore(store);
  for (const client of config.oauth_clients ?? []) {
    ws.insertOAuthClient({
      client_id: client.client_id,
      client_secret: client.client_secret,
      name: client.name ?? "Default App",
      redirect_uris: client.redirect_uris ?? ["http://localhost:3000/callback"]
    });
  }
  for (const org of config.organizations ?? []) {
    ws.insertOrganization({ id: org.id, name: org.name, slug: org.slug });
  }
  for (const user of config.users ?? []) {
    ws.insertUser({
      id: user.id,
      email: user.email,
      first_name: user.first_name ?? null,
      last_name: user.last_name ?? null,
      password: user.password,
      profile_picture_url: user.profile_picture_url ?? null,
      email_verified: user.email_verified
    });
  }
  for (const m of config.memberships ?? []) {
    const user = ws.findUserByEmail(m.user_email);
    const org = ws.findOrgBySlug(m.organization_slug);
    if (user && org) {
      ws.insertMembership(user.id, org.id, m.role ?? "member");
    } else {
      console.warn(
        `[workos-emulator] Skipping membership: user=${m.user_email} org=${m.organization_slug} \u2014 not found`
      );
    }
  }
}
function storeToSeedConfig(store, _baseUrl) {
  const ws = getWorkOSStore(store);
  const orgsById = new Map(ws.allOrgs().map((o) => [o.id, o]));
  const usersById = new Map(ws.allUsers().map((u) => [u.id, u]));
  return {
    oauth_clients: ws.allOAuthClients().map((c) => ({
      client_id: c.client_id,
      client_secret: c.client_secret,
      name: c.name,
      redirect_uris: c.redirect_uris
    })),
    organizations: ws.allOrgs().map((o) => ({ id: o.id, name: o.name, slug: o.slug })),
    users: ws.allUsers().map((u) => ({
      id: u.id,
      email: u.email,
      first_name: u.first_name ?? void 0,
      last_name: u.last_name ?? void 0,
      password: u.password,
      profile_picture_url: u.profile_picture_url ?? void 0,
      email_verified: u.email_verified
    })),
    memberships: ws.allMemberships().filter((m) => m.status === "active").flatMap((m) => {
      const user = usersById.get(m.user_id);
      const org = orgsById.get(m.organization_id);
      if (!user || !org) return [];
      return [{ user_email: user.email, organization_slug: org.slug, role: m.role.slug }];
    })
  };
}
var workosPlugin = {
  name: "workos",
  register(app, store, webhooks, baseUrl) {
    const ws = getWorkOSStore(store);
    app.get("/health", (c) => c.json({ ok: true }));
    inspectorRoutes({ app, store, webhooks, baseUrl });
    discoveryRoutes(app, baseUrl);
    oauthRoutes(app, ws, baseUrl);
    app.use("/user_management/*", requireAuthWhen("EMULATE_WORKOS_REQUIRE_AUTH", "EMULATE_REQUIRE_AUTH"));
    userRoutes(app, ws, webhooks);
    organizationRoutes(app, ws, webhooks);
    sessionRoutes(app, ws);
    invitationRoutes(app, ws, webhooks);
    webhookRoutes(app);
  },
  seed(store, _baseUrl) {
    const ws = getWorkOSStore(store);
    const user = ws.insertUser({
      id: "user_test_dev",
      email: "dev@agent-emulate.dev",
      first_name: "Dev",
      last_name: "User",
      password: "DevPassword123!"
    });
    const org = ws.insertOrganization({
      id: "org_test_taskr",
      name: "Taskr Dev",
      slug: "taskr-dev"
    });
    ws.insertMembership(user.id, org.id, "owner");
    ws.insertOAuthClient({
      client_id: "client_test_01",
      client_secret: "sk_test_secret",
      name: "Taskr Local",
      redirect_uris: ["http://localhost:3000/callback", "taskr://auth/callback"]
    });
  }
};
export {
  getWorkOSStore,
  seedFromConfig,
  storeToSeedConfig,
  workosPlugin
};
//# sourceMappingURL=dist-TIVSMHZE.js.map