// src/nextjs/middleware.ts
import { NextResponse } from "next/server";

// src/constants.ts
var ENV_URL = "SYLPHX_URL";
var ENV_SECRET_URL = "SYLPHX_SECRET_URL";
var DEFAULT_SDK_API_HOST = "api.sylphx.com";
var SDK_PLATFORM = typeof window !== "undefined" ? "browser" : typeof process !== "undefined" && process.versions?.node ? "node" : "unknown";
var TOKEN_EXPIRY_BUFFER_MS = 3e4;
var SESSION_TOKEN_LIFETIME_SECONDS = 5 * 60;
var SESSION_TOKEN_LIFETIME_MS = SESSION_TOKEN_LIFETIME_SECONDS * 1e3;
var REFRESH_TOKEN_LIFETIME_SECONDS = 30 * 24 * 60 * 60;
var FLAGS_CACHE_TTL_MS = 5 * 60 * 1e3;
var FLAGS_STALE_WHILE_REVALIDATE_MS = 60 * 1e3;
var ANALYTICS_SESSION_TIMEOUT_MS = 30 * 60 * 1e3;
var WEBHOOK_MAX_AGE_MS = 5 * 60 * 1e3;
var WEBHOOK_CLOCK_SKEW_MS = 30 * 1e3;
var PKCE_CODE_TTL_MS = 10 * 60 * 1e3;
var JOBS_DLQ_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
var SESSION_REPLAY_MAX_DURATION_MS = 60 * 60 * 1e3;
var FLAGS_EXPOSURE_DEDUPE_WINDOW_MS = 60 * 60 * 1e3;
var CLICK_ID_EXPIRY_MS = 90 * 24 * 60 * 60 * 1e3;
var STALE_TIME_FREQUENT_MS = 60 * 1e3;
var STALE_TIME_MODERATE_MS = 2 * 60 * 1e3;
var STALE_TIME_STABLE_MS = 5 * 60 * 1e3;
var STALE_TIME_STATS_MS = 30 * 1e3;
var NEW_USER_THRESHOLD_MS = 60 * 1e3;
var STORAGE_MULTIPART_THRESHOLD_BYTES = 5 * 1024 * 1024;
var STORAGE_DEFAULT_MAX_SIZE_BYTES = 5 * 1024 * 1024;
var STORAGE_AVATAR_MAX_SIZE_BYTES = 2 * 1024 * 1024;
var STORAGE_LARGE_MAX_SIZE_BYTES = 10 * 1024 * 1024;
var JWK_CACHE_TTL_MS = 60 * 60 * 1e3;
var ETAG_CACHE_TTL_MS = 5 * 60 * 1e3;

// src/key-validation.ts
var PUBLIC_KEY_PATTERN = /^pk_(dev|stg|prod|prev)(?:_[a-z0-9]{12})?_[a-f0-9]{32}$/;
var APP_ID_PATTERN = /^(app|pk)_(dev|stg|prod|prev)_[a-z0-9_-]+$/;
var SECRET_KEY_PATTERN = /^sk_(dev|stg|prod|prev)_[a-z0-9_-]+$/;
var ENV_PREFIX_MAP = {
  dev: "development",
  stg: "staging",
  prod: "production",
  prev: "preview"
};
function detectKeyIssues(key) {
  const issues = [];
  if (key !== key.trim()) issues.push("whitespace");
  if (key.includes("\n")) issues.push("newline");
  if (key.includes("\r")) issues.push("carriage-return");
  if (key.includes(" ")) issues.push("space");
  if (key !== key.toLowerCase()) issues.push("uppercase-chars");
  return issues;
}
function createSanitizationWarning(keyType, issues, envVarName) {
  const keyTypeName = keyType === "appId" ? "App ID" : "Secret Key";
  return `[Sylphx] ${keyTypeName} contains ${issues.join(", ")}. This is commonly caused by Vercel CLI's 'env pull' command.

To fix permanently:
1. Go to Vercel Dashboard \u2192 Your Project \u2192 Settings \u2192 Environment Variables
2. Edit ${envVarName}
3. Remove any trailing whitespace or newline characters
4. Redeploy your application

The SDK will automatically sanitize the key, but fixing the source is recommended.`;
}
function createInvalidKeyError(keyType, key, envVarName) {
  const maskedKey = key.length > 20 ? `${key.slice(0, 20)}...` : key;
  const formatHint = keyType === "appId" ? "pk_(dev|stg|prod|prev)_{ref}_{hex} or app_(dev|stg|prod|prev)_[id]" : "sk_(dev|stg|prod|prev)_{ref}_{hex}";
  const keyTypeName = keyType === "appId" ? "App ID" : "Secret Key";
  return `[Sylphx] Invalid ${keyTypeName} format.

Expected format: ${formatHint}
Received: "${maskedKey}"

Please check your ${envVarName} environment variable.
You can find your keys in the Sylphx Console \u2192 API Keys.

Common issues:
\u2022 Key has uppercase characters (must be lowercase)
\u2022 Key has wrong prefix (App ID: pk_ or app_, Secret Key: sk_)
\u2022 Key has invalid environment (must be dev, stg, prod, or prev)
\u2022 Key was copied with extra whitespace`;
}
function extractEnvironment(key) {
  const match = key.match(/^(?:app|pk|sk)_(dev|stg|prod|prev)_/);
  if (!match) return void 0;
  return ENV_PREFIX_MAP[match[1]];
}
function validateKeyForType(key, keyType, pattern, envVarName) {
  const keyTypeName = keyType === "appId" ? "App ID" : "Secret Key";
  if (!key) {
    return {
      valid: false,
      sanitizedKey: "",
      error: `[Sylphx] ${keyTypeName} is required. Set ${envVarName} in your environment variables.`,
      issues: ["missing"]
    };
  }
  const issues = detectKeyIssues(key);
  if (pattern.test(key)) {
    return {
      valid: true,
      sanitizedKey: key,
      keyType,
      environment: extractEnvironment(key),
      issues: []
    };
  }
  const sanitized = key.trim().toLowerCase();
  if (pattern.test(sanitized)) {
    return {
      valid: true,
      sanitizedKey: sanitized,
      keyType,
      environment: extractEnvironment(sanitized),
      warning: createSanitizationWarning(keyType, issues, envVarName),
      issues
    };
  }
  return {
    valid: false,
    sanitizedKey: "",
    error: createInvalidKeyError(keyType, key, envVarName),
    issues: [...issues, "invalid-format"]
  };
}
function validatePublicKey(key) {
  return validateKeyForType(key, "publicKey", PUBLIC_KEY_PATTERN, "publishable credential");
}
function validateAppId(key) {
  return validateKeyForType(key, "appId", APP_ID_PATTERN, "NEXT_PUBLIC_SYLPHX_APP_ID");
}
function validateAndSanitizeAppId(key) {
  const result = validateAppId(key);
  if (!result.valid) {
    throw new Error(result.error);
  }
  if (result.warning) {
    console.warn(result.warning);
  }
  return result.sanitizedKey;
}
function validateSecretKey(key) {
  return validateKeyForType(key, "secret", SECRET_KEY_PATTERN, "secret credential");
}
function validateAndSanitizeSecretKey(key) {
  const result = validateSecretKey(key);
  if (!result.valid) {
    throw new Error(result.error);
  }
  if (result.warning) {
    console.warn(result.warning);
  }
  return result.sanitizedKey;
}
function detectEnvironment(key) {
  const sanitized = key.trim().toLowerCase();
  if (sanitized.startsWith("pk_")) {
    const result = validatePublicKey(sanitized);
    if (!result.valid) throw new Error(result.error);
    return result.environment;
  }
  if (sanitized.startsWith("sk_")) {
    const result = validateSecretKey(sanitized);
    if (!result.valid) throw new Error(result.error);
    return result.environment;
  }
  if (sanitized.startsWith("app_")) {
    const result = validateAppId(sanitized);
    if (!result.valid) throw new Error(result.error);
    return result.environment;
  }
  throw new Error(
    `[Sylphx] Invalid key format. Key must start with 'pk_' (publishable), 'sk_' (secret), or 'app_' (legacy App ID).`
  );
}
function getCookieNamespace(secretKey) {
  const env = detectEnvironment(secretKey);
  const shortEnv = env === "development" ? "dev" : env === "staging" ? "stg" : env === "preview" ? "prev" : "prod";
  return `sylphx_${shortEnv}`;
}

// src/nextjs/cookies.ts
import { cookies } from "next/headers";
function getCookieNames(namespace) {
  return {
    /** HttpOnly JWT access token (5 min) */
    SESSION: `__${namespace}_session`,
    /** HttpOnly refresh token (30 days) */
    REFRESH: `__${namespace}_refresh`,
    /** JS-readable user data for client hydration (5 min) */
    USER: `__${namespace}_user`,
    /** HttpOnly active organization ID used to preserve org-scoped sessions */
    ACTIVE_ORG_ID: `__${namespace}_active_org_id`,
    /** HttpOnly active organization slug used to preserve org-scoped sessions */
    ACTIVE_ORG_SLUG: `__${namespace}_active_org_slug`
  };
}
var SESSION_TOKEN_LIFETIME = SESSION_TOKEN_LIFETIME_SECONDS;
var REFRESH_TOKEN_LIFETIME = REFRESH_TOKEN_LIFETIME_SECONDS;
var ACTIVE_ORG_LIFETIME = REFRESH_TOKEN_LIFETIME_SECONDS;
var SECURE_COOKIE_OPTIONS = {
  httpOnly: true,
  secure: process.env.NODE_ENV === "production",
  sameSite: "lax",
  path: "/"
};
var USER_COOKIE_OPTIONS = {
  httpOnly: false,
  // Readable by client JS for hydration
  secure: process.env.NODE_ENV === "production",
  sameSite: "lax",
  path: "/"
};
var ACTIVE_ORG_COOKIE_OPTIONS = {
  ...SECURE_COOKIE_OPTIONS,
  httpOnly: true
};
async function getAuthCookies(namespace) {
  const cookieStore = await cookies();
  const names = getCookieNames(namespace);
  const sessionToken = cookieStore.get(names.SESSION)?.value || null;
  const refreshToken = cookieStore.get(names.REFRESH)?.value || null;
  const userCookieValue = cookieStore.get(names.USER)?.value || null;
  let user = null;
  let expiresAt = null;
  if (userCookieValue) {
    try {
      const parsed = JSON.parse(userCookieValue);
      user = parsed.user;
      expiresAt = parsed.expiresAt;
    } catch {
      user = null;
      expiresAt = null;
    }
  }
  return { sessionToken, refreshToken, user, expiresAt };
}
async function setAuthCookies(namespace, response, options) {
  const cookieStore = await cookies();
  const names = getCookieNames(namespace);
  const sessionLifetime = options?.sessionLifetime ?? SESSION_TOKEN_LIFETIME;
  const expiresAt = Date.now() + sessionLifetime * 1e3;
  cookieStore.set(names.SESSION, response.accessToken, {
    ...SECURE_COOKIE_OPTIONS,
    maxAge: sessionLifetime
  });
  cookieStore.set(names.REFRESH, response.refreshToken, {
    ...SECURE_COOKIE_OPTIONS,
    maxAge: REFRESH_TOKEN_LIFETIME
  });
  const userData = {
    user: response.user,
    expiresAt
  };
  cookieStore.set(names.USER, JSON.stringify(userData), {
    ...USER_COOKIE_OPTIONS,
    maxAge: sessionLifetime
  });
}
async function clearAuthCookies(namespace) {
  const cookieStore = await cookies();
  const names = getCookieNames(namespace);
  cookieStore.delete(names.SESSION);
  cookieStore.delete(names.REFRESH);
  cookieStore.delete(names.USER);
  cookieStore.delete(names.ACTIVE_ORG_ID);
  cookieStore.delete(names.ACTIVE_ORG_SLUG);
}
async function isSessionExpired(namespace) {
  const { expiresAt } = await getAuthCookies(namespace);
  if (!expiresAt) return true;
  return expiresAt < Date.now() + TOKEN_EXPIRY_BUFFER_MS;
}
async function hasRefreshToken(namespace) {
  const { refreshToken } = await getAuthCookies(namespace);
  return !!refreshToken;
}
function setAuthCookiesMiddleware(response, namespace, tokens) {
  const names = getCookieNames(namespace);
  const expiresAt = Date.now() + SESSION_TOKEN_LIFETIME * 1e3;
  response.cookies.set(names.SESSION, tokens.accessToken, {
    ...SECURE_COOKIE_OPTIONS,
    maxAge: SESSION_TOKEN_LIFETIME
  });
  response.cookies.set(names.REFRESH, tokens.refreshToken, {
    ...SECURE_COOKIE_OPTIONS,
    maxAge: REFRESH_TOKEN_LIFETIME
  });
  const userData = {
    user: tokens.user,
    expiresAt
  };
  response.cookies.set(names.USER, JSON.stringify(userData), {
    ...USER_COOKIE_OPTIONS,
    maxAge: SESSION_TOKEN_LIFETIME
  });
}
function clearAuthCookiesMiddleware(response, namespace) {
  const names = getCookieNames(namespace);
  response.cookies.delete(names.SESSION);
  response.cookies.delete(names.REFRESH);
  response.cookies.delete(names.USER);
  response.cookies.delete(names.ACTIVE_ORG_ID);
  response.cookies.delete(names.ACTIVE_ORG_SLUG);
}
function parseUserCookie(value) {
  try {
    return JSON.parse(value);
  } catch {
    return null;
  }
}

// src/connection-url.ts
var SYLPHX_PROTOCOL = "sylphx:";
var DEFAULT_VERSION = "v1";
var CREDENTIAL_REGEX = /^(pk|sk)_(dev|stg|prod|prev)(?:_[a-z0-9]{12})?_[a-f0-9]{32,64}$/;
var VERSION_REGEX = /^v[0-9]+$/;
var SLUG_REGEX = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/;
var InvalidConnectionUrlError = class _InvalidConnectionUrlError extends Error {
  code = "INVALID_CONNECTION_URL";
  constructor(message2) {
    super(message2);
    this.name = "InvalidConnectionUrlError";
    Object.setPrototypeOf(this, _InvalidConnectionUrlError.prototype);
  }
};
function fail(reason) {
  throw new InvalidConnectionUrlError(`Invalid Sylphx connection URL: ${reason}`);
}
function parseCredential(raw) {
  const match = CREDENTIAL_REGEX.exec(raw);
  if (!match) {
    fail(`credential must match (pk|sk)_(dev|stg|prod|prev)(_{ref})?_{hex}, got "${raw}"`);
  }
  return {
    credentialType: match[1],
    env: match[2]
  };
}
function validateSlug(candidate) {
  if (!candidate || candidate.length > 63 || !SLUG_REGEX.test(candidate)) {
    fail(`slug "${candidate}" is not a valid DNS label (lowercase alnum + hyphens, 1-63 chars)`);
  }
  return candidate;
}
function parseConnectionUrl(url) {
  if (typeof url !== "string" || url.length === 0) {
    fail("url must be a non-empty string");
  }
  let parsed;
  try {
    parsed = new URL(url);
  } catch {
    fail(`not a valid URL: "${url}"`);
  }
  if (parsed.protocol !== SYLPHX_PROTOCOL) {
    fail(`protocol must be "sylphx:", got "${parsed.protocol}"`);
  }
  const credential = decodeURIComponent(parsed.username);
  if (!credential) {
    fail("missing credential (expected `sylphx://<credential>@<host>`)");
  }
  if (parsed.password) {
    fail("connection URL must not contain a password component");
  }
  const { credentialType, env } = parseCredential(credential);
  const host = parsed.host;
  if (!host) {
    fail("missing host");
  }
  const hostname = parsed.hostname;
  const firstDot = hostname.indexOf(".");
  if (firstDot <= 0) {
    fail(`host "${hostname}" must contain at least one dot (slug.domain)`);
  }
  const slugCandidate = hostname.slice(0, firstDot);
  const domainSuffix = hostname.slice(firstDot + 1);
  if (!domainSuffix) {
    fail(`host "${hostname}" has empty domain suffix`);
  }
  const slug = validateSlug(slugCandidate);
  const rawPath = parsed.pathname.replace(/^\/+/, "").replace(/\/+$/, "");
  let version = DEFAULT_VERSION;
  if (rawPath !== "") {
    if (!VERSION_REGEX.test(rawPath)) {
      fail(`path "${parsed.pathname}" must be empty or match /v{N}`);
    }
    version = rawPath;
  }
  if (parsed.search) {
    fail("connection URL must not contain a query string");
  }
  if (parsed.hash) {
    fail("connection URL must not contain a fragment");
  }
  const apiBaseUrl = `https://${host}/${version}`;
  return {
    credential,
    credentialType,
    env,
    slug,
    host,
    apiBaseUrl
  };
}

// src/nextjs/runtime-config.ts
var SylphxRoutingConfigurationError = class extends Error {
  name = "SylphxRoutingConfigurationError";
};
function normalizePlatformUrl(url) {
  const trimmed = url.trim().replace(/\/+$/, "");
  return trimmed.endsWith("/v1") ? trimmed.slice(0, -3) : trimmed;
}
function parseConnection(value) {
  if (!value) return null;
  return parseConnectionUrl(value.trim());
}
function platformUrlFromConnectionUrl(value) {
  const parsed = parseConnection(value);
  return parsed ? `https://${parsed.host}` : null;
}
function secretKeyFromConnectionUrl(value) {
  const parsed = parseConnection(value);
  if (!parsed || parsed.credentialType !== "sk") return null;
  return parsed.credential;
}
function resolveNextjsPlatformUrl(options) {
  if (options.explicitPlatformUrl) return normalizePlatformUrl(options.explicitPlatformUrl);
  const fromExplicitSecretUrl = platformUrlFromConnectionUrl(options.secretUrl);
  if (fromExplicitSecretUrl) return fromExplicitSecretUrl;
  const fromSecretUrl = platformUrlFromConnectionUrl(process.env[ENV_SECRET_URL]);
  if (fromSecretUrl) return fromSecretUrl;
  const fromConnectionUrl = platformUrlFromConnectionUrl(process.env[ENV_URL]);
  if (fromConnectionUrl) return fromConnectionUrl;
  const fromBaasOverride = process.env.SYLPHX_BAAS_URL ?? process.env.SYLPHX_RUNTIME_URL;
  if (fromBaasOverride) return normalizePlatformUrl(fromBaasOverride);
  throw new SylphxRoutingConfigurationError(
    '[Sylphx] BaaS routing target is required for @sylphx/sdk/nextjs. Set SYLPHX_SECRET_URL="sylphx://sk_<env>_<hex>@<tenant>.api.sylphx.com" or SYLPHX_URL="sylphx://<credential>@<tenant>.api.sylphx.com" or pass platformUrl explicitly. New-format sk_* credentials do not carry routing material.'
  );
}
function resolveNextjsSecretKey(options) {
  if (options.explicitSecretKey?.trim()) return options.explicitSecretKey.trim();
  const fromExplicitSecretUrl = secretKeyFromConnectionUrl(options.explicitSecretUrl);
  if (fromExplicitSecretUrl) return fromExplicitSecretUrl;
  const fromSecretUrl = secretKeyFromConnectionUrl(process.env[ENV_SECRET_URL]);
  if (fromSecretUrl) return fromSecretUrl;
  const fromGenericUrl = secretKeyFromConnectionUrl(process.env[ENV_URL]);
  if (fromGenericUrl) return fromGenericUrl;
  return null;
}

// src/nextjs/middleware.ts
function isTokenResponse(data) {
  return typeof data === "object" && data !== null && "accessToken" in data && "refreshToken" in data && "user" in data && typeof data.accessToken === "string" && typeof data.refreshToken === "string";
}
function decodeJwtPayload(token) {
  try {
    const parts = token.split(".");
    if (parts.length !== 3) return null;
    const payload = parts[1];
    const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
    const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "=");
    const jsonPayload = atob(padded);
    return JSON.parse(jsonPayload);
  } catch {
    return null;
  }
}
function isTokenExpired(token) {
  const payload = decodeJwtPayload(token);
  if (!payload?.exp) return true;
  return payload.exp * 1e3 < Date.now() + TOKEN_EXPIRY_BUFFER_MS;
}
function matchesPattern(pathname, pattern) {
  if (pattern === pathname) return true;
  if (pattern.endsWith("/*")) {
    const base = pattern.slice(0, -2);
    return pathname === base || pathname.startsWith(`${base}/`);
  }
  if (pattern.endsWith("/**")) {
    const base = pattern.slice(0, -3);
    return pathname === base || pathname.startsWith(`${base}/`);
  }
  return false;
}
function matchesAny(pathname, patterns) {
  return patterns.some((p) => matchesPattern(pathname, p));
}
function requestPathWithSearch(request) {
  const { pathname, search } = request.nextUrl;
  return `${pathname}${search}`;
}
function isSafeRelativeRedirectPath(value) {
  return typeof value === "string" && value.startsWith("/") && !value.startsWith("//");
}
function resolveSafeRelativeRedirectPath(value, fallback) {
  if (isSafeRelativeRedirectPath(value)) return value;
  if (isSafeRelativeRedirectPath(fallback)) return fallback;
  return "/";
}
async function handleCallback(request, ctx) {
  const { searchParams } = request.nextUrl;
  const code = searchParams.get("code");
  const error = searchParams.get("error");
  const errorDescription = searchParams.get("error_description");
  const redirectTo = searchParams.get("redirect_to") || ctx.config.afterSignInUrl;
  ctx.log("Callback", { hasCode: !!code, error });
  if (error) {
    const url = new URL(ctx.config.signInUrl, request.url);
    url.searchParams.set("error", error);
    if (errorDescription) url.searchParams.set("error_description", errorDescription);
    return NextResponse.redirect(url);
  }
  if (!code) {
    const url = new URL(ctx.config.signInUrl, request.url);
    url.searchParams.set("error", "missing_code");
    return NextResponse.redirect(url);
  }
  try {
    const res = await fetch(`${ctx.platformUrl}/v1/auth/token`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        grant_type: "authorization_code",
        code,
        client_secret: ctx.secretKey
      })
    });
    if (!res.ok) {
      const data2 = await res.json().catch(() => ({}));
      const url = new URL(ctx.config.signInUrl, request.url);
      url.searchParams.set("error", data2.error || "token_exchange_failed");
      return NextResponse.redirect(url);
    }
    const data = await res.json();
    if (!isTokenResponse(data)) {
      const url = new URL(ctx.config.signInUrl, request.url);
      url.searchParams.set("error", "invalid_response");
      return NextResponse.redirect(url);
    }
    const successUrl = new URL(redirectTo, request.url);
    const response = NextResponse.redirect(successUrl);
    setAuthCookiesMiddleware(response, ctx.namespace, data);
    ctx.log("Callback success", { redirectTo });
    return response;
  } catch (err) {
    console.error("[Sylphx] Callback error:", err);
    const url = new URL(ctx.config.signInUrl, request.url);
    url.searchParams.set("error", "internal_error");
    return NextResponse.redirect(url);
  }
}
async function handleSignOut(request, ctx) {
  ctx.log("Signout");
  const refreshToken = request.cookies.get(ctx.cookieNames.REFRESH)?.value;
  if (refreshToken) {
    try {
      await fetch(`${ctx.platformUrl}/v1/auth/revoke`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          token: refreshToken,
          client_secret: ctx.secretKey
        })
      });
    } catch {
    }
  }
  const url = new URL(ctx.config.afterSignOutUrl, request.url);
  const response = NextResponse.redirect(url);
  clearAuthCookiesMiddleware(response, ctx.namespace);
  ctx.log("Signout complete");
  return response;
}
function handleToken(request, ctx) {
  ctx.log("Token request");
  const sessionToken = request.cookies.get(ctx.cookieNames.SESSION)?.value;
  if (!sessionToken) {
    ctx.log("No session token");
    return NextResponse.json({ error: "Not authenticated", accessToken: null }, { status: 401 });
  }
  if (isTokenExpired(sessionToken)) {
    ctx.log("Session token expired");
    return NextResponse.json({ error: "Session expired", accessToken: null }, { status: 401 });
  }
  ctx.log("Token returned");
  return NextResponse.json({ accessToken: sessionToken });
}
function resolveOrgScopedTokenExpiresIn(data) {
  if (typeof data.expiresIn === "number") return data.expiresIn;
  if (typeof data.expires_in === "number") return data.expires_in;
  return SESSION_TOKEN_LIFETIME;
}
function resolveOrgScopedAccessToken(data) {
  if (data.accessToken) return data.accessToken;
  if (data.access_token) return data.access_token;
  return null;
}
function resolveOrgScopedRefreshToken(data, fallbackRefreshToken) {
  if (data.refreshToken) return data.refreshToken;
  if (data.refresh_token) return data.refresh_token;
  return fallbackRefreshToken;
}
function resolveOrgScopedTokenType(data) {
  if (data.tokenType) return data.tokenType;
  if (data.token_type) return data.token_type;
  return "Bearer";
}
function parseUserCookie2(value) {
  if (!value) return null;
  try {
    return JSON.parse(decodeCookieValue(value));
  } catch {
    return null;
  }
}
function decodeCookieValue(value) {
  try {
    return decodeURIComponent(value);
  } catch {
    return value;
  }
}
function readFirstCookieValue(request, names) {
  for (const name of names) {
    const value = request.cookies.get(name)?.value;
    if (value) return decodeCookieValue(value);
  }
  return null;
}
function uniqueCookieNames(names) {
  return [...new Set(names.filter((name) => Boolean(name)))];
}
function readActiveOrganizationContext(request, ctx, sessionToken) {
  const orgIdCookieNames = uniqueCookieNames([
    ctx.cookieNames.ACTIVE_ORG_ID,
    ...ctx.config.organizationContext.additionalOrgIdCookies
  ]);
  const orgSlugCookieNames = uniqueCookieNames([
    ctx.cookieNames.ACTIVE_ORG_SLUG,
    ...ctx.config.organizationContext.additionalOrgSlugCookies
  ]);
  const fromCookie = {
    id: readFirstCookieValue(request, orgIdCookieNames),
    slug: readFirstCookieValue(request, orgSlugCookieNames)
  };
  if (fromCookie.id || fromCookie.slug) return fromCookie;
  const payload = sessionToken ? decodeJwtPayload(sessionToken) : null;
  return {
    id: payload?.org_id ?? null,
    slug: payload?.org_slug ?? null
  };
}
function setActiveOrganizationCookies(response, ctx, org) {
  if (org.id) {
    response.cookies.set(ctx.cookieNames.ACTIVE_ORG_ID, org.id, {
      ...ACTIVE_ORG_COOKIE_OPTIONS,
      maxAge: ACTIVE_ORG_LIFETIME
    });
  }
  if (org.slug) {
    response.cookies.set(ctx.cookieNames.ACTIVE_ORG_SLUG, org.slug, {
      ...ACTIVE_ORG_COOKIE_OPTIONS,
      maxAge: ACTIVE_ORG_LIFETIME
    });
  }
}
async function getUserOrganizations(accessToken, ctx) {
  try {
    const res = await fetch(`${ctx.platformUrl}/v1/orgs/memberships`, {
      method: "GET",
      headers: {
        "Content-Type": "application/json",
        "x-app-secret": ctx.secretKey,
        Authorization: `Bearer ${accessToken}`
      }
    });
    if (!res.ok) {
      ctx.log("Organization memberships fetch failed", res.status);
      return null;
    }
    const data = await res.json().catch(() => ({}));
    return Array.isArray(data.organizations) ? data.organizations : null;
  } catch (err) {
    ctx.log("Organization memberships fetch error", err);
    return null;
  }
}
async function getOrgScopedTokens(accessToken, orgId, ctx) {
  try {
    const res = await fetch(`${ctx.platformUrl}/v1/auth/switch-org`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-app-secret": ctx.secretKey,
        Authorization: `Bearer ${accessToken}`
      },
      body: JSON.stringify({ orgId })
    });
    const data = await res.json().catch(() => ({}));
    if (!res.ok) {
      ctx.log("Org scope restore failed", data.error || data.message || res.status);
      return { status: res.status, data };
    }
    return { status: res.status, data };
  } catch (err) {
    ctx.log("Org scope restore error", err);
    return null;
  }
}
async function restoreOrganizationScopeAfterRefresh(request, ctx, refreshedTokens, previousSessionToken) {
  if (!ctx.config.organizationContext.enabled) {
    return { tokens: refreshedTokens, activeOrganization: null };
  }
  const activeOrg = readActiveOrganizationContext(request, ctx, previousSessionToken);
  let targetOrgId = activeOrg.id;
  let targetOrgSlug = activeOrg.slug;
  let organizations = null;
  if (!targetOrgId && targetOrgSlug) {
    organizations = await getUserOrganizations(refreshedTokens.accessToken, ctx);
    targetOrgId = organizations?.find((org) => org.slug === targetOrgSlug)?.id ?? null;
  }
  if (!targetOrgId && !targetOrgSlug && ctx.config.organizationContext.autoSelectSingleOrganization) {
    organizations = organizations ?? await getUserOrganizations(refreshedTokens.accessToken, ctx);
    const onlyOrg = organizations?.length === 1 ? organizations[0] : null;
    targetOrgId = onlyOrg?.id ?? null;
    targetOrgSlug = onlyOrg?.slug ?? null;
  }
  if (!targetOrgId) {
    return { tokens: refreshedTokens, activeOrganization: null };
  }
  const scoped = await getOrgScopedTokens(refreshedTokens.accessToken, targetOrgId, ctx);
  const scopedData = scoped?.data;
  const accessToken = scopedData ? resolveOrgScopedAccessToken(scopedData) : null;
  if (!scoped || scoped.status >= 400 || !scopedData || !accessToken) {
    return { tokens: refreshedTokens, activeOrganization: null };
  }
  const payload = decodeJwtPayload(accessToken);
  const resolvedOrg = {
    id: payload?.org_id ?? targetOrgId,
    slug: payload?.org_slug ?? targetOrgSlug
  };
  return {
    tokens: {
      ...refreshedTokens,
      accessToken,
      refreshToken: resolveOrgScopedRefreshToken(scopedData, refreshedTokens.refreshToken),
      expiresIn: resolveOrgScopedTokenExpiresIn(scopedData),
      tokenType: resolveOrgScopedTokenType(scopedData),
      user: scopedData.user ?? refreshedTokens.user
    },
    activeOrganization: resolvedOrg
  };
}
async function handleSwitchOrg(request, ctx) {
  ctx.log("Switch org request");
  if (request.method !== "POST") {
    return NextResponse.json({ error: "Method not allowed" }, { status: 405 });
  }
  const sessionToken = request.cookies.get(ctx.cookieNames.SESSION)?.value;
  if (!sessionToken || isTokenExpired(sessionToken)) {
    return NextResponse.json({ error: "Not authenticated", accessToken: null }, { status: 401 });
  }
  let orgId = null;
  let requestedOrgSlug = null;
  try {
    const body = await request.json();
    orgId = typeof body.orgId === "string" && body.orgId.trim() ? body.orgId.trim() : null;
    requestedOrgSlug = typeof body.orgSlug === "string" && body.orgSlug.trim() ? body.orgSlug.trim() : null;
  } catch {
    return NextResponse.json({ error: "Invalid request body" }, { status: 400 });
  }
  if (!orgId) {
    return NextResponse.json({ error: "orgId is required" }, { status: 400 });
  }
  try {
    const scoped = await getOrgScopedTokens(sessionToken, orgId, ctx);
    const data = scoped?.data;
    if (!scoped || scoped.status >= 400 || !data) {
      return NextResponse.json(
        { error: data?.error || data?.message || "switch_org_failed" },
        { status: scoped?.status ?? 502 }
      );
    }
    const accessToken = resolveOrgScopedAccessToken(data);
    if (!accessToken) {
      return NextResponse.json(
        { error: data.error || data.message || "invalid_response" },
        { status: 502 }
      );
    }
    const expiresIn = resolveOrgScopedTokenExpiresIn(data);
    const expiresAt = Date.now() + expiresIn * 1e3;
    const response = NextResponse.json({
      accessToken,
      token: accessToken,
      expiresIn,
      tokenType: resolveOrgScopedTokenType(data),
      user: data.user ?? null
    });
    response.cookies.set(ctx.cookieNames.SESSION, accessToken, {
      ...SECURE_COOKIE_OPTIONS,
      maxAge: expiresIn
    });
    const existingUser = parseUserCookie2(request.cookies.get(ctx.cookieNames.USER)?.value);
    const user = data.user ?? existingUser?.user;
    if (user) {
      response.cookies.set(
        ctx.cookieNames.USER,
        JSON.stringify({
          user,
          expiresAt
        }),
        {
          ...USER_COOKIE_OPTIONS,
          maxAge: expiresIn
        }
      );
    }
    const payload = decodeJwtPayload(accessToken);
    setActiveOrganizationCookies(response, ctx, {
      id: payload?.org_id ?? orgId,
      slug: payload?.org_slug ?? requestedOrgSlug
    });
    ctx.log("Switch org success", { orgId });
    return response;
  } catch (err) {
    ctx.log("Switch org error", err);
    return NextResponse.json({ error: "internal_error" }, { status: 500 });
  }
}
async function refreshTokens(refreshToken, ctx) {
  ctx.log("Refreshing tokens");
  try {
    const res = await fetch(`${ctx.platformUrl}/v1/auth/token`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        grant_type: "refresh_token",
        refresh_token: refreshToken,
        client_secret: ctx.secretKey
      })
    });
    if (!res.ok) {
      ctx.log("Refresh failed", res.status);
      return null;
    }
    const data = await res.json();
    if (!isTokenResponse(data)) {
      ctx.log("Invalid refresh response");
      return null;
    }
    ctx.log("Refresh success");
    return data;
  } catch (err) {
    ctx.log("Refresh error", err);
    return null;
  }
}
function createSylphxMiddleware(userConfig = {}) {
  let secretKey = null;
  function resolveSecretKey() {
    if (secretKey) return secretKey;
    const rawSecretKey = resolveNextjsSecretKey({
      explicitSecretKey: userConfig.secretKey,
      explicitSecretUrl: userConfig.secretUrl
    });
    if (!rawSecretKey) {
      throw new Error(
        "[Sylphx] Server connection URL is required.\nEither pass secretUrl in config or set SYLPHX_SECRET_URL env var."
      );
    }
    secretKey = validateAndSanitizeSecretKey(rawSecretKey);
    return secretKey;
  }
  let platformUrl;
  let namespace;
  let cookieNames;
  function resolveConfig() {
    const key = resolveSecretKey();
    platformUrl = resolveNextjsPlatformUrl({
      explicitPlatformUrl: userConfig.platformUrl,
      secretKey: key,
      secretUrl: userConfig.secretUrl
    });
    namespace = getCookieNamespace(key);
    cookieNames = getCookieNames(namespace);
  }
  const config = {
    publicRoutes: userConfig.publicRoutes ?? ["/"],
    ignoredRoutes: userConfig.ignoredRoutes ?? [],
    signInUrl: userConfig.signInUrl ?? "/login",
    afterSignOutUrl: userConfig.afterSignOutUrl ?? "/",
    afterSignInUrl: userConfig.afterSignInUrl ?? "/dashboard",
    authPrefix: userConfig.authPrefix ?? "/auth",
    debug: userConfig.debug ?? false,
    orgRequired: userConfig.orgRequired ?? false,
    orgSelectionUrl: userConfig.orgSelectionUrl ?? "/select-organization",
    organizationContext: {
      enabled: userConfig.organizationContext?.enabled ?? true,
      autoSelectSingleOrganization: userConfig.organizationContext?.autoSelectSingleOrganization ?? true,
      additionalOrgIdCookies: userConfig.organizationContext?.additionalOrgIdCookies ?? [],
      additionalOrgSlugCookies: userConfig.organizationContext?.additionalOrgSlugCookies ?? []
    },
    onResponse: userConfig.onResponse
  };
  const publicRoutes = [
    ...config.publicRoutes,
    config.signInUrl,
    "/signup",
    `${config.authPrefix}/*`
  ];
  const log = (msg, data) => {
    if (config.debug) {
    }
  };
  const ctx = {
    get secretKey() {
      return secretKey;
    },
    get platformUrl() {
      return platformUrl;
    },
    get namespace() {
      return namespace;
    },
    get cookieNames() {
      return cookieNames;
    },
    config,
    log
  };
  return async function middleware(request) {
    resolveConfig();
    const { pathname } = request.nextUrl;
    log(`${request.method} ${pathname}`);
    if (matchesAny(pathname, config.ignoredRoutes)) {
      log("Ignored route");
      return NextResponse.next();
    }
    if (pathname.includes(".") || pathname.startsWith("/_next")) {
      return NextResponse.next();
    }
    if (pathname === `${config.authPrefix}/callback`) {
      return handleCallback(request, ctx);
    }
    if (pathname === `${config.authPrefix}/signout`) {
      return handleSignOut(request, ctx);
    }
    if (pathname === `${config.authPrefix}/token`) {
      return handleToken(request, ctx);
    }
    if (pathname === `${config.authPrefix}/switch-org`) {
      return handleSwitchOrg(request, ctx);
    }
    const sessionToken = request.cookies.get(cookieNames.SESSION)?.value;
    const refreshToken = request.cookies.get(cookieNames.REFRESH)?.value;
    const hasValidSession = sessionToken && !isTokenExpired(sessionToken);
    const response = NextResponse.next({ request: { headers: request.headers } });
    let isAuthenticated = hasValidSession;
    let activeSessionToken = hasValidSession ? sessionToken : null;
    if (!hasValidSession && refreshToken) {
      log("Session expired, refreshing");
      const tokens = await refreshTokens(refreshToken, ctx);
      if (tokens) {
        const restored = await restoreOrganizationScopeAfterRefresh(
          request,
          ctx,
          tokens,
          sessionToken
        );
        setAuthCookiesMiddleware(response, namespace, restored.tokens);
        if (restored.activeOrganization) {
          setActiveOrganizationCookies(response, ctx, restored.activeOrganization);
        }
        isAuthenticated = true;
        activeSessionToken = restored.tokens.accessToken;
      } else {
        clearAuthCookiesMiddleware(response, namespace);
        isAuthenticated = false;
        activeSessionToken = null;
      }
    }
    const isPublic = matchesAny(pathname, publicRoutes);
    if (!isPublic && !isAuthenticated) {
      log("Redirecting to sign-in");
      const url = new URL(config.signInUrl, request.url);
      url.searchParams.set("callbackUrl", requestPathWithSearch(request));
      return NextResponse.redirect(url);
    }
    if (isAuthenticated && pathname === config.signInUrl) {
      const callbackUrl = resolveSafeRelativeRedirectPath(
        request.nextUrl.searchParams.get("callbackUrl"),
        config.afterSignInUrl
      );
      log("Redirecting from sign-in", { callbackUrl });
      return NextResponse.redirect(new URL(callbackUrl, request.url));
    }
    if (config.orgRequired && !isPublic && isAuthenticated && activeSessionToken && !matchesPattern(pathname, config.orgSelectionUrl)) {
      const payload = decodeJwtPayload(activeSessionToken);
      if (!payload?.org_id) {
        log("Redirecting to organization selection");
        const url = new URL(config.orgSelectionUrl, request.url);
        url.searchParams.set("redirect_to", requestPathWithSearch(request));
        return NextResponse.redirect(url);
      }
    }
    if (config.onResponse) {
      await config.onResponse(response, request);
    }
    return response;
  };
}
var sylphxMiddleware = createSylphxMiddleware;
function createMatcher() {
  return {
    matcher: ["/((?!_next|monitoring|.*\\..*).*)", "/"]
  };
}
function getNamespace(secretKey) {
  return getCookieNamespace(validateAndSanitizeSecretKey(secretKey));
}

// src/nextjs/server.ts
import { cache as cache2 } from "react";

// ../../node_modules/jose/dist/webapi/lib/buffer_utils.js
var encoder = new TextEncoder();
var decoder = new TextDecoder();
var MAX_INT32 = 2 ** 32;
function concat(...buffers) {
  const size = buffers.reduce((acc, { length }) => acc + length, 0);
  const buf = new Uint8Array(size);
  let i = 0;
  for (const buffer of buffers) {
    buf.set(buffer, i);
    i += buffer.length;
  }
  return buf;
}
function encode(string) {
  const bytes = new Uint8Array(string.length);
  for (let i = 0; i < string.length; i++) {
    const code = string.charCodeAt(i);
    if (code > 127) {
      throw new TypeError("non-ASCII string encountered in encode()");
    }
    bytes[i] = code;
  }
  return bytes;
}

// ../../node_modules/jose/dist/webapi/lib/base64.js
function decodeBase64(encoded) {
  if (Uint8Array.fromBase64) {
    return Uint8Array.fromBase64(encoded);
  }
  const binary = atob(encoded);
  const bytes = new Uint8Array(binary.length);
  for (let i = 0; i < binary.length; i++) {
    bytes[i] = binary.charCodeAt(i);
  }
  return bytes;
}

// ../../node_modules/jose/dist/webapi/util/base64url.js
function decode(input) {
  if (Uint8Array.fromBase64) {
    return Uint8Array.fromBase64(typeof input === "string" ? input : decoder.decode(input), {
      alphabet: "base64url"
    });
  }
  let encoded = input;
  if (encoded instanceof Uint8Array) {
    encoded = decoder.decode(encoded);
  }
  encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
  try {
    return decodeBase64(encoded);
  } catch {
    throw new TypeError("The input to be decoded is not correctly encoded.");
  }
}

// ../../node_modules/jose/dist/webapi/util/errors.js
var JOSEError = class extends Error {
  static code = "ERR_JOSE_GENERIC";
  code = "ERR_JOSE_GENERIC";
  constructor(message2, options) {
    super(message2, options);
    this.name = this.constructor.name;
    Error.captureStackTrace?.(this, this.constructor);
  }
};
var JWTClaimValidationFailed = class extends JOSEError {
  static code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
  code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
  claim;
  reason;
  payload;
  constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
    super(message2, { cause: { claim, reason, payload } });
    this.claim = claim;
    this.reason = reason;
    this.payload = payload;
  }
};
var JWTExpired = class extends JOSEError {
  static code = "ERR_JWT_EXPIRED";
  code = "ERR_JWT_EXPIRED";
  claim;
  reason;
  payload;
  constructor(message2, payload, claim = "unspecified", reason = "unspecified") {
    super(message2, { cause: { claim, reason, payload } });
    this.claim = claim;
    this.reason = reason;
    this.payload = payload;
  }
};
var JOSEAlgNotAllowed = class extends JOSEError {
  static code = "ERR_JOSE_ALG_NOT_ALLOWED";
  code = "ERR_JOSE_ALG_NOT_ALLOWED";
};
var JOSENotSupported = class extends JOSEError {
  static code = "ERR_JOSE_NOT_SUPPORTED";
  code = "ERR_JOSE_NOT_SUPPORTED";
};
var JWSInvalid = class extends JOSEError {
  static code = "ERR_JWS_INVALID";
  code = "ERR_JWS_INVALID";
};
var JWTInvalid = class extends JOSEError {
  static code = "ERR_JWT_INVALID";
  code = "ERR_JWT_INVALID";
};
var JWSSignatureVerificationFailed = class extends JOSEError {
  static code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
  code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
  constructor(message2 = "signature verification failed", options) {
    super(message2, options);
  }
};

// ../../node_modules/jose/dist/webapi/lib/crypto_key.js
var unusable = (name, prop = "algorithm.name") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
var isAlgorithm = (algorithm, name) => algorithm.name === name;
function getHashLength(hash) {
  return parseInt(hash.name.slice(4), 10);
}
function getNamedCurve(alg) {
  switch (alg) {
    case "ES256":
      return "P-256";
    case "ES384":
      return "P-384";
    case "ES512":
      return "P-521";
    default:
      throw new Error("unreachable");
  }
}
function checkUsage(key, usage) {
  if (usage && !key.usages.includes(usage)) {
    throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
  }
}
function checkSigCryptoKey(key, alg, usage) {
  switch (alg) {
    case "HS256":
    case "HS384":
    case "HS512": {
      if (!isAlgorithm(key.algorithm, "HMAC"))
        throw unusable("HMAC");
      const expected = parseInt(alg.slice(2), 10);
      const actual = getHashLength(key.algorithm.hash);
      if (actual !== expected)
        throw unusable(`SHA-${expected}`, "algorithm.hash");
      break;
    }
    case "RS256":
    case "RS384":
    case "RS512": {
      if (!isAlgorithm(key.algorithm, "RSASSA-PKCS1-v1_5"))
        throw unusable("RSASSA-PKCS1-v1_5");
      const expected = parseInt(alg.slice(2), 10);
      const actual = getHashLength(key.algorithm.hash);
      if (actual !== expected)
        throw unusable(`SHA-${expected}`, "algorithm.hash");
      break;
    }
    case "PS256":
    case "PS384":
    case "PS512": {
      if (!isAlgorithm(key.algorithm, "RSA-PSS"))
        throw unusable("RSA-PSS");
      const expected = parseInt(alg.slice(2), 10);
      const actual = getHashLength(key.algorithm.hash);
      if (actual !== expected)
        throw unusable(`SHA-${expected}`, "algorithm.hash");
      break;
    }
    case "Ed25519":
    case "EdDSA": {
      if (!isAlgorithm(key.algorithm, "Ed25519"))
        throw unusable("Ed25519");
      break;
    }
    case "ML-DSA-44":
    case "ML-DSA-65":
    case "ML-DSA-87": {
      if (!isAlgorithm(key.algorithm, alg))
        throw unusable(alg);
      break;
    }
    case "ES256":
    case "ES384":
    case "ES512": {
      if (!isAlgorithm(key.algorithm, "ECDSA"))
        throw unusable("ECDSA");
      const expected = getNamedCurve(alg);
      const actual = key.algorithm.namedCurve;
      if (actual !== expected)
        throw unusable(expected, "algorithm.namedCurve");
      break;
    }
    default:
      throw new TypeError("CryptoKey does not support this operation");
  }
  checkUsage(key, usage);
}

// ../../node_modules/jose/dist/webapi/lib/invalid_key_input.js
function message(msg, actual, ...types) {
  types = types.filter(Boolean);
  if (types.length > 2) {
    const last = types.pop();
    msg += `one of type ${types.join(", ")}, or ${last}.`;
  } else if (types.length === 2) {
    msg += `one of type ${types[0]} or ${types[1]}.`;
  } else {
    msg += `of type ${types[0]}.`;
  }
  if (actual == null) {
    msg += ` Received ${actual}`;
  } else if (typeof actual === "function" && actual.name) {
    msg += ` Received function ${actual.name}`;
  } else if (typeof actual === "object" && actual != null) {
    if (actual.constructor?.name) {
      msg += ` Received an instance of ${actual.constructor.name}`;
    }
  }
  return msg;
}
var invalidKeyInput = (actual, ...types) => message("Key must be ", actual, ...types);
var withAlg = (alg, actual, ...types) => message(`Key for the ${alg} algorithm must be `, actual, ...types);

// ../../node_modules/jose/dist/webapi/lib/is_key_like.js
var isCryptoKey = (key) => {
  if (key?.[Symbol.toStringTag] === "CryptoKey")
    return true;
  try {
    return key instanceof CryptoKey;
  } catch {
    return false;
  }
};
var isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject";
var isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);

// ../../node_modules/jose/dist/webapi/lib/is_disjoint.js
function isDisjoint(...headers) {
  const sources = headers.filter(Boolean);
  if (sources.length === 0 || sources.length === 1) {
    return true;
  }
  let acc;
  for (const header of sources) {
    const parameters = Object.keys(header);
    if (!acc || acc.size === 0) {
      acc = new Set(parameters);
      continue;
    }
    for (const parameter of parameters) {
      if (acc.has(parameter)) {
        return false;
      }
      acc.add(parameter);
    }
  }
  return true;
}

// ../../node_modules/jose/dist/webapi/lib/is_object.js
var isObjectLike = (value) => typeof value === "object" && value !== null;
function isObject(input) {
  if (!isObjectLike(input) || Object.prototype.toString.call(input) !== "[object Object]") {
    return false;
  }
  if (Object.getPrototypeOf(input) === null) {
    return true;
  }
  let proto = input;
  while (Object.getPrototypeOf(proto) !== null) {
    proto = Object.getPrototypeOf(proto);
  }
  return Object.getPrototypeOf(input) === proto;
}

// ../../node_modules/jose/dist/webapi/lib/check_key_length.js
function checkKeyLength(alg, key) {
  if (alg.startsWith("RS") || alg.startsWith("PS")) {
    const { modulusLength } = key.algorithm;
    if (typeof modulusLength !== "number" || modulusLength < 2048) {
      throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
    }
  }
}

// ../../node_modules/jose/dist/webapi/lib/jwk_to_key.js
function subtleMapping(jwk) {
  let algorithm;
  let keyUsages;
  switch (jwk.kty) {
    case "AKP": {
      switch (jwk.alg) {
        case "ML-DSA-44":
        case "ML-DSA-65":
        case "ML-DSA-87":
          algorithm = { name: jwk.alg };
          keyUsages = jwk.priv ? ["sign"] : ["verify"];
          break;
        default:
          throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
      }
      break;
    }
    case "RSA": {
      switch (jwk.alg) {
        case "PS256":
        case "PS384":
        case "PS512":
          algorithm = { name: "RSA-PSS", hash: `SHA-${jwk.alg.slice(-3)}` };
          keyUsages = jwk.d ? ["sign"] : ["verify"];
          break;
        case "RS256":
        case "RS384":
        case "RS512":
          algorithm = { name: "RSASSA-PKCS1-v1_5", hash: `SHA-${jwk.alg.slice(-3)}` };
          keyUsages = jwk.d ? ["sign"] : ["verify"];
          break;
        case "RSA-OAEP":
        case "RSA-OAEP-256":
        case "RSA-OAEP-384":
        case "RSA-OAEP-512":
          algorithm = {
            name: "RSA-OAEP",
            hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}`
          };
          keyUsages = jwk.d ? ["decrypt", "unwrapKey"] : ["encrypt", "wrapKey"];
          break;
        default:
          throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
      }
      break;
    }
    case "EC": {
      switch (jwk.alg) {
        case "ES256":
          algorithm = { name: "ECDSA", namedCurve: "P-256" };
          keyUsages = jwk.d ? ["sign"] : ["verify"];
          break;
        case "ES384":
          algorithm = { name: "ECDSA", namedCurve: "P-384" };
          keyUsages = jwk.d ? ["sign"] : ["verify"];
          break;
        case "ES512":
          algorithm = { name: "ECDSA", namedCurve: "P-521" };
          keyUsages = jwk.d ? ["sign"] : ["verify"];
          break;
        case "ECDH-ES":
        case "ECDH-ES+A128KW":
        case "ECDH-ES+A192KW":
        case "ECDH-ES+A256KW":
          algorithm = { name: "ECDH", namedCurve: jwk.crv };
          keyUsages = jwk.d ? ["deriveBits"] : [];
          break;
        default:
          throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
      }
      break;
    }
    case "OKP": {
      switch (jwk.alg) {
        case "Ed25519":
        case "EdDSA":
          algorithm = { name: "Ed25519" };
          keyUsages = jwk.d ? ["sign"] : ["verify"];
          break;
        case "ECDH-ES":
        case "ECDH-ES+A128KW":
        case "ECDH-ES+A192KW":
        case "ECDH-ES+A256KW":
          algorithm = { name: jwk.crv };
          keyUsages = jwk.d ? ["deriveBits"] : [];
          break;
        default:
          throw new JOSENotSupported('Invalid or unsupported JWK "alg" (Algorithm) Parameter value');
      }
      break;
    }
    default:
      throw new JOSENotSupported('Invalid or unsupported JWK "kty" (Key Type) Parameter value');
  }
  return { algorithm, keyUsages };
}
async function jwkToKey(jwk) {
  if (!jwk.alg) {
    throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
  }
  const { algorithm, keyUsages } = subtleMapping(jwk);
  const keyData = { ...jwk };
  if (keyData.kty !== "AKP") {
    delete keyData.alg;
  }
  delete keyData.use;
  return crypto.subtle.importKey("jwk", keyData, algorithm, jwk.ext ?? (jwk.d || jwk.priv ? false : true), jwk.key_ops ?? keyUsages);
}

// ../../node_modules/jose/dist/webapi/key/import.js
async function importJWK(jwk, alg, options) {
  if (!isObject(jwk)) {
    throw new TypeError("JWK must be an object");
  }
  let ext;
  alg ??= jwk.alg;
  ext ??= options?.extractable ?? jwk.ext;
  switch (jwk.kty) {
    case "oct":
      if (typeof jwk.k !== "string" || !jwk.k) {
        throw new TypeError('missing "k" (Key Value) Parameter value');
      }
      return decode(jwk.k);
    case "RSA":
      if ("oth" in jwk && jwk.oth !== void 0) {
        throw new JOSENotSupported('RSA JWK "oth" (Other Primes Info) Parameter value is not supported');
      }
      return jwkToKey({ ...jwk, alg, ext });
    case "AKP": {
      if (typeof jwk.alg !== "string" || !jwk.alg) {
        throw new TypeError('missing "alg" (Algorithm) Parameter value');
      }
      if (alg !== void 0 && alg !== jwk.alg) {
        throw new TypeError("JWK alg and alg option value mismatch");
      }
      return jwkToKey({ ...jwk, ext });
    }
    case "EC":
    case "OKP":
      return jwkToKey({ ...jwk, alg, ext });
    default:
      throw new JOSENotSupported('Unsupported "kty" (Key Type) Parameter value');
  }
}

// ../../node_modules/jose/dist/webapi/lib/validate_crit.js
function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
  if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0) {
    throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
  }
  if (!protectedHeader || protectedHeader.crit === void 0) {
    return /* @__PURE__ */ new Set();
  }
  if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input !== "string" || input.length === 0)) {
    throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
  }
  let recognized;
  if (recognizedOption !== void 0) {
    recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]);
  } else {
    recognized = recognizedDefault;
  }
  for (const parameter of protectedHeader.crit) {
    if (!recognized.has(parameter)) {
      throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
    }
    if (joseHeader[parameter] === void 0) {
      throw new Err(`Extension Header Parameter "${parameter}" is missing`);
    }
    if (recognized.get(parameter) && protectedHeader[parameter] === void 0) {
      throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
    }
  }
  return new Set(protectedHeader.crit);
}

// ../../node_modules/jose/dist/webapi/lib/validate_algorithms.js
function validateAlgorithms(option, algorithms) {
  if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== "string"))) {
    throw new TypeError(`"${option}" option must be an array of strings`);
  }
  if (!algorithms) {
    return void 0;
  }
  return new Set(algorithms);
}

// ../../node_modules/jose/dist/webapi/lib/is_jwk.js
var isJWK = (key) => isObject(key) && typeof key.kty === "string";
var isPrivateJWK = (key) => key.kty !== "oct" && (key.kty === "AKP" && typeof key.priv === "string" || typeof key.d === "string");
var isPublicJWK = (key) => key.kty !== "oct" && key.d === void 0 && key.priv === void 0;
var isSecretJWK = (key) => key.kty === "oct" && typeof key.k === "string";

// ../../node_modules/jose/dist/webapi/lib/normalize_key.js
var cache;
var handleJWK = async (key, jwk, alg, freeze = false) => {
  cache ||= /* @__PURE__ */ new WeakMap();
  let cached = cache.get(key);
  if (cached?.[alg]) {
    return cached[alg];
  }
  const cryptoKey = await jwkToKey({ ...jwk, alg });
  if (freeze)
    Object.freeze(key);
  if (!cached) {
    cache.set(key, { [alg]: cryptoKey });
  } else {
    cached[alg] = cryptoKey;
  }
  return cryptoKey;
};
var handleKeyObject = (keyObject, alg) => {
  cache ||= /* @__PURE__ */ new WeakMap();
  let cached = cache.get(keyObject);
  if (cached?.[alg]) {
    return cached[alg];
  }
  const isPublic = keyObject.type === "public";
  const extractable = isPublic ? true : false;
  let cryptoKey;
  if (keyObject.asymmetricKeyType === "x25519") {
    switch (alg) {
      case "ECDH-ES":
      case "ECDH-ES+A128KW":
      case "ECDH-ES+A192KW":
      case "ECDH-ES+A256KW":
        break;
      default:
        throw new TypeError("given KeyObject instance cannot be used for this algorithm");
    }
    cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, isPublic ? [] : ["deriveBits"]);
  }
  if (keyObject.asymmetricKeyType === "ed25519") {
    if (alg !== "EdDSA" && alg !== "Ed25519") {
      throw new TypeError("given KeyObject instance cannot be used for this algorithm");
    }
    cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [
      isPublic ? "verify" : "sign"
    ]);
  }
  switch (keyObject.asymmetricKeyType) {
    case "ml-dsa-44":
    case "ml-dsa-65":
    case "ml-dsa-87": {
      if (alg !== keyObject.asymmetricKeyType.toUpperCase()) {
        throw new TypeError("given KeyObject instance cannot be used for this algorithm");
      }
      cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [
        isPublic ? "verify" : "sign"
      ]);
    }
  }
  if (keyObject.asymmetricKeyType === "rsa") {
    let hash;
    switch (alg) {
      case "RSA-OAEP":
        hash = "SHA-1";
        break;
      case "RS256":
      case "PS256":
      case "RSA-OAEP-256":
        hash = "SHA-256";
        break;
      case "RS384":
      case "PS384":
      case "RSA-OAEP-384":
        hash = "SHA-384";
        break;
      case "RS512":
      case "PS512":
      case "RSA-OAEP-512":
        hash = "SHA-512";
        break;
      default:
        throw new TypeError("given KeyObject instance cannot be used for this algorithm");
    }
    if (alg.startsWith("RSA-OAEP")) {
      return keyObject.toCryptoKey({
        name: "RSA-OAEP",
        hash
      }, extractable, isPublic ? ["encrypt"] : ["decrypt"]);
    }
    cryptoKey = keyObject.toCryptoKey({
      name: alg.startsWith("PS") ? "RSA-PSS" : "RSASSA-PKCS1-v1_5",
      hash
    }, extractable, [isPublic ? "verify" : "sign"]);
  }
  if (keyObject.asymmetricKeyType === "ec") {
    const nist = /* @__PURE__ */ new Map([
      ["prime256v1", "P-256"],
      ["secp384r1", "P-384"],
      ["secp521r1", "P-521"]
    ]);
    const namedCurve = nist.get(keyObject.asymmetricKeyDetails?.namedCurve);
    if (!namedCurve) {
      throw new TypeError("given KeyObject instance cannot be used for this algorithm");
    }
    if (alg === "ES256" && namedCurve === "P-256") {
      cryptoKey = keyObject.toCryptoKey({
        name: "ECDSA",
        namedCurve
      }, extractable, [isPublic ? "verify" : "sign"]);
    }
    if (alg === "ES384" && namedCurve === "P-384") {
      cryptoKey = keyObject.toCryptoKey({
        name: "ECDSA",
        namedCurve
      }, extractable, [isPublic ? "verify" : "sign"]);
    }
    if (alg === "ES512" && namedCurve === "P-521") {
      cryptoKey = keyObject.toCryptoKey({
        name: "ECDSA",
        namedCurve
      }, extractable, [isPublic ? "verify" : "sign"]);
    }
    if (alg.startsWith("ECDH-ES")) {
      cryptoKey = keyObject.toCryptoKey({
        name: "ECDH",
        namedCurve
      }, extractable, isPublic ? [] : ["deriveBits"]);
    }
  }
  if (!cryptoKey) {
    throw new TypeError("given KeyObject instance cannot be used for this algorithm");
  }
  if (!cached) {
    cache.set(keyObject, { [alg]: cryptoKey });
  } else {
    cached[alg] = cryptoKey;
  }
  return cryptoKey;
};
async function normalizeKey(key, alg) {
  if (key instanceof Uint8Array) {
    return key;
  }
  if (isCryptoKey(key)) {
    return key;
  }
  if (isKeyObject(key)) {
    if (key.type === "secret") {
      return key.export();
    }
    if ("toCryptoKey" in key && typeof key.toCryptoKey === "function") {
      try {
        return handleKeyObject(key, alg);
      } catch (err) {
        if (err instanceof TypeError) {
          throw err;
        }
      }
    }
    let jwk = key.export({ format: "jwk" });
    return handleJWK(key, jwk, alg);
  }
  if (isJWK(key)) {
    if (key.k) {
      return decode(key.k);
    }
    return handleJWK(key, key, alg, true);
  }
  throw new Error("unreachable");
}

// ../../node_modules/jose/dist/webapi/lib/check_key_type.js
var tag = (key) => key?.[Symbol.toStringTag];
var jwkMatchesOp = (alg, key, usage) => {
  if (key.use !== void 0) {
    let expected;
    switch (usage) {
      case "sign":
      case "verify":
        expected = "sig";
        break;
      case "encrypt":
      case "decrypt":
        expected = "enc";
        break;
    }
    if (key.use !== expected) {
      throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
    }
  }
  if (key.alg !== void 0 && key.alg !== alg) {
    throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
  }
  if (Array.isArray(key.key_ops)) {
    let expectedKeyOp;
    switch (true) {
      case (usage === "sign" || usage === "verify"):
      case alg === "dir":
      case alg.includes("CBC-HS"):
        expectedKeyOp = usage;
        break;
      case alg.startsWith("PBES2"):
        expectedKeyOp = "deriveBits";
        break;
      case /^A\d{3}(?:GCM)?(?:KW)?$/.test(alg):
        if (!alg.includes("GCM") && alg.endsWith("KW")) {
          expectedKeyOp = usage === "encrypt" ? "wrapKey" : "unwrapKey";
        } else {
          expectedKeyOp = usage;
        }
        break;
      case (usage === "encrypt" && alg.startsWith("RSA")):
        expectedKeyOp = "wrapKey";
        break;
      case usage === "decrypt":
        expectedKeyOp = alg.startsWith("RSA") ? "unwrapKey" : "deriveBits";
        break;
    }
    if (expectedKeyOp && key.key_ops?.includes?.(expectedKeyOp) === false) {
      throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
    }
  }
  return true;
};
var symmetricTypeCheck = (alg, key, usage) => {
  if (key instanceof Uint8Array)
    return;
  if (isJWK(key)) {
    if (isSecretJWK(key) && jwkMatchesOp(alg, key, usage))
      return;
    throw new TypeError(`JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`);
  }
  if (!isKeyLike(key)) {
    throw new TypeError(withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key", "Uint8Array"));
  }
  if (key.type !== "secret") {
    throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
  }
};
var asymmetricTypeCheck = (alg, key, usage) => {
  if (isJWK(key)) {
    switch (usage) {
      case "decrypt":
      case "sign":
        if (isPrivateJWK(key) && jwkMatchesOp(alg, key, usage))
          return;
        throw new TypeError(`JSON Web Key for this operation must be a private JWK`);
      case "encrypt":
      case "verify":
        if (isPublicJWK(key) && jwkMatchesOp(alg, key, usage))
          return;
        throw new TypeError(`JSON Web Key for this operation must be a public JWK`);
    }
  }
  if (!isKeyLike(key)) {
    throw new TypeError(withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key"));
  }
  if (key.type === "secret") {
    throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`);
  }
  if (key.type === "public") {
    switch (usage) {
      case "sign":
        throw new TypeError(`${tag(key)} instances for asymmetric algorithm signing must be of type "private"`);
      case "decrypt":
        throw new TypeError(`${tag(key)} instances for asymmetric algorithm decryption must be of type "private"`);
    }
  }
  if (key.type === "private") {
    switch (usage) {
      case "verify":
        throw new TypeError(`${tag(key)} instances for asymmetric algorithm verifying must be of type "public"`);
      case "encrypt":
        throw new TypeError(`${tag(key)} instances for asymmetric algorithm encryption must be of type "public"`);
    }
  }
};
function checkKeyType(alg, key, usage) {
  switch (alg.substring(0, 2)) {
    case "A1":
    case "A2":
    case "di":
    case "HS":
    case "PB":
      symmetricTypeCheck(alg, key, usage);
      break;
    default:
      asymmetricTypeCheck(alg, key, usage);
  }
}

// ../../node_modules/jose/dist/webapi/lib/subtle_dsa.js
function subtleAlgorithm(alg, algorithm) {
  const hash = `SHA-${alg.slice(-3)}`;
  switch (alg) {
    case "HS256":
    case "HS384":
    case "HS512":
      return { hash, name: "HMAC" };
    case "PS256":
    case "PS384":
    case "PS512":
      return { hash, name: "RSA-PSS", saltLength: parseInt(alg.slice(-3), 10) >> 3 };
    case "RS256":
    case "RS384":
    case "RS512":
      return { hash, name: "RSASSA-PKCS1-v1_5" };
    case "ES256":
    case "ES384":
    case "ES512":
      return { hash, name: "ECDSA", namedCurve: algorithm.namedCurve };
    case "Ed25519":
    case "EdDSA":
      return { name: "Ed25519" };
    case "ML-DSA-44":
    case "ML-DSA-65":
    case "ML-DSA-87":
      return { name: alg };
    default:
      throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
  }
}

// ../../node_modules/jose/dist/webapi/lib/get_sign_verify_key.js
async function getSigKey(alg, key, usage) {
  if (key instanceof Uint8Array) {
    if (!alg.startsWith("HS")) {
      throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "JSON Web Key"));
    }
    return crypto.subtle.importKey("raw", key, { hash: `SHA-${alg.slice(-3)}`, name: "HMAC" }, false, [usage]);
  }
  checkSigCryptoKey(key, alg, usage);
  return key;
}

// ../../node_modules/jose/dist/webapi/lib/verify.js
async function verify(alg, key, signature, data) {
  const cryptoKey = await getSigKey(alg, key, "verify");
  checkKeyLength(alg, cryptoKey);
  const algorithm = subtleAlgorithm(alg, cryptoKey.algorithm);
  try {
    return await crypto.subtle.verify(algorithm, cryptoKey, signature, data);
  } catch {
    return false;
  }
}

// ../../node_modules/jose/dist/webapi/jws/flattened/verify.js
async function flattenedVerify(jws, key, options) {
  if (!isObject(jws)) {
    throw new JWSInvalid("Flattened JWS must be an object");
  }
  if (jws.protected === void 0 && jws.header === void 0) {
    throw new JWSInvalid('Flattened JWS must have either of the "protected" or "header" members');
  }
  if (jws.protected !== void 0 && typeof jws.protected !== "string") {
    throw new JWSInvalid("JWS Protected Header incorrect type");
  }
  if (jws.payload === void 0) {
    throw new JWSInvalid("JWS Payload missing");
  }
  if (typeof jws.signature !== "string") {
    throw new JWSInvalid("JWS Signature missing or incorrect type");
  }
  if (jws.header !== void 0 && !isObject(jws.header)) {
    throw new JWSInvalid("JWS Unprotected Header incorrect type");
  }
  let parsedProt = {};
  if (jws.protected) {
    try {
      const protectedHeader = decode(jws.protected);
      parsedProt = JSON.parse(decoder.decode(protectedHeader));
    } catch {
      throw new JWSInvalid("JWS Protected Header is invalid");
    }
  }
  if (!isDisjoint(parsedProt, jws.header)) {
    throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
  }
  const joseHeader = {
    ...parsedProt,
    ...jws.header
  };
  const extensions = validateCrit(JWSInvalid, /* @__PURE__ */ new Map([["b64", true]]), options?.crit, parsedProt, joseHeader);
  let b64 = true;
  if (extensions.has("b64")) {
    b64 = parsedProt.b64;
    if (typeof b64 !== "boolean") {
      throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
    }
  }
  const { alg } = joseHeader;
  if (typeof alg !== "string" || !alg) {
    throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
  }
  const algorithms = options && validateAlgorithms("algorithms", options.algorithms);
  if (algorithms && !algorithms.has(alg)) {
    throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter value not allowed');
  }
  if (b64) {
    if (typeof jws.payload !== "string") {
      throw new JWSInvalid("JWS Payload must be a string");
    }
  } else if (typeof jws.payload !== "string" && !(jws.payload instanceof Uint8Array)) {
    throw new JWSInvalid("JWS Payload must be a string or an Uint8Array instance");
  }
  let resolvedKey = false;
  if (typeof key === "function") {
    key = await key(parsedProt, jws);
    resolvedKey = true;
  }
  checkKeyType(alg, key, "verify");
  const data = concat(jws.protected !== void 0 ? encode(jws.protected) : new Uint8Array(), encode("."), typeof jws.payload === "string" ? b64 ? encode(jws.payload) : encoder.encode(jws.payload) : jws.payload);
  let signature;
  try {
    signature = decode(jws.signature);
  } catch {
    throw new JWSInvalid("Failed to base64url decode the signature");
  }
  const k = await normalizeKey(key, alg);
  const verified = await verify(alg, k, signature, data);
  if (!verified) {
    throw new JWSSignatureVerificationFailed();
  }
  let payload;
  if (b64) {
    try {
      payload = decode(jws.payload);
    } catch {
      throw new JWSInvalid("Failed to base64url decode the payload");
    }
  } else if (typeof jws.payload === "string") {
    payload = encoder.encode(jws.payload);
  } else {
    payload = jws.payload;
  }
  const result = { payload };
  if (jws.protected !== void 0) {
    result.protectedHeader = parsedProt;
  }
  if (jws.header !== void 0) {
    result.unprotectedHeader = jws.header;
  }
  if (resolvedKey) {
    return { ...result, key: k };
  }
  return result;
}

// ../../node_modules/jose/dist/webapi/jws/compact/verify.js
async function compactVerify(jws, key, options) {
  if (jws instanceof Uint8Array) {
    jws = decoder.decode(jws);
  }
  if (typeof jws !== "string") {
    throw new JWSInvalid("Compact JWS must be a string or Uint8Array");
  }
  const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split(".");
  if (length !== 3) {
    throw new JWSInvalid("Invalid Compact JWS");
  }
  const verified = await flattenedVerify({ payload, protected: protectedHeader, signature }, key, options);
  const result = { payload: verified.payload, protectedHeader: verified.protectedHeader };
  if (typeof key === "function") {
    return { ...result, key: verified.key };
  }
  return result;
}

// ../../node_modules/jose/dist/webapi/lib/jwt_claims_set.js
var epoch = (date) => Math.floor(date.getTime() / 1e3);
var minute = 60;
var hour = minute * 60;
var day = hour * 24;
var week = day * 7;
var year = day * 365.25;
var REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;
function secs(str) {
  const matched = REGEX.exec(str);
  if (!matched || matched[4] && matched[1]) {
    throw new TypeError("Invalid time period format");
  }
  const value = parseFloat(matched[2]);
  const unit = matched[3].toLowerCase();
  let numericDate;
  switch (unit) {
    case "sec":
    case "secs":
    case "second":
    case "seconds":
    case "s":
      numericDate = Math.round(value);
      break;
    case "minute":
    case "minutes":
    case "min":
    case "mins":
    case "m":
      numericDate = Math.round(value * minute);
      break;
    case "hour":
    case "hours":
    case "hr":
    case "hrs":
    case "h":
      numericDate = Math.round(value * hour);
      break;
    case "day":
    case "days":
    case "d":
      numericDate = Math.round(value * day);
      break;
    case "week":
    case "weeks":
    case "w":
      numericDate = Math.round(value * week);
      break;
    default:
      numericDate = Math.round(value * year);
      break;
  }
  if (matched[1] === "-" || matched[4] === "ago") {
    return -numericDate;
  }
  return numericDate;
}
var normalizeTyp = (value) => {
  if (value.includes("/")) {
    return value.toLowerCase();
  }
  return `application/${value.toLowerCase()}`;
};
var checkAudiencePresence = (audPayload, audOption) => {
  if (typeof audPayload === "string") {
    return audOption.includes(audPayload);
  }
  if (Array.isArray(audPayload)) {
    return audOption.some(Set.prototype.has.bind(new Set(audPayload)));
  }
  return false;
};
function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {
  let payload;
  try {
    payload = JSON.parse(decoder.decode(encodedPayload));
  } catch {
  }
  if (!isObject(payload)) {
    throw new JWTInvalid("JWT Claims Set must be a top-level JSON object");
  }
  const { typ } = options;
  if (typ && (typeof protectedHeader.typ !== "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) {
    throw new JWTClaimValidationFailed('unexpected "typ" JWT header value', payload, "typ", "check_failed");
  }
  const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options;
  const presenceCheck = [...requiredClaims];
  if (maxTokenAge !== void 0)
    presenceCheck.push("iat");
  if (audience !== void 0)
    presenceCheck.push("aud");
  if (subject !== void 0)
    presenceCheck.push("sub");
  if (issuer !== void 0)
    presenceCheck.push("iss");
  for (const claim of new Set(presenceCheck.reverse())) {
    if (!(claim in payload)) {
      throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, "missing");
    }
  }
  if (issuer && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss)) {
    throw new JWTClaimValidationFailed('unexpected "iss" claim value', payload, "iss", "check_failed");
  }
  if (subject && payload.sub !== subject) {
    throw new JWTClaimValidationFailed('unexpected "sub" claim value', payload, "sub", "check_failed");
  }
  if (audience && !checkAudiencePresence(payload.aud, typeof audience === "string" ? [audience] : audience)) {
    throw new JWTClaimValidationFailed('unexpected "aud" claim value', payload, "aud", "check_failed");
  }
  let tolerance;
  switch (typeof options.clockTolerance) {
    case "string":
      tolerance = secs(options.clockTolerance);
      break;
    case "number":
      tolerance = options.clockTolerance;
      break;
    case "undefined":
      tolerance = 0;
      break;
    default:
      throw new TypeError("Invalid clockTolerance option type");
  }
  const { currentDate } = options;
  const now = epoch(currentDate || /* @__PURE__ */ new Date());
  if ((payload.iat !== void 0 || maxTokenAge) && typeof payload.iat !== "number") {
    throw new JWTClaimValidationFailed('"iat" claim must be a number', payload, "iat", "invalid");
  }
  if (payload.nbf !== void 0) {
    if (typeof payload.nbf !== "number") {
      throw new JWTClaimValidationFailed('"nbf" claim must be a number', payload, "nbf", "invalid");
    }
    if (payload.nbf > now + tolerance) {
      throw new JWTClaimValidationFailed('"nbf" claim timestamp check failed', payload, "nbf", "check_failed");
    }
  }
  if (payload.exp !== void 0) {
    if (typeof payload.exp !== "number") {
      throw new JWTClaimValidationFailed('"exp" claim must be a number', payload, "exp", "invalid");
    }
    if (payload.exp <= now - tolerance) {
      throw new JWTExpired('"exp" claim timestamp check failed', payload, "exp", "check_failed");
    }
  }
  if (maxTokenAge) {
    const age = now - payload.iat;
    const max = typeof maxTokenAge === "number" ? maxTokenAge : secs(maxTokenAge);
    if (age - tolerance > max) {
      throw new JWTExpired('"iat" claim timestamp check failed (too far in the past)', payload, "iat", "check_failed");
    }
    if (age < 0 - tolerance) {
      throw new JWTClaimValidationFailed('"iat" claim timestamp check failed (it should be in the past)', payload, "iat", "check_failed");
    }
  }
  return payload;
}

// ../../node_modules/jose/dist/webapi/jwt/verify.js
async function jwtVerify(jwt, key, options) {
  const verified = await compactVerify(jwt, key, options);
  if (verified.protectedHeader.crit?.includes("b64") && verified.protectedHeader.b64 === false) {
    throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
  }
  const payload = validateClaimsSet(verified.protectedHeader, verified.payload, options);
  const result = { payload, protectedHeader: verified.protectedHeader };
  if (typeof key === "function") {
    return { ...result, key: verified.key };
  }
  return result;
}

// src/lib/ids.ts
var CB32 = "0123456789abcdefghjkmnpqrstvwxyz";
var CB32_MAP = Object.fromEntries([...CB32].map((c, i) => [c, i]));
var B58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
var B58_MAP = Object.fromEntries([...B58].map((c, i) => [c, i]));
function cb32Encode(hex) {
  const num = BigInt(`0x${hex}`);
  const chars = [];
  let n = num;
  for (let i = 0; i < 26; i++) {
    chars.unshift(CB32[Number(n & 0x1fn)]);
    n >>= 5n;
  }
  return chars.join("");
}
function cb32Decode(str) {
  if (str.length !== 26) return null;
  let n = 0n;
  for (const c of str.toLowerCase()) {
    const idx = CB32_MAP[c];
    if (idx === void 0) return null;
    n = n << 5n | BigInt(idx);
  }
  return n.toString(16).padStart(32, "0");
}
function b58Decode(str) {
  let n = 0n;
  for (const c of str) {
    const i = B58_MAP[c] ?? -1;
    if (i === -1) return null;
    n = n * 58n + BigInt(i);
  }
  const hex = n.toString(16).padStart(32, "0");
  return hex.length === 32 ? hex : null;
}
function hexToUuid(hex) {
  return [
    hex.slice(0, 8),
    hex.slice(8, 12),
    hex.slice(12, 16),
    hex.slice(16, 20),
    hex.slice(20)
  ].join("-");
}
function encodeUserId(uuid) {
  const hex = uuid.replace(/-/g, "");
  if (hex.length !== 32)
    throw new Error("Invalid UUID: expected 32 hex chars after stripping dashes");
  return `user_${cb32Encode(hex)}`;
}
function decodeUserId(prefixedId) {
  if (!prefixedId.startsWith("user_")) return null;
  const enc = prefixedId.slice(5);
  if (!enc) return null;
  if (enc.length === 26) {
    const hex2 = cb32Decode(enc);
    if (hex2) return hexToUuid(hex2);
  }
  const hex = b58Decode(enc);
  if (hex) return hexToUuid(hex);
  return null;
}

// src/server/index.ts
function isJwksResponse(data) {
  return typeof data === "object" && data !== null && "keys" in data && Array.isArray(data.keys);
}
function isAccessTokenPayload(payload) {
  return typeof payload.sub === "string" && typeof payload.email === "string" && typeof payload.app_id === "string" && typeof payload.iat === "number" && typeof payload.exp === "number";
}
var jwksCache = null;
async function getJwks(platformUrl = `https://${DEFAULT_SDK_API_HOST}`) {
  const now = Date.now();
  if (jwksCache && jwksCache.expiresAt > now) {
    return jwksCache.keys;
  }
  const response = await fetch(`${platformUrl}/api/v1/auth/.well-known/jwks.json`);
  if (!response.ok) {
    throw new Error("Failed to fetch JWKS");
  }
  const data = await response.json();
  if (!isJwksResponse(data)) {
    throw new Error("Invalid JWKS response format");
  }
  jwksCache = {
    keys: data.keys,
    expiresAt: now + JWK_CACHE_TTL_MS
    // Cache for 1 hour
  };
  return data.keys;
}
async function verifyAccessToken(token, options) {
  const platformUrl = options.platformUrl || `https://${DEFAULT_SDK_API_HOST}`;
  const keys = await getJwks(platformUrl);
  if (!keys.length) {
    throw new Error("No keys in JWKS");
  }
  let lastError = null;
  for (const key of keys) {
    try {
      const jwk = await importJWK(key, "RS256");
      const { payload } = await jwtVerify(token, jwk, {
        issuer: platformUrl
      });
      if (!isAccessTokenPayload(payload)) {
        throw new Error("Invalid token payload structure");
      }
      return {
        sub: payload.sub,
        pid: payload.pid,
        email: payload.email,
        name: payload.name,
        picture: payload.picture,
        email_verified: payload.email_verified,
        app_id: payload.app_id,
        role: payload.role,
        iat: payload.iat,
        exp: payload.exp
      };
    } catch (err) {
      lastError = err;
    }
  }
  throw lastError || new Error("Token verification failed");
}

// src/nextjs/server.ts
function isTokenResponse2(data) {
  return typeof data === "object" && data !== null && "accessToken" in data && "refreshToken" in data && "user" in data && typeof data.accessToken === "string" && typeof data.refreshToken === "string";
}
var serverConfig = null;
function configureServer(config) {
  const rawSecretKey = resolveNextjsSecretKey({
    explicitSecretKey: config.secretKey,
    explicitSecretUrl: config.secretUrl
  });
  if (!rawSecretKey) {
    throw new Error(
      "[Sylphx] Server credential is required. Set SYLPHX_SECRET_URL or pass secretUrl/secretKey to configureServer()."
    );
  }
  const secretKey = validateAndSanitizeSecretKey(rawSecretKey);
  serverConfig = {
    secretKey,
    platformUrl: resolveNextjsPlatformUrl({
      explicitPlatformUrl: config.platformUrl,
      secretKey,
      secretUrl: config.secretUrl
    })
  };
}
function getConfig() {
  if (serverConfig) {
    return serverConfig;
  }
  const rawSecretKey = resolveNextjsSecretKey({});
  if (!rawSecretKey) {
    return null;
  }
  try {
    const secretKey = validateAndSanitizeSecretKey(rawSecretKey);
    const platformUrl = resolveNextjsPlatformUrl({ secretKey });
    serverConfig = { secretKey, platformUrl };
    return serverConfig;
  } catch (error) {
    console.warn("[Sylphx] Invalid @sylphx/sdk/nextjs server configuration:", error);
    return null;
  }
}
function getCookieNamespace2() {
  const config = getConfig();
  if (!config) return "sylphx";
  return getCookieNamespace(config.secretKey);
}
var auth = cache2(async () => {
  const config = getConfig();
  if (!config) {
    return { userId: null, user: null, sessionToken: null };
  }
  const namespace = getCookieNamespace2();
  const { sessionToken, refreshToken, user, expiresAt } = await getAuthCookies(namespace);
  if (!sessionToken && !refreshToken) {
    return { userId: null, user: null, sessionToken: null };
  }
  if (sessionToken && expiresAt && expiresAt > Date.now() + TOKEN_EXPIRY_BUFFER_MS) {
    try {
      const payload = await verifyAccessToken(sessionToken, config);
      const resolvedUserId = payload.pid ?? payload.sub;
      return {
        userId: resolvedUserId,
        user: user || {
          id: resolvedUserId,
          email: payload.email,
          name: payload.name || null,
          image: payload.picture || null,
          emailVerified: payload.email_verified
        },
        sessionToken
      };
    } catch {
    }
  }
  if (refreshToken && user && expiresAt) {
    if (expiresAt > Date.now()) {
      return {
        userId: user.id,
        user,
        sessionToken: sessionToken || null
        // May be expired, but user data is valid
      };
    }
  }
  return { userId: null, user: null, sessionToken: null };
});
async function currentUser() {
  const { user } = await auth();
  return user;
}
async function currentUserId() {
  const { userId } = await auth();
  return userId;
}
async function handleCallback2(code) {
  const config = getConfig();
  if (!config) {
    throw new Error("Sylphx SDK not configured. Set SYLPHX_SECRET_URL environment variable.");
  }
  const response = await fetch(`${config.platformUrl}/v1/auth/token`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      grant_type: "authorization_code",
      code,
      client_secret: config.secretKey
    })
  });
  if (!response.ok) {
    const errorData = await response.json().catch(() => ({ error: "Token exchange failed" }));
    throw new Error(errorData.error || "Token exchange failed");
  }
  const data = await response.json();
  if (!isTokenResponse2(data)) {
    throw new Error("Invalid token response format");
  }
  const namespace = getCookieNamespace2();
  await setAuthCookies(namespace, data);
  return data.user;
}
async function signOut() {
  const config = getConfig();
  if (!config) {
    return;
  }
  const namespace = getCookieNamespace2();
  const { refreshToken } = await getAuthCookies(namespace);
  if (refreshToken) {
    try {
      await fetch(`${config.platformUrl}/v1/auth/revoke`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          token: refreshToken,
          client_secret: config.secretKey
        })
      });
    } catch {
    }
  }
  await clearAuthCookies(namespace);
}
async function syncAuthToCookies(tokens) {
  "use server";
  const namespace = getCookieNamespace2();
  await setAuthCookies(namespace, tokens);
}
function getAuthorizationUrl(options) {
  const config = getConfig();
  if (!config) {
    throw new Error("Sylphx SDK not configured. Set SYLPHX_SECRET_URL environment variable.");
  }
  const rawClientId = options?.appId || process.env.NEXT_PUBLIC_SYLPHX_APP_ID;
  if (!rawClientId) {
    throw new Error("App ID is required for authorization URL. Set NEXT_PUBLIC_SYLPHX_APP_ID.");
  }
  const clientId = validateAndSanitizeAppId(rawClientId);
  const params = new URLSearchParams({
    client_id: clientId,
    redirect_uri: options?.redirectUri || "/",
    response_type: "code"
  });
  if (options?.mode === "signup") {
    params.set("mode", "signup");
  }
  if (options?.state) {
    params.set("state", options.state);
  }
  return `${config.platformUrl}/auth/authorize?${params}`;
}
async function getSessionToken() {
  const { sessionToken } = await auth();
  return sessionToken;
}
export {
  ACTIVE_ORG_COOKIE_OPTIONS,
  ACTIVE_ORG_LIFETIME,
  REFRESH_TOKEN_LIFETIME,
  SECURE_COOKIE_OPTIONS,
  SESSION_TOKEN_LIFETIME,
  SESSION_TOKEN_LIFETIME_MS,
  TOKEN_EXPIRY_BUFFER_MS,
  USER_COOKIE_OPTIONS,
  auth,
  clearAuthCookies,
  clearAuthCookiesMiddleware,
  configureServer,
  createMatcher,
  createSylphxMiddleware,
  currentUser,
  currentUserId,
  decodeUserId,
  encodeUserId,
  getAuthCookies,
  getAuthorizationUrl,
  getCookieNames,
  getNamespace,
  getSessionToken,
  handleCallback2 as handleCallback,
  hasRefreshToken,
  isSessionExpired,
  parseUserCookie,
  setAuthCookies,
  setAuthCookiesMiddleware,
  signOut,
  sylphxMiddleware,
  syncAuthToCookies
};
//# sourceMappingURL=index.mjs.map