import "./chunk-AQ2CLRU3.js";

// ../@emulators/uptick/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();
}
function escapeHtml(s) {
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
}
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 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>`;
}
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());
function getUptickStore(store) {
  return {
    clients: store.collection("uptick.clients", ["contact_email"]),
    properties: store.collection("uptick.properties", ["client_id"]),
    assets: store.collection("uptick.assets", ["property_id", "client_id"]),
    defects: store.collection("uptick.defects", ["asset_id", "property_id", "client_id"]),
    assetTypes: store.collection("uptick.assetTypes"),
    users: store.collection("uptick.users", ["email"])
  };
}
function toRel(type, id) {
  if (!id) return { data: null };
  return { data: { type, id: String(id) } };
}
function formatClient(c) {
  return {
    type: "Client",
    id: String(c.id),
    attributes: {
      name: c.name,
      // Nango sync reads company_name (falls back to name for individual clients)
      company_name: c.name,
      // Nango sync reads first_name / last_name from contact_name split
      first_name: c.contact_name?.split(" ")[0] || null,
      last_name: c.contact_name?.split(" ").slice(1).join(" ") || null,
      email: c.contact_email || null,
      phone: null,
      is_active: c.is_active,
      // Nango reads archived (inverse of is_active)
      archived: !c.is_active,
      sector: c.sector || null,
      ref: c.ref || null,
      contact_name: c.contact_name || null,
      contact_email: c.contact_email || null,
      // Nango reads created_at / updated_at (not created/updated)
      created_at: c.created_at,
      updated_at: c.updated_at
    }
  };
}
function formatProperty(p, _us) {
  return {
    type: "Property",
    id: String(p.id),
    attributes: {
      name: p.name,
      is_active: p.is_active,
      // Nango reads archived (inverse of is_active)
      archived: !p.is_active,
      // Nango reads flat address fields (not nested address object)
      address_line_1: p.address_streetline || null,
      suburb: p.address_city || null,
      state: p.address_state || null,
      postcode: p.address_postal_code || null,
      country: p.address_country || "AU",
      // Nango reads client_id in attributes (not relationships)
      client_id: p.client_id ? String(p.client_id) : null,
      // Nango reads created_at / updated_at (not created/updated)
      created_at: p.created_at,
      updated_at: p.updated_at
    },
    relationships: {
      client: toRel("Client", p.client_id)
    }
  };
}
function formatAsset(a, _us) {
  return {
    type: "Asset",
    id: String(a.id),
    attributes: {
      name: a.name,
      // Nango reads barcode (Uptick's public field name for asset_number)
      barcode: a.asset_number || null,
      asset_number: a.asset_number || null,
      is_active: a.is_active,
      // Nango reads archived (inverse of is_active)
      archived: !a.is_active,
      standard_maintenance: a.standard_maintenance || null,
      // Nango reads asset_type_name in attributes (not from relationship)
      asset_type_name: a.asset_type_name || null,
      // Nango reads property_id / client_id in attributes (not relationships)
      property_id: a.property_id ? String(a.property_id) : null,
      client_id: a.client_id ? String(a.client_id) : null,
      // Nango reads created_at / updated_at (not created/updated)
      created_at: a.created_at,
      updated_at: a.updated_at
    },
    relationships: {
      property: toRel("Property", a.property_id),
      client: toRel("Client", a.client_id),
      asset_type: toRel("AssetType", a.asset_type_id)
    }
  };
}
function formatDefect(d, _us) {
  return {
    type: "Defect",
    id: String(d.id),
    attributes: {
      description: d.description,
      notes: d.notes || null,
      severity: d.severity || null,
      status: d.status || "open",
      // Nango reads asset_id / property_id / client_id in attributes (not relationships)
      asset_id: d.asset_id ? String(d.asset_id) : null,
      property_id: d.property_id ? String(d.property_id) : null,
      client_id: d.client_id ? String(d.client_id) : null,
      // Nango reads created_at / updated_at (not created/updated)
      created_at: d.created_at,
      updated_at: d.updated_at,
      // Nango reads resolved_at for completed defects
      resolved_at: d.status === "resolved" || d.status === "closed" ? d.updated_at : null
    },
    relationships: {
      asset: toRel("Asset", d.asset_id),
      property: toRel("Property", d.property_id),
      client: toRel("Client", d.client_id)
    }
  };
}
function formatAssetType(t) {
  return {
    type: "AssetType",
    id: String(t.id),
    attributes: {
      name: t.name,
      description: t.description || null
    }
  };
}
function formatUser(u) {
  return {
    type: "User",
    id: String(u.id),
    attributes: {
      username: u.username,
      email: u.email,
      first_name: u.first_name,
      last_name: u.last_name,
      is_active: u.is_active
    }
  };
}
function uptickError(c, status, title) {
  return c.json({ errors: [{ status: String(status), title }] }, status);
}
function parseId(raw) {
  if (!raw) return void 0;
  const n = parseInt(raw, 10);
  return isNaN(n) ? void 0 : n;
}
async function parseJsonApiBody(c) {
  try {
    const body = await c.req.json();
    const data = body.data ?? body;
    return {
      attributes: data.attributes ?? {},
      relationships: data.relationships ?? {}
    };
  } catch {
    return { attributes: {}, relationships: {} };
  }
}
function relId(rel) {
  if (!rel || typeof rel !== "object") return null;
  const data = rel.data;
  if (!data || typeof data !== "object") return null;
  const id = data.id;
  if (id === void 0 || id === null) return null;
  const n = parseInt(String(id), 10);
  return isNaN(n) ? null : n;
}
function filterByUpdatedSince(items, since) {
  if (!since) return items;
  try {
    const sinceMs = new Date(since).getTime();
    return items.filter((item) => new Date(item.updated_at).getTime() >= sinceMs);
  } catch {
    return items;
  }
}
function paginateItems(c, allItems, resourcePath) {
  const url = new URL(c.req.url);
  const updatedSince = url.searchParams.get("updatedsince");
  const filtered = filterByUpdatedSince(allItems, updatedSince);
  const hasCursor = url.searchParams.has("page[cursor]");
  const pageSize = parseInt(url.searchParams.get("page[size]") ?? "50", 10);
  const pageLimit = parseInt(url.searchParams.get("page[limit]") ?? "50", 10);
  const pageOffset = parseInt(url.searchParams.get("page[offset]") ?? "0", 10);
  let offset;
  let limit;
  if (hasCursor) {
    const cursorVal = url.searchParams.get("page[cursor]") ?? "";
    if (cursorVal) {
      try {
        offset = parseInt(Buffer.from(cursorVal, "base64").toString("utf-8"), 10);
      } catch {
        offset = 0;
      }
    } else {
      offset = 0;
    }
    limit = isNaN(pageSize) ? 50 : Math.min(pageSize, 250);
  } else {
    offset = isNaN(pageOffset) ? 0 : pageOffset;
    limit = isNaN(pageLimit) ? 50 : Math.min(pageLimit, 250);
  }
  const slice = filtered.slice(offset, offset + limit);
  const nextOffset = offset + limit;
  const hasNext = nextOffset < filtered.length;
  const hasPrev = offset > 0;
  const baseUrl = `${url.origin}${resourcePath}`;
  let nextUrl = null;
  let prevUrl = null;
  if (hasNext) {
    if (hasCursor) {
      const nextCursor = Buffer.from(String(nextOffset)).toString("base64");
      nextUrl = `${baseUrl}?page[cursor]=${nextCursor}&page[size]=${limit}`;
    } else {
      nextUrl = `${baseUrl}?page[limit]=${limit}&page[offset]=${nextOffset}`;
    }
    if (updatedSince) nextUrl += `&updatedsince=${encodeURIComponent(updatedSince)}`;
  }
  if (hasPrev) {
    const prevOff = Math.max(0, offset - limit);
    if (hasCursor) {
      const prevCursor = Buffer.from(String(prevOff)).toString("base64");
      prevUrl = `${baseUrl}?page[cursor]=${prevCursor}&page[size]=${limit}`;
    } else {
      prevUrl = `${baseUrl}?page[limit]=${limit}&page[offset]=${prevOff}`;
    }
    if (updatedSince) prevUrl += `&updatedsince=${encodeURIComponent(updatedSince)}`;
  }
  return { items: slice, nextUrl, prevUrl };
}
function uptickPaginate(c, allItems, formatFn, resourcePath) {
  const { items, nextUrl, prevUrl } = paginateItems(c, allItems, resourcePath);
  return c.json({
    data: items.map(formatFn),
    links: {
      next: nextUrl,
      prev: prevUrl
    }
  });
}
function assetRoutes({ app, store }) {
  const us = () => getUptickStore(store);
  app.get("/api/:ver/assets/", (c) => {
    const s = us();
    let assets = s.assets.all();
    const propertyFilter = c.req.query("property");
    if (propertyFilter) {
      const pid = parseInt(propertyFilter, 10);
      if (!isNaN(pid)) assets = assets.filter((a) => a.property_id === pid);
    }
    const clientFilter = c.req.query("client");
    if (clientFilter) {
      const cid = parseInt(clientFilter, 10);
      if (!isNaN(cid)) assets = assets.filter((a) => a.client_id === cid);
    }
    const isActive = c.req.query("is_active");
    if (isActive !== void 0) {
      const active = isActive !== "false";
      assets = assets.filter((a) => a.is_active === active);
    }
    const search = c.req.query("search")?.toLowerCase();
    if (search) {
      assets = assets.filter(
        (a) => a.name.toLowerCase().includes(search) || a.asset_number.toLowerCase().includes(search)
      );
    }
    return uptickPaginate(c, assets, (a) => formatAsset(a, s), `/api/${c.req.param("ver")}/assets/`);
  });
  app.post("/api/:ver/assets/", async (c) => {
    const s = us();
    const { attributes, relationships } = await parseJsonApiBody(c);
    const propertyId = relId(relationships.property);
    const clientId = relId(relationships.client);
    const assetTypeId = relId(relationships.asset_type);
    const assetType = assetTypeId ? s.assetTypes.get(assetTypeId) : null;
    const asset = s.assets.insert({
      name: attributes.name ?? "New Asset",
      asset_number: attributes.asset_number ?? "",
      is_active: attributes.is_active !== false,
      standard_maintenance: attributes.standard_maintenance ?? "",
      property_id: propertyId ?? null,
      client_id: clientId ?? null,
      asset_type_id: assetTypeId ?? null,
      asset_type_name: assetType?.name ?? attributes.asset_type_name ?? ""
    });
    return c.json({ data: formatAsset(asset, s) }, 201);
  });
  app.get("/api/:ver/assets/:id/defects/", (c) => {
    const s = us();
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    if (!s.assets.get(id)) return uptickError(c, 404, "Not Found");
    const defects = s.defects.all().filter((d) => d.asset_id === id);
    return uptickPaginate(c, defects, (d) => formatDefect(d, s), `/api/${c.req.param("ver")}/assets/${id}/defects/`);
  });
  app.get("/api/:ver/assets/:id", (c) => {
    const s = us();
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    const asset = s.assets.get(id);
    if (!asset) return uptickError(c, 404, "Not Found");
    return c.json({ data: formatAsset(asset, s) });
  });
  app.patch("/api/:ver/assets/:id", async (c) => {
    const s = us();
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    const existing = s.assets.get(id);
    if (!existing) return uptickError(c, 404, "Not Found");
    const { attributes, relationships } = await parseJsonApiBody(c);
    const propertyId = relId(relationships.property);
    const clientId = relId(relationships.client);
    const assetTypeId = relId(relationships.asset_type);
    const assetType = assetTypeId ? s.assetTypes.get(assetTypeId) : null;
    const updated = s.assets.update(id, {
      name: attributes.name ?? existing.name,
      asset_number: attributes.asset_number ?? existing.asset_number,
      is_active: attributes.is_active !== void 0 ? attributes.is_active : existing.is_active,
      standard_maintenance: attributes.standard_maintenance ?? existing.standard_maintenance,
      property_id: propertyId ?? existing.property_id,
      client_id: clientId ?? existing.client_id,
      asset_type_id: assetTypeId ?? existing.asset_type_id,
      asset_type_name: assetType?.name ?? attributes.asset_type_name ?? existing.asset_type_name
    });
    return c.json({ data: formatAsset(updated, s) });
  });
  app.delete("/api/:ver/assets/:id", (c) => {
    const s = us();
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    if (!s.assets.get(id)) return uptickError(c, 404, "Not Found");
    s.assets.delete(id);
    return c.body(null, 204);
  });
}
function clientRoutes({ app, store }) {
  const us = () => getUptickStore(store);
  app.get("/api/:ver/clients/", (c) => {
    let clients = us().clients.all();
    const isActive = c.req.query("is_active");
    if (isActive !== void 0) {
      const active = isActive !== "false";
      clients = clients.filter((cl) => cl.is_active === active);
    }
    const search = c.req.query("search")?.toLowerCase();
    if (search) {
      clients = clients.filter(
        (cl) => cl.name.toLowerCase().includes(search) || cl.contact_email.toLowerCase().includes(search) || cl.contact_name.toLowerCase().includes(search)
      );
    }
    return uptickPaginate(c, clients, formatClient, `/api/${c.req.param("ver")}/clients/`);
  });
  app.post("/api/:ver/clients/", async (c) => {
    const { attributes } = await parseJsonApiBody(c);
    const client = us().clients.insert({
      name: attributes.name ?? "New Client",
      is_active: attributes.is_active !== false,
      sector: attributes.sector ?? "",
      ref: attributes.ref ?? "",
      contact_name: attributes.contact_name ?? "",
      contact_email: attributes.contact_email ?? ""
    });
    return c.json({ data: formatClient(client) }, 201);
  });
  app.get("/api/:ver/clients/:id", (c) => {
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    const client = us().clients.get(id);
    if (!client) return uptickError(c, 404, "Not Found");
    return c.json({ data: formatClient(client) });
  });
  app.patch("/api/:ver/clients/:id", async (c) => {
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    const s = us();
    const existing = s.clients.get(id);
    if (!existing) return uptickError(c, 404, "Not Found");
    const { attributes } = await parseJsonApiBody(c);
    const updated = s.clients.update(id, {
      name: attributes.name ?? existing.name,
      is_active: attributes.is_active !== void 0 ? attributes.is_active : existing.is_active,
      sector: attributes.sector ?? existing.sector,
      ref: attributes.ref ?? existing.ref,
      contact_name: attributes.contact_name ?? existing.contact_name,
      contact_email: attributes.contact_email ?? existing.contact_email
    });
    return c.json({ data: formatClient(updated) });
  });
  app.delete("/api/:ver/clients/:id", (c) => {
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    if (!us().clients.get(id)) return uptickError(c, 404, "Not Found");
    us().clients.delete(id);
    return c.body(null, 204);
  });
}
function defectRoutes({ app, store }) {
  const us = () => getUptickStore(store);
  app.get("/api/:ver/defects/", (c) => {
    const s = us();
    let defects = s.defects.all();
    const assetFilter = c.req.query("asset");
    if (assetFilter) {
      const aid = parseInt(assetFilter, 10);
      if (!isNaN(aid)) defects = defects.filter((d) => d.asset_id === aid);
    }
    const propertyFilter = c.req.query("property");
    if (propertyFilter) {
      const pid = parseInt(propertyFilter, 10);
      if (!isNaN(pid)) defects = defects.filter((d) => d.property_id === pid);
    }
    const clientFilter = c.req.query("client");
    if (clientFilter) {
      const cid = parseInt(clientFilter, 10);
      if (!isNaN(cid)) defects = defects.filter((d) => d.client_id === cid);
    }
    const statusFilter = c.req.query("status") ?? c.req.query("filter[status]");
    if (statusFilter) {
      defects = defects.filter((d) => d.status === statusFilter);
    }
    const severityFilter = c.req.query("severity") ?? c.req.query("filter[severity]");
    if (severityFilter) {
      defects = defects.filter((d) => d.severity === severityFilter);
    }
    const resourcePath = `/api/${c.req.param("ver")}/defects/`;
    const include = (c.req.query("include") ?? "").split(",").map((s2) => s2.trim());
    if (include.includes("asset")) {
      const { items, nextUrl, prevUrl } = paginateItems(c, defects, resourcePath);
      const assetIds = [...new Set(items.map((d) => d.asset_id).filter((id) => id != null))];
      const included = assetIds.map((id) => s.assets.get(id)).filter((a) => a != null).map((a) => formatAsset(a, s));
      return c.json({
        data: items.map((d) => formatDefect(d, s)),
        included,
        links: { next: nextUrl, prev: prevUrl }
      });
    }
    return uptickPaginate(c, defects, (d) => formatDefect(d, s), resourcePath);
  });
  app.post("/api/:ver/defects/", async (c) => {
    const s = us();
    const { attributes, relationships } = await parseJsonApiBody(c);
    const assetId = relId(relationships.asset);
    const propertyId = relId(relationships.property);
    const clientId = relId(relationships.client);
    let resolvedPropertyId = propertyId;
    let resolvedClientId = clientId;
    if (assetId && !resolvedPropertyId) {
      const asset = s.assets.get(assetId);
      if (asset) {
        resolvedPropertyId = asset.property_id ?? null;
        resolvedClientId = resolvedClientId ?? asset.client_id ?? null;
      }
    }
    const defect = s.defects.insert({
      description: attributes.description ?? "",
      notes: attributes.notes ?? "",
      severity: attributes.severity ?? "",
      status: attributes.status ?? "open",
      asset_id: assetId ?? null,
      property_id: resolvedPropertyId ?? null,
      client_id: resolvedClientId ?? null
    });
    return c.json({ data: formatDefect(defect, s) }, 201);
  });
  app.get("/api/:ver/defects/:id", (c) => {
    const s = us();
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    const defect = s.defects.get(id);
    if (!defect) return uptickError(c, 404, "Not Found");
    return c.json({ data: formatDefect(defect, s) });
  });
  app.patch("/api/:ver/defects/:id", async (c) => {
    const s = us();
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    const existing = s.defects.get(id);
    if (!existing) return uptickError(c, 404, "Not Found");
    const { attributes, relationships } = await parseJsonApiBody(c);
    const assetId = relId(relationships.asset);
    const propertyId = relId(relationships.property);
    const clientId = relId(relationships.client);
    const updated = s.defects.update(id, {
      description: attributes.description ?? existing.description,
      notes: attributes.notes ?? existing.notes,
      severity: attributes.severity ?? existing.severity,
      status: attributes.status ?? existing.status,
      asset_id: assetId ?? existing.asset_id,
      property_id: propertyId ?? existing.property_id,
      client_id: clientId ?? existing.client_id
    });
    return c.json({ data: formatDefect(updated, s) });
  });
  app.delete("/api/:ver/defects/:id", (c) => {
    const s = us();
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    if (!s.defects.get(id)) return uptickError(c, 404, "Not Found");
    s.defects.delete(id);
    return c.body(null, 204);
  });
}
function activeBadge(active) {
  return active ? `<span class="badge badge-granted">Active</span>` : `<span class="badge badge-denied">Inactive</span>`;
}
function statusBadge(status) {
  const open = ["open", "pending"];
  const closed = ["resolved", "closed", "completed"];
  const cls = closed.includes(status.toLowerCase()) ? "badge-granted" : open.includes(status.toLowerCase()) ? "badge-requested" : "badge-denied";
  return `<span class="badge ${cls}">${escapeHtml(status)}</span>`;
}
function inspectorRoutes({ app, store }) {
  const us = () => getUptickStore(store);
  app.get("/", (c) => {
    const tab = c.req.query("tab") ?? "clients";
    const s = us();
    const clients = s.clients.all();
    const properties = s.properties.all();
    const assets = s.assets.all();
    const defects = s.defects.all();
    const assetTypes = s.assetTypes.all();
    const users = s.users.all();
    const sidebar = `
<a href="/?tab=clients"${tab === "clients" ? ' class="active"' : ""}>Clients (${clients.length})</a>
<a href="/?tab=properties"${tab === "properties" ? ' class="active"' : ""}>Properties (${properties.length})</a>
<a href="/?tab=assets"${tab === "assets" ? ' class="active"' : ""}>Assets (${assets.length})</a>
<a href="/?tab=defects"${tab === "defects" ? ' class="active"' : ""}>Defects (${defects.length})</a>
<a href="/?tab=reference"${tab === "reference" ? ' class="active"' : ""}>Reference</a>`;
    let bodyHtml = "";
    if (tab === "clients") {
      const rows = clients.length === 0 ? `<tr><td colspan="4" class="inspector-empty">No clients yet.</td></tr>` : clients.map(
        (cl) => `
<tr>
  <td style="color:#1a8c00">${cl.id}</td>
  <td><span style="color:#33ff00;font-weight:600">${escapeHtml(cl.name)}</span></td>
  <td>${escapeHtml(cl.contact_email)}</td>
  <td>${activeBadge(cl.is_active)}</td>
</tr>`
      ).join("");
      bodyHtml = `
<div class="inspector-section">
  <h2>Clients</h2>
  <table class="inspector-table">
    <thead><tr><th>ID</th><th>Name</th><th>Email</th><th>Active</th></tr></thead>
    <tbody>${rows}</tbody>
  </table>
</div>`;
    } else if (tab === "properties") {
      const rows = properties.length === 0 ? `<tr><td colspan="5" class="inspector-empty">No properties yet.</td></tr>` : properties.map((p) => {
        const client = s.clients.get(p.client_id);
        return `
<tr>
  <td style="color:#1a8c00">${p.id}</td>
  <td><span style="color:#33ff00;font-weight:600">${escapeHtml(p.name)}</span></td>
  <td>${escapeHtml(client?.name ?? String(p.client_id))}</td>
  <td>${escapeHtml(p.address_city)}</td>
  <td>${activeBadge(p.is_active)}</td>
</tr>`;
      }).join("");
      bodyHtml = `
<div class="inspector-section">
  <h2>Properties</h2>
  <table class="inspector-table">
    <thead><tr><th>ID</th><th>Name</th><th>Client</th><th>City</th><th>Active</th></tr></thead>
    <tbody>${rows}</tbody>
  </table>
</div>`;
    } else if (tab === "assets") {
      const rows = assets.length === 0 ? `<tr><td colspan="5" class="inspector-empty">No assets yet.</td></tr>` : assets.map((a) => {
        const property = a.property_id ? s.properties.get(a.property_id) : null;
        return `
<tr>
  <td style="color:#1a8c00">${a.id}</td>
  <td><span style="color:#33ff00;font-weight:600">${escapeHtml(a.name)}</span></td>
  <td>${escapeHtml(a.asset_type_name)}</td>
  <td>${escapeHtml(property?.name ?? "\u2014")}</td>
  <td>${activeBadge(a.is_active)}</td>
</tr>`;
      }).join("");
      bodyHtml = `
<div class="inspector-section">
  <h2>Assets</h2>
  <table class="inspector-table">
    <thead><tr><th>ID</th><th>Name</th><th>Type</th><th>Property</th><th>Active</th></tr></thead>
    <tbody>${rows}</tbody>
  </table>
</div>`;
    } else if (tab === "defects") {
      const rows = defects.length === 0 ? `<tr><td colspan="5" class="inspector-empty">No defects yet.</td></tr>` : defects.map((d) => {
        const asset = d.asset_id ? s.assets.get(d.asset_id) : null;
        return `
<tr>
  <td style="color:#1a8c00">${d.id}</td>
  <td>${escapeHtml(d.description.length > 60 ? d.description.slice(0, 60) + "\u2026" : d.description)}</td>
  <td>${escapeHtml(d.severity || "\u2014")}</td>
  <td>${statusBadge(d.status)}</td>
  <td>${escapeHtml(asset?.name ?? "\u2014")}</td>
</tr>`;
      }).join("");
      bodyHtml = `
<div class="inspector-section">
  <h2>Defects</h2>
  <table class="inspector-table">
    <thead><tr><th>ID</th><th>Description</th><th>Severity</th><th>Status</th><th>Asset</th></tr></thead>
    <tbody>${rows}</tbody>
  </table>
</div>`;
    } else if (tab === "reference") {
      bodyHtml = `
<div class="inspector-section">
  <h2>Reference Data</h2>
  <table class="inspector-table">
    <thead><tr><th>Entity</th><th>Count</th></tr></thead>
    <tbody>
      <tr><td>Asset Types</td><td>${assetTypes.length}</td></tr>
      <tr><td>Users</td><td>${users.length}</td></tr>
    </tbody>
  </table>
</div>
<div class="inspector-section" style="margin-top:16px">
  <h2>Asset Types</h2>
  <table class="inspector-table">
    <thead><tr><th>ID</th><th>Name</th><th>Description</th></tr></thead>
    <tbody>${assetTypes.length === 0 ? `<tr><td colspan="3" class="inspector-empty">No asset types yet.</td></tr>` : assetTypes.map((t) => `<tr><td style="color:#1a8c00">${t.id}</td><td>${escapeHtml(t.name)}</td><td>${escapeHtml(t.description)}</td></tr>`).join("")}</tbody>
  </table>
</div>
<div class="inspector-section" style="margin-top:16px">
  <h2>Users</h2>
  <table class="inspector-table">
    <thead><tr><th>ID</th><th>Name</th><th>Email</th><th>Active</th></tr></thead>
    <tbody>${users.length === 0 ? `<tr><td colspan="4" class="inspector-empty">No users yet.</td></tr>` : users.map((u) => `<tr><td style="color:#1a8c00">${u.id}</td><td>${escapeHtml(`${u.first_name} ${u.last_name}`.trim())}</td><td>${escapeHtml(u.email)}</td><td>${activeBadge(u.is_active)}</td></tr>`).join("")}</tbody>
  </table>
</div>`;
    }
    const stats = `${clients.length} client${clients.length !== 1 ? "s" : ""} \xB7 ${properties.length} propert${properties.length !== 1 ? "ies" : "y"} \xB7 ${assets.length} asset${assets.length !== 1 ? "s" : ""} \xB7 ${defects.length} defect${defects.length !== 1 ? "s" : ""}`;
    return c.html(
      renderSettingsPage(
        "Uptick Inspector",
        sidebar,
        `<div class="s-card">
  <div class="s-card-header">
    <div class="s-icon">U</div>
    <div>
      <div class="s-title">Uptick Fire Protection</div>
      <div class="s-subtitle">${stats}</div>
    </div>
  </div>
  ${bodyHtml}
</div>`,
        "Uptick"
      )
    );
  });
}
function generateToken() {
  return `uptick-token-${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`;
}
function oauthRoutes({ app }) {
  app.post("/api/oauth2/token/", async (c) => {
    let grantType;
    const contentType = c.req.header("content-type") ?? "";
    if (contentType.includes("multipart/form-data")) {
      const form = await c.req.formData().catch(() => null);
      grantType = form?.get("grant_type")?.toString();
    } else if (contentType.includes("application/x-www-form-urlencoded")) {
      const text = await c.req.text();
      const params = new URLSearchParams(text);
      grantType = params.get("grant_type") ?? void 0;
    } else {
      const body = await c.req.json().catch(() => ({}));
      grantType = typeof body.grant_type === "string" ? body.grant_type : void 0;
    }
    if (!grantType) {
      return c.json({ error: "invalid_request", error_description: "grant_type is required" }, 400);
    }
    if (grantType !== "password" && grantType !== "refresh_token") {
      return c.json({ error: "unsupported_grant_type" }, 400);
    }
    return c.json({
      access_token: generateToken(),
      refresh_token: generateToken(),
      token_type: "Bearer",
      expires_in: 3600,
      scope: "read write"
    });
  });
}
var RESOURCE_OPTIONS = {
  clients: {
    type: "Client",
    methods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
    fields: {
      name: { type: "string", required: true },
      is_active: { type: "boolean" },
      sector: { type: "string" },
      ref: { type: "string" },
      contact_name: { type: "string" },
      contact_email: { type: "string" }
    }
  },
  properties: {
    type: "Property",
    methods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
    fields: {
      name: { type: "string", required: true },
      is_active: { type: "boolean" },
      address: { type: "object" },
      client: { type: "relationship", relationship: "Client" }
    }
  },
  assets: {
    type: "Asset",
    methods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
    fields: {
      name: { type: "string", required: true },
      asset_number: { type: "string" },
      barcode: { type: "string" },
      standard_maintenance: { type: "string" },
      property: { type: "relationship", relationship: "Property" },
      client: { type: "relationship", relationship: "Client" },
      asset_type: { type: "relationship", relationship: "AssetType" }
    }
  },
  defects: {
    type: "Defect",
    methods: ["GET", "POST", "PATCH", "DELETE", "OPTIONS"],
    fields: {
      description: { type: "string", required: true },
      notes: { type: "string" },
      severity: { type: "string" },
      status: { type: "string" },
      asset: { type: "relationship", relationship: "Asset" },
      property: { type: "relationship", relationship: "Property" },
      client: { type: "relationship", relationship: "Client" }
    }
  },
  assettypes: {
    type: "AssetType",
    methods: ["GET", "POST", "OPTIONS"],
    fields: {
      name: { type: "string", required: true },
      description: { type: "string" }
    }
  },
  users: {
    type: "User",
    methods: ["GET", "POST", "OPTIONS"],
    fields: {
      username: { type: "string", required: true },
      email: { type: "string", required: true },
      first_name: { type: "string" },
      last_name: { type: "string" },
      is_active: { type: "boolean" }
    }
  }
};
function endpointIndex(ver) {
  const base = `/api/${ver}`;
  return Object.fromEntries(Object.keys(RESOURCE_OPTIONS).map((resource) => [resource, `${base}/${resource}/`]));
}
function optionsRoutes({ app }) {
  app.options("/api/version/", (c) => {
    c.header("Allow", "GET, OPTIONS");
    return c.json({
      name: "version",
      methods: ["GET", "OPTIONS"],
      fields: {
        latest: { type: "string" },
        deprecated: { type: "array" },
        imminent_removal: { type: "array" },
        removed: { type: "array" }
      }
    });
  });
  app.options("/api/:ver/", (c) => {
    c.header("Allow", "GET, OPTIONS");
    const ver = c.req.param("ver");
    return c.json({
      version: ver,
      methods: ["GET", "OPTIONS"],
      endpoints: endpointIndex(ver)
    });
  });
  app.options("/api/:ver/:resource/", (c) => {
    const resource = c.req.param("resource");
    const meta = RESOURCE_OPTIONS[resource];
    if (!meta) return uptickError(c, 404, "Not Found");
    c.header("Allow", meta.methods.join(", "));
    return c.json({
      endpoint: `/api/${c.req.param("ver")}/${resource}/`,
      ...meta
    });
  });
  app.options("/api/:ver/:resource/:id", (c) => {
    const resource = c.req.param("resource");
    const meta = RESOURCE_OPTIONS[resource];
    if (!meta) return uptickError(c, 404, "Not Found");
    c.header("Allow", meta.methods.filter((method) => method !== "POST").join(", "));
    return c.json({
      endpoint: `/api/${c.req.param("ver")}/${resource}/${c.req.param("id")}`,
      ...meta,
      methods: meta.methods.filter((method) => method !== "POST")
    });
  });
}
function propertyRoutes({ app, store }) {
  const us = () => getUptickStore(store);
  app.get("/api/:ver/properties/", (c) => {
    const s = us();
    let properties = s.properties.all();
    const clientFilter = c.req.query("client");
    if (clientFilter) {
      const cid = parseInt(clientFilter, 10);
      if (!isNaN(cid)) properties = properties.filter((p) => p.client_id === cid);
    }
    const isActive = c.req.query("is_active");
    if (isActive !== void 0) {
      const active = isActive !== "false";
      properties = properties.filter((p) => p.is_active === active);
    }
    const search = c.req.query("search")?.toLowerCase();
    if (search) {
      properties = properties.filter((p) => p.name.toLowerCase().includes(search));
    }
    return uptickPaginate(c, properties, (p) => formatProperty(p, s), `/api/${c.req.param("ver")}/properties/`);
  });
  app.post("/api/:ver/properties/", async (c) => {
    const s = us();
    const { attributes, relationships } = await parseJsonApiBody(c);
    const clientId = relId(relationships.client) ?? 0;
    const addr = attributes.address ?? {};
    const property = s.properties.insert({
      name: attributes.name ?? "New Property",
      client_id: clientId,
      is_active: attributes.is_active !== false,
      address_display: addr.display ?? "",
      address_streetline: addr.streetline ?? "",
      address_city: addr.city ?? "",
      address_state: addr.state ?? "",
      address_postal_code: addr.postal_code ?? "",
      address_country: addr.country ?? "AU"
    });
    return c.json({ data: formatProperty(property, s) }, 201);
  });
  app.get("/api/:ver/properties/:id", (c) => {
    const s = us();
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    const property = s.properties.get(id);
    if (!property) return uptickError(c, 404, "Not Found");
    return c.json({ data: formatProperty(property, s) });
  });
  app.patch("/api/:ver/properties/:id", async (c) => {
    const s = us();
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    const existing = s.properties.get(id);
    if (!existing) return uptickError(c, 404, "Not Found");
    const { attributes, relationships } = await parseJsonApiBody(c);
    const addr = attributes.address ?? {};
    const clientId = relId(relationships.client);
    const updated = s.properties.update(id, {
      name: attributes.name ?? existing.name,
      client_id: clientId ?? existing.client_id,
      is_active: attributes.is_active !== void 0 ? attributes.is_active : existing.is_active,
      address_display: addr.display ?? existing.address_display,
      address_streetline: addr.streetline ?? existing.address_streetline,
      address_city: addr.city ?? existing.address_city,
      address_state: addr.state ?? existing.address_state,
      address_postal_code: addr.postal_code ?? existing.address_postal_code,
      address_country: addr.country ?? existing.address_country
    });
    return c.json({ data: formatProperty(updated, s) });
  });
  app.delete("/api/:ver/properties/:id", (c) => {
    const s = us();
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    if (!s.properties.get(id)) return uptickError(c, 404, "Not Found");
    s.properties.delete(id);
    return c.body(null, 204);
  });
}
function referenceRoutes({ app, store }) {
  const us = () => getUptickStore(store);
  app.get("/api/:ver/assettypes/", (c) => {
    return uptickPaginate(c, us().assetTypes.all(), formatAssetType, `/api/${c.req.param("ver")}/assettypes/`);
  });
  app.post("/api/:ver/assettypes/", async (c) => {
    const { attributes } = await parseJsonApiBody(c);
    const at = us().assetTypes.insert({
      name: attributes.name ?? "New Asset Type",
      description: attributes.description ?? ""
    });
    return c.json({ data: formatAssetType(at) }, 201);
  });
  app.get("/api/:ver/assettypes/:id", (c) => {
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    const at = us().assetTypes.get(id);
    if (!at) return uptickError(c, 404, "Not Found");
    return c.json({ data: formatAssetType(at) });
  });
  app.get("/api/:ver/users/", (c) => {
    return uptickPaginate(c, us().users.all(), formatUser, `/api/${c.req.param("ver")}/users/`);
  });
  app.post("/api/:ver/users/", async (c) => {
    const { attributes } = await parseJsonApiBody(c);
    const user = us().users.insert({
      username: attributes.username ?? "newuser",
      email: attributes.email ?? "",
      first_name: attributes.first_name ?? "",
      last_name: attributes.last_name ?? "",
      is_active: attributes.is_active !== false
    });
    return c.json({ data: formatUser(user) }, 201);
  });
  app.get("/api/:ver/users/:id", (c) => {
    const id = parseId(c.req.param("id"));
    if (!id) return uptickError(c, 400, "Invalid ID");
    const user = us().users.get(id);
    if (!user) return uptickError(c, 404, "Not Found");
    return c.json({ data: formatUser(user) });
  });
  app.get("/api/version/", (c) => {
    return c.json({
      latest: "v2.15",
      deprecated: [],
      imminent_removal: [],
      removed: []
    });
  });
  app.get("/api/:ver/", (c) => {
    const ver = c.req.param("ver");
    const base = `/api/${ver}`;
    return c.json({
      clients: `${base}/clients/`,
      properties: `${base}/properties/`,
      assets: `${base}/assets/`,
      defects: `${base}/defects/`,
      assettypes: `${base}/assettypes/`,
      users: `${base}/users/`
    });
  });
}
function seedFromConfig(store, _baseUrl, config) {
  const us = getUptickStore(store);
  for (const at of config.asset_types ?? []) {
    if (!us.assetTypes.all().find((t) => t.name === at.name)) {
      us.assetTypes.insert({ name: at.name, description: at.description ?? "" });
    }
  }
  for (const u of config.users ?? []) {
    if (!us.users.findOneBy("email", u.email)) {
      us.users.insert({
        username: u.username,
        email: u.email,
        first_name: u.first_name ?? "",
        last_name: u.last_name ?? "",
        is_active: u.is_active !== false
      });
    }
  }
  for (const cl of config.clients ?? []) {
    const existing = us.clients.all().find((c) => c.name === cl.name);
    if (existing) continue;
    us.clients.insert({
      name: cl.name,
      is_active: cl.is_active !== false,
      sector: cl.sector ?? "",
      ref: cl.ref ?? "",
      contact_name: cl.contact_name ?? "",
      contact_email: cl.contact_email ?? ""
    });
  }
  for (const p of config.properties ?? []) {
    const client = p.client_name ? us.clients.all().find((c) => c.name === p.client_name) : null;
    if (p.client_name && !client) {
      console.warn(`[uptick] seedFromConfig: property "${p.name}" \u2014 client "${p.client_name}" not found, skipping`);
      continue;
    }
    const existing = client ? us.properties.findBy("client_id", client.id).find((pr) => pr.name === p.name) : us.properties.all().find((pr) => pr.name === p.name);
    if (existing) continue;
    us.properties.insert({
      name: p.name,
      client_id: client?.id ?? 0,
      is_active: p.is_active !== false,
      address_display: p.address_display ?? "",
      address_streetline: p.address_streetline ?? "",
      address_city: p.address_city ?? "",
      address_state: p.address_state ?? "",
      address_postal_code: p.address_postcode ?? "",
      address_country: p.address_country ?? "AU"
    });
  }
  for (const a of config.assets ?? []) {
    const client = a.client_name ? us.clients.all().find((c) => c.name === a.client_name) : null;
    const property = a.property_name ? us.properties.all().find((p) => p.name === a.property_name) : null;
    const assetType = a.asset_type_name ? us.assetTypes.all().find((t) => t.name === a.asset_type_name) : null;
    const duplicate = us.assets.all().find((asset) => asset.name === a.name && asset.property_id === (property?.id ?? null));
    if (duplicate) continue;
    us.assets.insert({
      name: a.name,
      asset_number: a.asset_number ?? "",
      is_active: a.is_active !== false,
      standard_maintenance: a.standard_maintenance ?? "",
      property_id: property?.id ?? null,
      client_id: client?.id ?? (property ? us.properties.get(property.id)?.client_id ?? null : null),
      asset_type_id: assetType?.id ?? null,
      asset_type_name: assetType?.name ?? a.asset_type_name ?? ""
    });
  }
  for (const d of config.defects ?? []) {
    const asset = d.asset_name ? us.assets.all().find((a) => a.name === d.asset_name) : null;
    const property = d.property_name ? us.properties.all().find((p) => p.name === d.property_name) : asset?.property_id ? us.properties.get(asset.property_id) ?? null : null;
    const client = d.client_name ? us.clients.all().find((c) => c.name === d.client_name) : property?.client_id ? us.clients.get(property.client_id) ?? null : null;
    const duplicate = us.defects.all().find(
      (def) => def.description === d.description && def.asset_id === (asset?.id ?? null) && def.property_id === (property?.id ?? null)
    );
    if (duplicate) continue;
    us.defects.insert({
      description: d.description,
      notes: d.notes ?? "",
      severity: d.severity ?? "",
      status: d.status ?? "open",
      asset_id: asset?.id ?? null,
      property_id: property?.id ?? null,
      client_id: client?.id ?? null
    });
  }
}
function storeToSeedConfig(store, _baseUrl) {
  const us = getUptickStore(store);
  const clientName = (id) => id != null ? us.clients.get(id)?.name ?? void 0 : void 0;
  const propertyName = (id) => id != null ? us.properties.get(id)?.name ?? void 0 : void 0;
  const assetName = (id) => id != null ? us.assets.get(id)?.name ?? void 0 : void 0;
  return {
    asset_types: us.assetTypes.all().map((t) => ({ name: t.name, description: t.description })),
    users: us.users.all().map((u) => ({
      username: u.username,
      email: u.email,
      first_name: u.first_name,
      last_name: u.last_name,
      is_active: u.is_active
    })),
    clients: us.clients.all().map((c) => ({
      name: c.name,
      is_active: c.is_active,
      sector: c.sector,
      ref: c.ref,
      contact_name: c.contact_name,
      contact_email: c.contact_email
    })),
    properties: us.properties.all().map((p) => ({
      name: p.name,
      client_name: clientName(p.client_id),
      is_active: p.is_active,
      address_display: p.address_display,
      address_streetline: p.address_streetline,
      address_city: p.address_city,
      address_state: p.address_state,
      address_postcode: p.address_postal_code,
      address_country: p.address_country
    })),
    assets: us.assets.all().map((a) => ({
      name: a.name,
      asset_number: a.asset_number,
      is_active: a.is_active,
      standard_maintenance: a.standard_maintenance,
      property_name: propertyName(a.property_id),
      client_name: clientName(a.client_id),
      asset_type_name: a.asset_type_name || void 0
    })),
    defects: us.defects.all().map((d) => ({
      description: d.description,
      notes: d.notes,
      severity: d.severity,
      status: d.status,
      asset_name: assetName(d.asset_id),
      property_name: propertyName(d.property_id),
      client_name: clientName(d.client_id)
    }))
  };
}
var uptickPlugin = {
  name: "uptick",
  register(app, store, webhooks, baseUrl, tokenMap) {
    const ctx = { app, store, webhooks, baseUrl, tokenMap };
    app.get("/health", (c) => c.json({ status: "ok", service: "uptick" }));
    oauthRoutes(ctx);
    inspectorRoutes(ctx);
    optionsRoutes(ctx);
    app.use("/api/*", requireAuthWhen("EMULATE_UPTICK_REQUIRE_AUTH", "EMULATE_REQUIRE_AUTH"));
    referenceRoutes(ctx);
    clientRoutes(ctx);
    propertyRoutes(ctx);
    assetRoutes(ctx);
    defectRoutes(ctx);
  },
  seed(_store, _baseUrl) {
  }
};
var index_default = uptickPlugin;
export {
  index_default as default,
  getUptickStore,
  seedFromConfig,
  storeToSeedConfig,
  uptickPlugin
};
//# sourceMappingURL=dist-IJ2NCR7X.js.map