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

// src/server/entities/schema.ts
import { createFunctionSchema } from "@spfn/core/db";
var authSchema;
var init_schema = __esm({
  "src/server/entities/schema.ts"() {
    "use strict";
    authSchema = createFunctionSchema("@spfn/auth");
  }
});

// src/server/entities/roles.ts
import { text, boolean, integer, index } from "drizzle-orm/pg-core";
import { id, timestamps } from "@spfn/core/db";
var roles;
var init_roles = __esm({
  "src/server/entities/roles.ts"() {
    "use strict";
    init_schema();
    roles = authSchema.table(
      "roles",
      {
        // Primary key
        id: id(),
        // Role identifier (used in code, e.g., 'admin', 'editor')
        // Must be unique, lowercase, kebab-case recommended
        name: text("name").notNull().unique(),
        // Display name for UI (e.g., 'Administrator', 'Content Editor')
        displayName: text("display_name").notNull(),
        // Role description
        description: text("description"),
        // Built-in role flag
        // true: Core package roles (user, admin, superadmin) - cannot be deleted
        // false: Custom or preset roles - can be deleted
        isBuiltin: boolean("is_builtin").notNull().default(false),
        // System role flag
        // true: Defined in code (builtin or preset) - deletion restricted
        // false: Runtime created custom role - fully manageable
        isSystem: boolean("is_system").notNull().default(false),
        // Active status
        // false: Deactivated role (users cannot be assigned)
        isActive: boolean("is_active").notNull().default(true),
        // Priority level (higher = more privileged)
        // superadmin: 100, admin: 80, user: 10
        // Used for role hierarchy and conflict resolution
        priority: integer("priority").notNull().default(10),
        ...timestamps()
      },
      (table) => [
        index("roles_name_idx").on(table.name),
        index("roles_is_system_idx").on(table.isSystem),
        index("roles_is_active_idx").on(table.isActive),
        index("roles_is_builtin_idx").on(table.isBuiltin),
        index("roles_priority_idx").on(table.priority)
      ]
    );
  }
});

// src/server/entities/users.ts
import { text as text2, timestamp, check, boolean as boolean2, bigint, index as index2 } from "drizzle-orm/pg-core";
import { id as id2, timestamps as timestamps2 } from "@spfn/core/db";
import { sql } from "drizzle-orm";
var users;
var init_users = __esm({
  "src/server/entities/users.ts"() {
    "use strict";
    init_roles();
    init_schema();
    users = authSchema.table(
      "users",
      {
        // Identity
        id: id2(),
        // Email address (unique identifier)
        // Used for: login, password reset, notifications
        email: text2("email").unique(),
        // Phone number in E.164 international format
        // Format: +[country code][number] (e.g., +821012345678)
        // Used for: SMS login, 2FA, notifications
        phone: text2("phone").unique(),
        // Authentication
        // Bcrypt password hash ($2b$10$[salt][hash], 60 chars)
        // Nullable to support OAuth-only accounts
        passwordHash: text2("password_hash"),
        // Force password change on next login
        // Use cases: initial setup, security breach, policy violation
        passwordChangeRequired: boolean2("password_change_required").notNull().default(false),
        // Authorization (Role-Based Access Control)
        // Foreign key to roles table
        // References built-in roles: user (default), admin, superadmin
        // Can also reference custom roles created at runtime
        roleId: bigint("role_id", { mode: "number" }).references(() => roles.id).notNull(),
        // Account status
        // - active: Normal operation (default)
        // - inactive: Deactivated (user request, dormant)
        // - suspended: Locked (security incident, ToS violation)
        status: text2(
          "status",
          {
            enum: ["active", "inactive", "suspended"]
          }
        ).notNull().default("active"),
        // Verification timestamps
        // null = unverified, timestamp = verified at this time
        // Email verification (via verification code or magic link)
        emailVerifiedAt: timestamp("email_verified_at", { withTimezone: true }),
        // Phone verification (via SMS OTP)
        phoneVerifiedAt: timestamp("phone_verified_at", { withTimezone: true }),
        // Metadata
        // Last successful login timestamp
        // Used for: security auditing, dormant account detection
        lastLoginAt: timestamp("last_login_at", { withTimezone: true }),
        ...timestamps2()
      },
      (table) => [
        // Database constraints
        // Ensure at least one identifier exists (email OR phone)
        check(
          "email_or_phone_check",
          sql`${table.email} IS NOT NULL OR ${table.phone} IS NOT NULL`
        ),
        // Indexes for query optimization
        index2("users_email_idx").on(table.email),
        index2("users_phone_idx").on(table.phone),
        index2("users_status_idx").on(table.status),
        index2("users_role_id_idx").on(table.roleId)
      ]
    );
  }
});

// src/server/entities/user-social-accounts.ts
import { text as text3, timestamp as timestamp2, uniqueIndex } from "drizzle-orm/pg-core";
import { id as id3, timestamps as timestamps3, foreignKey } from "@spfn/core/db";
var userSocialAccounts;
var init_user_social_accounts = __esm({
  "src/server/entities/user-social-accounts.ts"() {
    "use strict";
    init_users();
    init_schema();
    userSocialAccounts = authSchema.table(
      "user_social_accounts",
      {
        id: id3(),
        // Foreign key to users
        userId: foreignKey("user", () => users.id),
        // Provider info
        provider: text3(
          "provider",
          {
            enum: ["google", "github", "kakao", "naver"]
          }
        ).notNull(),
        providerUserId: text3("provider_user_id").notNull(),
        providerEmail: text3("provider_email"),
        // OAuth tokens (encrypted in production)
        accessToken: text3("access_token"),
        refreshToken: text3("refresh_token"),
        tokenExpiresAt: timestamp2("token_expires_at", { withTimezone: true }),
        ...timestamps3()
      },
      (table) => [
        // Unique constraint: one provider account per provider
        uniqueIndex("provider_user_unique_idx").on(table.provider, table.providerUserId)
      ]
    );
  }
});

// src/server/entities/user-public-keys.ts
import { text as text4, timestamp as timestamp3, boolean as boolean3, index as index3 } from "drizzle-orm/pg-core";
import { id as id4, foreignKey as foreignKey2 } from "@spfn/core/db";
var userPublicKeys;
var init_user_public_keys = __esm({
  "src/server/entities/user-public-keys.ts"() {
    "use strict";
    init_users();
    init_schema();
    userPublicKeys = authSchema.table(
      "user_public_keys",
      {
        id: id4(),
        // User reference
        userId: foreignKey2("user", () => users.id),
        // Key identification (client-generated UUID)
        keyId: text4("key_id").notNull().unique(),
        // Public key in Base64-encoded DER format (SPKI)
        publicKey: text4("public_key").notNull(),
        // Algorithm used (ES256 recommended, RS256 fallback)
        algorithm: text4("algorithm", {
          enum: ["ES256", "RS256"]
        }).notNull().default("ES256"),
        // Key fingerprint (SHA-256 hash for quick identification)
        fingerprint: text4("fingerprint").notNull(),
        // Key status
        isActive: boolean3("is_active").notNull().default(true),
        // Timestamps
        createdAt: timestamp3("created_at", { mode: "date", withTimezone: true }).notNull().defaultNow(),
        lastUsedAt: timestamp3("last_used_at", { mode: "date", withTimezone: true }),
        expiresAt: timestamp3("expires_at", { mode: "date", withTimezone: true }),
        // Revocation
        revokedAt: timestamp3("revoked_at", { mode: "date", withTimezone: true }),
        revokedReason: text4("revoked_reason")
      },
      (table) => [
        index3("user_public_keys_user_id_idx").on(table.userId),
        index3("user_public_keys_key_id_idx").on(table.keyId),
        index3("user_public_keys_active_idx").on(table.isActive),
        index3("user_public_keys_fingerprint_idx").on(table.fingerprint)
      ]
    );
  }
});

// src/server/entities/verification-codes.ts
import { text as text5, timestamp as timestamp4, index as index4 } from "drizzle-orm/pg-core";
import { id as id5, timestamps as timestamps4 } from "@spfn/core/db";
var verificationCodes;
var init_verification_codes = __esm({
  "src/server/entities/verification-codes.ts"() {
    "use strict";
    init_schema();
    verificationCodes = authSchema.table(
      "verification_codes",
      {
        id: id5(),
        // Target (email or phone)
        target: text5("target").notNull(),
        // Email address or E.164 phone number
        targetType: text5(
          "target_type",
          {
            enum: ["email", "phone"]
          }
        ).notNull(),
        // Code
        code: text5("code").notNull(),
        // 6-digit code by default (configurable)
        // Purpose
        purpose: text5(
          "purpose",
          {
            enum: ["registration", "login", "password_reset", "email_change", "phone_change"]
          }
        ).notNull(),
        // Expiry
        expiresAt: timestamp4("expires_at", { withTimezone: true }).notNull(),
        // Usage tracking
        usedAt: timestamp4("used_at", { withTimezone: true }),
        attempts: text5("attempts").notNull().default("0"),
        // Track failed verification attempts
        ...timestamps4()
      },
      (table) => [
        // Index for quick lookup by target and purpose
        index4("target_purpose_idx").on(table.target, table.purpose, table.expiresAt)
      ]
    );
  }
});

// src/server/entities/invitations.ts
import { text as text6, timestamp as timestamp5, bigint as bigint2, index as index5, jsonb } from "drizzle-orm/pg-core";
import { id as id6, timestamps as timestamps5 } from "@spfn/core/db";
var invitations;
var init_invitations = __esm({
  "src/server/entities/invitations.ts"() {
    "use strict";
    init_roles();
    init_users();
    init_schema();
    invitations = authSchema.table(
      "user_invitations",
      {
        // Primary key
        id: id6(),
        // Target email address for the invitation
        // Will become the user's email upon acceptance
        email: text6("email").notNull(),
        // Unique invitation token (UUID v4)
        // Used in invitation URL: /auth/invite/{token}
        // Single-use token that expires after acceptance
        token: text6("token").notNull().unique(),
        // Role to be assigned when invitation is accepted
        // Foreign key to roles table
        roleId: bigint2("role_id", { mode: "number" }).references(() => roles.id).notNull(),
        // User who created this invitation
        // Foreign key to users table
        // Used for: audit trail, permission checks
        invitedBy: bigint2("invited_by", { mode: "number" }).references(() => users.id).notNull(),
        // Invitation status
        // - pending: Invitation sent, awaiting acceptance
        // - accepted: User accepted and account created
        // - expired: Invitation expired (automatic)
        // - cancelled: Invitation cancelled by admin
        status: text6(
          "status",
          {
            enum: ["pending", "accepted", "expired", "cancelled"]
          }
        ).notNull().default("pending"),
        // Expiration timestamp (default: 7 days from creation)
        // Invitation cannot be accepted after this time
        // Background job should update status to 'expired'
        expiresAt: timestamp5("expires_at", { withTimezone: true }).notNull(),
        // Timestamp when invitation was accepted
        // null = not yet accepted
        // Used for: audit trail, analytics
        acceptedAt: timestamp5("accepted_at", { withTimezone: true }),
        // Timestamp when invitation was cancelled
        // null = not cancelled
        // Used for: audit trail
        cancelledAt: timestamp5("cancelled_at", { withTimezone: true }),
        // Additional metadata (JSONB)
        // Use cases:
        // - Custom welcome message
        // - Onboarding instructions
        // - Team/department assignment
        // - Custom fields for app-specific data
        // Example: { message: "Welcome!", department: "Engineering" }
        metadata: jsonb("metadata"),
        ...timestamps5()
      },
      (table) => [
        // Indexes for query optimization
        index5("invitations_token_idx").on(table.token),
        index5("invitations_email_idx").on(table.email),
        index5("invitations_status_idx").on(table.status),
        index5("invitations_invited_by_idx").on(table.invitedBy),
        index5("invitations_expires_at_idx").on(table.expiresAt),
        // For cleanup jobs
        index5("invitations_role_id_idx").on(table.roleId)
      ]
    );
  }
});

// src/server/entities/permissions.ts
import { text as text7, boolean as boolean4, index as index6 } from "drizzle-orm/pg-core";
import { id as id7, timestamps as timestamps6 } from "@spfn/core/db";
var permissions;
var init_permissions = __esm({
  "src/server/entities/permissions.ts"() {
    "use strict";
    init_schema();
    permissions = authSchema.table(
      "permissions",
      {
        // Primary key
        id: id7(),
        // Permission identifier (e.g., 'user:delete', 'post:publish')
        // Format: resource:action or namespace:resource:action
        // Must be unique
        name: text7("name").notNull().unique(),
        // Display name for UI
        displayName: text7("display_name").notNull(),
        // Permission description
        description: text7("description"),
        // Category for grouping (e.g., 'user', 'post', 'admin', 'system')
        category: text7("category"),
        // Built-in permission flag
        // true: Core package permissions - cannot be deleted
        // false: Custom or preset permissions
        isBuiltin: boolean4("is_builtin").notNull().default(false),
        // System permission flag
        // true: Defined in code (builtin or preset)
        // false: Runtime created custom permission
        isSystem: boolean4("is_system").notNull().default(false),
        // Active status
        // false: Deactivated permission (not enforced)
        isActive: boolean4("is_active").notNull().default(true),
        ...timestamps6()
      },
      (table) => [
        index6("permissions_name_idx").on(table.name),
        index6("permissions_category_idx").on(table.category),
        index6("permissions_is_system_idx").on(table.isSystem),
        index6("permissions_is_active_idx").on(table.isActive),
        index6("permissions_is_builtin_idx").on(table.isBuiltin)
      ]
    );
  }
});

// src/server/entities/role-permissions.ts
import { bigint as bigint3, index as index7, unique } from "drizzle-orm/pg-core";
import { id as id8, timestamps as timestamps7 } from "@spfn/core/db";
var rolePermissions;
var init_role_permissions = __esm({
  "src/server/entities/role-permissions.ts"() {
    "use strict";
    init_roles();
    init_permissions();
    init_schema();
    rolePermissions = authSchema.table(
      "role_permissions",
      {
        // Primary key
        id: id8(),
        // Foreign key to roles table
        roleId: bigint3("role_id", { mode: "number" }).notNull().references(() => roles.id, { onDelete: "cascade" }),
        // Foreign key to permissions table
        permissionId: bigint3("permission_id", { mode: "number" }).notNull().references(() => permissions.id, { onDelete: "cascade" }),
        ...timestamps7()
      },
      (table) => [
        // Indexes for query performance
        index7("role_permissions_role_id_idx").on(table.roleId),
        index7("role_permissions_permission_id_idx").on(table.permissionId),
        // Unique constraint: one role-permission pair only
        unique("role_permissions_unique").on(table.roleId, table.permissionId)
      ]
    );
  }
});

// src/server/entities/user-permissions.ts
import { bigint as bigint4, boolean as boolean5, text as text8, timestamp as timestamp6, index as index8, unique as unique2 } from "drizzle-orm/pg-core";
import { id as id9, timestamps as timestamps8 } from "@spfn/core/db";
var userPermissions;
var init_user_permissions = __esm({
  "src/server/entities/user-permissions.ts"() {
    "use strict";
    init_users();
    init_permissions();
    init_schema();
    userPermissions = authSchema.table(
      "user_permissions",
      {
        // Primary key
        id: id9(),
        // Foreign key to users table
        userId: bigint4("user_id", { mode: "number" }).notNull().references(() => users.id, { onDelete: "cascade" }),
        // Foreign key to permissions table
        permissionId: bigint4("permission_id", { mode: "number" }).notNull().references(() => permissions.id, { onDelete: "cascade" }),
        // Grant or revoke
        // true: Grant this permission (even if role doesn't have it)
        // false: Revoke this permission (even if role has it)
        granted: boolean5("granted").notNull().default(true),
        // Reason for grant/revocation (audit trail)
        reason: text8("reason"),
        // Expiration timestamp (optional)
        // null: Permanent override
        // timestamp: Permission expires at this time
        expiresAt: timestamp6("expires_at", { withTimezone: true }),
        ...timestamps8()
      },
      (table) => [
        // Indexes for query performance
        index8("user_permissions_user_id_idx").on(table.userId),
        index8("user_permissions_permission_id_idx").on(table.permissionId),
        index8("user_permissions_expires_at_idx").on(table.expiresAt),
        // Unique constraint: one user-permission pair only
        unique2("user_permissions_unique").on(table.userId, table.permissionId)
      ]
    );
  }
});

// src/server/entities/index.ts
var entities_exports = {};
__export(entities_exports, {
  authSchema: () => authSchema,
  invitations: () => invitations,
  permissions: () => permissions,
  rolePermissions: () => rolePermissions,
  roles: () => roles,
  userPermissions: () => userPermissions,
  userPublicKeys: () => userPublicKeys,
  userSocialAccounts: () => userSocialAccounts,
  users: () => users,
  verificationCodes: () => verificationCodes
});
var init_entities = __esm({
  "src/server/entities/index.ts"() {
    "use strict";
    init_schema();
    init_users();
    init_user_social_accounts();
    init_user_public_keys();
    init_verification_codes();
    init_invitations();
    init_roles();
    init_permissions();
    init_role_permissions();
    init_user_permissions();
  }
});

// src/server/helpers/jwt.ts
var jwt_exports = {};
__export(jwt_exports, {
  decodeToken: () => decodeToken,
  generateToken: () => generateToken,
  verifyClientToken: () => verifyClientToken,
  verifyKeyFingerprint: () => verifyKeyFingerprint,
  verifyToken: () => verifyToken
});
import jwt from "jsonwebtoken";
import crypto from "crypto";
function generateToken(payload) {
  return jwt.sign(payload, JWT_SECRET, {
    expiresIn: JWT_EXPIRES_IN
  });
}
function verifyToken(token) {
  return jwt.verify(token, JWT_SECRET);
}
function verifyClientToken(token, publicKeyB64, algorithm) {
  try {
    const publicKeyDER = Buffer.from(publicKeyB64, "base64");
    const publicKeyObject = crypto.createPublicKey({
      key: publicKeyDER,
      format: "der",
      type: "spki"
    });
    const decoded = jwt.verify(token, publicKeyObject, {
      algorithms: [algorithm],
      // Prevent algorithm confusion attacks
      issuer: "spfn-client"
      // Validate token issuer
    });
    if (typeof decoded === "string") {
      throw new Error("Invalid token format: expected object payload");
    }
    return decoded;
  } catch (error) {
    if (error instanceof jwt.TokenExpiredError) {
      throw new Error("Token has expired");
    }
    if (error instanceof jwt.JsonWebTokenError) {
      throw new Error("Invalid token signature");
    }
    throw new Error(`Token verification failed: ${error instanceof Error ? error.message : "Unknown error"}`);
  }
}
function decodeToken(token) {
  try {
    return jwt.decode(token);
  } catch {
    return null;
  }
}
function verifyKeyFingerprint(publicKeyB64, expectedFingerprint) {
  try {
    const publicKeyDER = Buffer.from(publicKeyB64, "base64");
    const fingerprint = crypto.createHash("sha256").update(publicKeyDER).digest("hex");
    return fingerprint === expectedFingerprint;
  } catch (error) {
    console.error("Failed to verify key fingerprint:", error);
    return false;
  }
}
var JWT_SECRET, JWT_EXPIRES_IN;
var init_jwt = __esm({
  "src/server/helpers/jwt.ts"() {
    "use strict";
    JWT_SECRET = process.env.SPFN_AUTH_JWT_SECRET || // New prefixed version (recommended)
    process.env.JWT_SECRET || // Legacy fallback
    "dev-secret-key-change-in-production";
    JWT_EXPIRES_IN = process.env.SPFN_AUTH_JWT_EXPIRES_IN || // New prefixed version (recommended)
    process.env.JWT_EXPIRES_IN || // Legacy fallback
    "7d";
  }
});

// src/server/services/role.service.ts
var role_service_exports = {};
__export(role_service_exports, {
  addPermissionToRole: () => addPermissionToRole,
  createRole: () => createRole,
  deleteRole: () => deleteRole,
  getAllRoles: () => getAllRoles,
  getRoleByName: () => getRoleByName,
  getRolePermissions: () => getRolePermissions,
  removePermissionFromRole: () => removePermissionFromRole,
  setRolePermissions: () => setRolePermissions,
  updateRole: () => updateRole
});
import { getDatabase as getDatabase3 } from "@spfn/core/db";
import { eq as eq3, and as and3 } from "drizzle-orm";
async function createRole(data) {
  const db = getDatabase3();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const existing = await db.select().from(roles).where(eq3(roles.name, data.name)).limit(1);
  if (existing.length > 0) {
    throw new Error(`Role with name '${data.name}' already exists`);
  }
  const [newRole] = await db.insert(roles).values({
    name: data.name,
    displayName: data.displayName,
    description: data.description,
    priority: data.priority ?? 10,
    isSystem: false,
    // Custom roles are never system roles
    isBuiltin: false
  }).returning();
  if (data.permissionIds && data.permissionIds.length > 0) {
    const mappings = data.permissionIds.map((permId) => ({
      roleId: newRole.id,
      permissionId: Number(permId)
    }));
    await db.insert(rolePermissions).values(mappings);
  }
  console.log(`[Auth] \u2705 Created custom role: ${data.name}`);
  return newRole;
}
async function updateRole(roleId, data) {
  const db = getDatabase3();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const roleIdNum = Number(roleId);
  const [role] = await db.select().from(roles).where(eq3(roles.id, roleIdNum)).limit(1);
  if (!role) {
    throw new Error("Role not found");
  }
  if (role.isBuiltin && data.priority !== void 0) {
    throw new Error("Cannot modify priority of built-in roles");
  }
  const [updated] = await db.update(roles).set(data).where(eq3(roles.id, roleIdNum)).returning();
  return updated;
}
async function deleteRole(roleId) {
  const db = getDatabase3();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const roleIdNum = Number(roleId);
  const [role] = await db.select().from(roles).where(eq3(roles.id, roleIdNum)).limit(1);
  if (!role) {
    throw new Error("Role not found");
  }
  if (role.isBuiltin) {
    throw new Error(`Cannot delete built-in role: ${role.name}`);
  }
  if (role.isSystem) {
    throw new Error(`Cannot delete system role: ${role.name}. Deactivate it instead.`);
  }
  await db.delete(roles).where(eq3(roles.id, roleIdNum));
  console.log(`[Auth] \u{1F5D1}\uFE0F  Deleted role: ${role.name}`);
}
async function addPermissionToRole(roleId, permissionId) {
  const db = getDatabase3();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const roleIdNum = Number(roleId);
  const permissionIdNum = Number(permissionId);
  const existing = await db.select().from(rolePermissions).where(
    and3(
      eq3(rolePermissions.roleId, roleIdNum),
      eq3(rolePermissions.permissionId, permissionIdNum)
    )
  ).limit(1);
  if (existing.length > 0) {
    return;
  }
  await db.insert(rolePermissions).values({
    roleId: roleIdNum,
    permissionId: permissionIdNum
  });
}
async function removePermissionFromRole(roleId, permissionId) {
  const db = getDatabase3();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const roleIdNum = Number(roleId);
  const permissionIdNum = Number(permissionId);
  await db.delete(rolePermissions).where(
    and3(
      eq3(rolePermissions.roleId, roleIdNum),
      eq3(rolePermissions.permissionId, permissionIdNum)
    )
  );
}
async function setRolePermissions(roleId, permissionIds) {
  const db = getDatabase3();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const roleIdNum = Number(roleId);
  await db.delete(rolePermissions).where(eq3(rolePermissions.roleId, roleIdNum));
  if (permissionIds.length > 0) {
    const mappings = permissionIds.map((permId) => ({
      roleId: roleIdNum,
      permissionId: Number(permId)
    }));
    await db.insert(rolePermissions).values(mappings);
  }
}
async function getAllRoles(includeInactive = false) {
  const db = getDatabase3();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const query = db.select().from(roles);
  if (!includeInactive) {
    return query.where(eq3(roles.isActive, true));
  }
  return query;
}
async function getRoleByName(name) {
  const db = getDatabase3();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const [role] = await db.select().from(roles).where(eq3(roles.name, name)).limit(1);
  return role || null;
}
async function getRolePermissions(roleId) {
  const db = getDatabase3();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const roleIdNum = Number(roleId);
  const perms = await db.select({ name: permissions.name }).from(rolePermissions).innerJoin(permissions, eq3(rolePermissions.permissionId, permissions.id)).where(eq3(rolePermissions.roleId, roleIdNum));
  return perms.map((p) => p.name);
}
var init_role_service = __esm({
  "src/server/services/role.service.ts"() {
    "use strict";
    init_entities();
  }
});

// src/server/rbac/builtin.ts
var BUILTIN_ROLES = {
  SUPERADMIN: {
    name: "superadmin",
    displayName: "Super Administrator",
    description: "Full system access and RBAC management",
    priority: 100,
    isSystem: true,
    isBuiltin: true
  },
  ADMIN: {
    name: "admin",
    displayName: "Administrator",
    description: "User management and organization administration",
    priority: 80,
    isSystem: true,
    isBuiltin: true
  },
  USER: {
    name: "user",
    displayName: "User",
    description: "Default user role with basic permissions",
    priority: 10,
    isSystem: true,
    isBuiltin: true
  }
};
var BUILTIN_PERMISSIONS = {
  // Self-service auth management
  AUTH_SELF_MANAGE: {
    name: "auth:self:manage",
    displayName: "Manage Own Auth",
    description: "Change own password, rotate keys, manage own sessions",
    category: "auth",
    isSystem: true,
    isBuiltin: true
  },
  // User management (admin functions)
  USER_READ: {
    name: "user:read",
    displayName: "Read Users",
    description: "View user information and list users",
    category: "user",
    isSystem: true,
    isBuiltin: true
  },
  USER_WRITE: {
    name: "user:write",
    displayName: "Write Users",
    description: "Create and update user accounts",
    category: "user",
    isSystem: true,
    isBuiltin: true
  },
  USER_DELETE: {
    name: "user:delete",
    displayName: "Delete Users",
    description: "Delete user accounts",
    category: "user",
    isSystem: true,
    isBuiltin: true
  },
  USER_INVITE: {
    name: "user:invite",
    displayName: "Invite Users",
    description: "Create and send user invitations",
    category: "user",
    isSystem: true,
    isBuiltin: true
  },
  // RBAC management (superadmin functions)
  RBAC_ROLE_MANAGE: {
    name: "rbac:role:manage",
    displayName: "Manage Roles",
    description: "Create, update, and delete roles",
    category: "rbac",
    isSystem: true,
    isBuiltin: true
  },
  RBAC_PERMISSION_MANAGE: {
    name: "rbac:permission:manage",
    displayName: "Manage Permissions",
    description: "Assign permissions to roles and users",
    category: "rbac",
    isSystem: true,
    isBuiltin: true
  }
};
var BUILTIN_ROLE_PERMISSIONS = {
  superadmin: [
    "auth:self:manage",
    "user:read",
    "user:write",
    "user:delete",
    "user:invite",
    "rbac:role:manage",
    "rbac:permission:manage"
  ],
  admin: [
    "auth:self:manage",
    "user:read",
    "user:write",
    "user:delete",
    "user:invite"
  ],
  user: [
    "auth:self:manage"
  ]
};

// src/server/services/auth.service.ts
init_entities();
import { findOne as findOne2, create as create3 } from "@spfn/core/db";
import { ValidationError as ValidationError2 } from "@spfn/core/errors";

// src/server/helpers/password.ts
import bcrypt from "bcrypt";
var SALT_ROUNDS = parseInt(
  process.env.SPFN_AUTH_BCRYPT_SALT_ROUNDS || // New prefixed version (recommended)
  process.env.BCRYPT_SALT_ROUNDS || // Legacy fallback
  "10",
  10
);
async function hashPassword(password) {
  if (!password || password.length === 0) {
    throw new Error("Password cannot be empty");
  }
  return bcrypt.hash(password, SALT_ROUNDS);
}
async function verifyPassword(password, hash) {
  if (!password || password.length === 0) {
    throw new Error("Password cannot be empty");
  }
  if (!hash || hash.length === 0) {
    throw new Error("Hash cannot be empty");
  }
  return bcrypt.compare(password, hash);
}
function validatePasswordStrength(password) {
  const errors = [];
  if (password.length < 8) {
    errors.push("Password must be at least 8 characters");
  }
  if (!/[A-Z]/.test(password)) {
    errors.push("Password must contain at least one uppercase letter");
  }
  if (!/[a-z]/.test(password)) {
    errors.push("Password must contain at least one lowercase letter");
  }
  if (!/[0-9]/.test(password)) {
    errors.push("Password must contain at least one number");
  }
  if (!/[^A-Za-z0-9]/.test(password)) {
    errors.push("Password must contain at least one special character");
  }
  return {
    valid: errors.length === 0,
    errors
  };
}

// src/server/helpers/index.ts
init_jwt();

// src/server/helpers/verification.ts
init_verification_codes();
import jwt2 from "jsonwebtoken";
import { getDatabase, create } from "@spfn/core/db";
import { eq, and } from "drizzle-orm";
function getVerificationTokenSecret() {
  const secret = process.env.SPFN_AUTH_VERIFICATION_TOKEN_SECRET || // New prefixed version (recommended)
  process.env.VERIFICATION_TOKEN_SECRET || // Legacy fallback
  process.env.SPFN_AUTH_JWT_SECRET || // New JWT secret fallback
  process.env.JWT_SECRET;
  if (!secret || secret.length < 32) {
    throw new Error("SPFN_AUTH_VERIFICATION_TOKEN_SECRET must be at least 32 characters long");
  }
  return secret;
}
var VERIFICATION_TOKEN_EXPIRY = "15m";
var VERIFICATION_CODE_EXPIRY_MINUTES = 5;
var MAX_VERIFICATION_ATTEMPTS = 5;
function generateVerificationCode() {
  const code = Math.floor(Math.random() * 1e6).toString().padStart(6, "0");
  return code;
}
async function storeVerificationCode(target, targetType, code, purpose) {
  const db = getDatabase();
  if (!db) {
    throw new Error("Database not initialized");
  }
  const expiresAt = /* @__PURE__ */ new Date();
  expiresAt.setMinutes(expiresAt.getMinutes() + VERIFICATION_CODE_EXPIRY_MINUTES);
  const record = await create(verificationCodes, {
    target,
    targetType,
    code,
    purpose,
    expiresAt,
    attempts: "0"
  });
  return record;
}
async function validateVerificationCode(target, targetType, code, purpose) {
  const db = getDatabase();
  if (!db) {
    throw new Error("Database not initialized");
  }
  const records = await db.select().from(verificationCodes).where(
    and(
      eq(verificationCodes.target, target),
      eq(verificationCodes.targetType, targetType),
      eq(verificationCodes.code, code),
      eq(verificationCodes.purpose, purpose)
    )
  ).limit(1);
  if (records.length === 0) {
    return { valid: false, error: "Invalid verification code" };
  }
  const record = records[0];
  if (record.usedAt) {
    return { valid: false, error: "Verification code already used" };
  }
  if (/* @__PURE__ */ new Date() > new Date(record.expiresAt)) {
    return { valid: false, error: "Verification code expired" };
  }
  const attempts = parseInt(record.attempts, 10);
  if (attempts >= MAX_VERIFICATION_ATTEMPTS) {
    return { valid: false, error: "Too many attempts, please request a new code" };
  }
  await db.update(verificationCodes).set({ attempts: (attempts + 1).toString() }).where(eq(verificationCodes.id, record.id));
  return { valid: true, codeId: record.id };
}
async function markCodeAsUsed(codeId) {
  const db = getDatabase();
  if (!db) {
    throw new Error("Database not initialized");
  }
  await db.update(verificationCodes).set({ usedAt: /* @__PURE__ */ new Date() }).where(eq(verificationCodes.id, codeId));
}
function createVerificationToken(payload) {
  const secret = getVerificationTokenSecret();
  return jwt2.sign(payload, secret, {
    expiresIn: VERIFICATION_TOKEN_EXPIRY,
    issuer: "spfn-auth",
    audience: "spfn-client"
  });
}
function validateVerificationToken(token) {
  try {
    const secret = getVerificationTokenSecret();
    const decoded = jwt2.verify(token, secret, {
      issuer: "spfn-auth",
      audience: "spfn-client"
    });
    if (typeof decoded === "object" && decoded !== null && "target" in decoded && "targetType" in decoded && "purpose" in decoded && "codeId" in decoded) {
      return decoded;
    }
    return null;
  } catch (error) {
    console.error("[validateVerificationToken] Error:", error);
    return null;
  }
}
async function sendVerificationEmail(email, code, purpose) {
  console.log(`[VERIFICATION EMAIL] To: ${email}, Code: ${code}, Purpose: ${purpose}`);
}
async function sendVerificationSMS(phone, code, purpose) {
  console.log(`[VERIFICATION SMS] To: ${phone}, Code: ${code}, Purpose: ${purpose}`);
}

// src/server/helpers/context.ts
function getAuth(c) {
  if ("raw" in c && c.raw) {
    return c.raw.get("auth");
  }
  return c.get("auth");
}
function getUser(c) {
  return getAuth(c).user;
}
function getUserId(c) {
  return getAuth(c).userId;
}
function getKeyId(c) {
  return getAuth(c).keyId;
}

// src/server/errors/auth-errors.ts
import {
  ValidationError,
  UnauthorizedError,
  ForbiddenError,
  ConflictError
} from "@spfn/core/errors";
var InvalidCredentialsError = class extends UnauthorizedError {
  constructor(message = "Invalid credentials") {
    super(message);
    this.name = "InvalidCredentialsError";
  }
};
var InvalidTokenError = class extends UnauthorizedError {
  constructor(message = "Invalid authentication token") {
    super(message);
    this.name = "InvalidTokenError";
  }
};
var TokenExpiredError = class extends UnauthorizedError {
  constructor(message = "Authentication token has expired") {
    super(message);
    this.name = "TokenExpiredError";
  }
};
var KeyExpiredError = class extends UnauthorizedError {
  constructor(message = "Public key has expired") {
    super(message);
    this.name = "KeyExpiredError";
  }
};
var AccountDisabledError = class extends ForbiddenError {
  constructor(status = "disabled") {
    super(`Account is ${status}`, { details: { status } });
    this.name = "AccountDisabledError";
  }
};
var AccountAlreadyExistsError = class extends ConflictError {
  constructor(identifier, identifierType) {
    super("Account already exists", { details: { identifier, identifierType } });
    this.name = "AccountAlreadyExistsError";
  }
};
var InvalidVerificationCodeError = class extends ValidationError {
  constructor(reason = "Invalid verification code") {
    super(reason);
    this.name = "InvalidVerificationCodeError";
  }
};
var InvalidVerificationTokenError = class extends ValidationError {
  constructor(message = "Invalid or expired verification token") {
    super(message);
    this.name = "InvalidVerificationTokenError";
  }
};
var InvalidKeyFingerprintError = class extends ValidationError {
  constructor(message = "Invalid key fingerprint") {
    super(message);
    this.name = "InvalidKeyFingerprintError";
  }
};
var VerificationTokenPurposeMismatchError = class extends ValidationError {
  constructor(expected, actual) {
    super(`Verification token is for ${actual}, but ${expected} was expected`, { details: { expected, actual } });
    this.name = "VerificationTokenPurposeMismatchError";
  }
};
var VerificationTokenTargetMismatchError = class extends ValidationError {
  constructor() {
    super("Verification token does not match provided email/phone");
    this.name = "VerificationTokenTargetMismatchError";
  }
};

// src/server/services/key.service.ts
init_entities();
init_jwt();
import { create as create2, getDatabase as getDatabase2 } from "@spfn/core/db";
import { eq as eq2, and as and2 } from "drizzle-orm";
function getKeyExpiryDate() {
  const expiresAt = /* @__PURE__ */ new Date();
  expiresAt.setDate(expiresAt.getDate() + 90);
  return expiresAt;
}
async function registerPublicKeyService(params) {
  const { userId, keyId, publicKey, fingerprint, algorithm = "ES256" } = params;
  const isValidFingerprint = verifyKeyFingerprint(publicKey, fingerprint);
  if (!isValidFingerprint) {
    throw new InvalidKeyFingerprintError();
  }
  await create2(userPublicKeys, {
    userId,
    keyId,
    publicKey,
    algorithm,
    fingerprint,
    isActive: true,
    createdAt: /* @__PURE__ */ new Date(),
    expiresAt: getKeyExpiryDate()
  });
}
async function rotateKeyService(params) {
  const { userId, oldKeyId, newKeyId, newPublicKey, fingerprint, algorithm = "ES256" } = params;
  const isValidFingerprint = verifyKeyFingerprint(newPublicKey, fingerprint);
  if (!isValidFingerprint) {
    throw new InvalidKeyFingerprintError();
  }
  const db = getDatabase2();
  await db.update(userPublicKeys).set({
    isActive: false,
    revokedAt: /* @__PURE__ */ new Date(),
    revokedReason: "Replaced by key rotation"
  }).where(
    and2(
      eq2(userPublicKeys.keyId, oldKeyId),
      eq2(userPublicKeys.userId, userId)
    )
  );
  await create2(userPublicKeys, {
    userId,
    keyId: newKeyId,
    publicKey: newPublicKey,
    algorithm,
    fingerprint,
    isActive: true,
    createdAt: /* @__PURE__ */ new Date(),
    expiresAt: getKeyExpiryDate()
  });
  return {
    success: true,
    keyId: newKeyId
  };
}
async function revokeKeyService(params) {
  const { userId, keyId, reason } = params;
  const db = getDatabase2();
  await db.update(userPublicKeys).set({
    isActive: false,
    revokedAt: /* @__PURE__ */ new Date(),
    revokedReason: reason
  }).where(
    and2(
      eq2(userPublicKeys.keyId, keyId),
      eq2(userPublicKeys.userId, userId)
    )
  );
}

// src/server/services/user.service.ts
init_entities();
import { findOne, updateOne } from "@spfn/core/db";
async function getUserByIdService(userId) {
  return await findOne(users, { id: userId });
}
async function getUserByEmailService(email) {
  return await findOne(users, { email });
}
async function getUserByPhoneService(phone) {
  return await findOne(users, { phone });
}
async function updateLastLoginService(userId) {
  await updateOne(users, { id: userId }, {
    lastLoginAt: /* @__PURE__ */ new Date()
  });
}
async function updateUserService(userId, updates) {
  await updateOne(users, { id: userId }, {
    ...updates,
    updatedAt: /* @__PURE__ */ new Date()
  });
}

// src/server/services/auth.service.ts
async function checkAccountExistsService(params) {
  const { email, phone } = params;
  let identifier;
  let identifierType;
  let user;
  if (email) {
    identifier = email;
    identifierType = "email";
    user = await findOne2(users, { email });
  } else if (phone) {
    identifier = phone;
    identifierType = "phone";
    user = await findOne2(users, { phone });
  } else {
    throw new ValidationError2("Either email or phone must be provided");
  }
  return {
    exists: !!user,
    identifier,
    identifierType
  };
}
async function registerService(params) {
  const { email, phone, verificationToken, password, publicKey, keyId, fingerprint, algorithm } = params;
  const tokenPayload = validateVerificationToken(verificationToken);
  if (!tokenPayload) {
    throw new InvalidVerificationTokenError();
  }
  if (tokenPayload.purpose !== "registration") {
    throw new VerificationTokenPurposeMismatchError("registration", tokenPayload.purpose);
  }
  const providedTarget = email || phone;
  if (tokenPayload.target !== providedTarget) {
    throw new VerificationTokenTargetMismatchError();
  }
  const providedTargetType = email ? "email" : "phone";
  if (tokenPayload.targetType !== providedTargetType) {
    throw new VerificationTokenTargetMismatchError();
  }
  let existingUser;
  if (email) {
    existingUser = await findOne2(users, { email });
  } else if (phone) {
    existingUser = await findOne2(users, { phone });
  } else {
    throw new ValidationError2("Either email or phone must be provided");
  }
  if (existingUser) {
    const identifierType = email ? "email" : "phone";
    throw new AccountAlreadyExistsError(email || phone, identifierType);
  }
  const passwordHash = await hashPassword(password);
  const { getRoleByName: getRoleByName2 } = await Promise.resolve().then(() => (init_role_service(), role_service_exports));
  const userRole = await getRoleByName2("user");
  if (!userRole) {
    throw new Error("Default user role not found. Run initializeAuth() first.");
  }
  const newUser = await create3(users, {
    email: email || null,
    phone: phone || null,
    passwordHash,
    passwordChangeRequired: false,
    roleId: userRole.id,
    status: "active",
    createdAt: /* @__PURE__ */ new Date(),
    updatedAt: /* @__PURE__ */ new Date()
  });
  await registerPublicKeyService({
    userId: newUser.id,
    keyId,
    publicKey,
    fingerprint,
    algorithm
  });
  return {
    userId: String(newUser.id),
    email: newUser.email || void 0,
    phone: newUser.phone || void 0
  };
}
async function loginService(params) {
  const { email, phone, password, publicKey, keyId, fingerprint, oldKeyId, algorithm } = params;
  let user;
  if (email) {
    user = await findOne2(users, { email });
  } else if (phone) {
    user = await findOne2(users, { phone });
  } else {
    throw new ValidationError2("Either email or phone must be provided");
  }
  if (!user || !user.passwordHash) {
    throw new InvalidCredentialsError();
  }
  console.log("user", user);
  console.log("\uD328\uC2A4\uC6CC\uB4DC: ", password);
  const isValid = await verifyPassword(password, user.passwordHash);
  if (!isValid) {
    throw new InvalidCredentialsError();
  }
  if (user.status !== "active") {
    throw new AccountDisabledError(user.status);
  }
  if (oldKeyId) {
    await revokeKeyService({
      userId: user.id,
      keyId: oldKeyId,
      reason: "Replaced by new key on login"
    });
  }
  await registerPublicKeyService({
    userId: user.id,
    keyId,
    publicKey,
    fingerprint,
    algorithm
  });
  await updateLastLoginService(user.id);
  return {
    userId: String(user.id),
    email: user.email || void 0,
    phone: user.phone || void 0,
    passwordChangeRequired: user.passwordChangeRequired
  };
}
async function logoutService(params) {
  const { userId, keyId } = params;
  await revokeKeyService({
    userId,
    keyId,
    reason: "Revoked by logout"
  });
}
async function changePasswordService(params) {
  const { userId, currentPassword, newPassword, passwordHash: providedHash } = params;
  let passwordHash;
  if (providedHash) {
    passwordHash = providedHash;
  } else {
    const user = await findOne2(users, { id: userId });
    if (!user) {
      throw new ValidationError2("User not found");
    }
    passwordHash = user.passwordHash;
  }
  if (!passwordHash) {
    throw new ValidationError2("No password set for this account");
  }
  const isValid = await verifyPassword(currentPassword, passwordHash);
  if (!isValid) {
    throw new InvalidCredentialsError("Current password is incorrect");
  }
  const newPasswordHash = await hashPassword(newPassword);
  const { updateOne: updateOne2 } = await import("@spfn/core/db");
  await updateOne2(users, { id: userId }, {
    passwordHash: newPasswordHash,
    passwordChangeRequired: false,
    updatedAt: /* @__PURE__ */ new Date()
  });
}

// src/server/services/verification.service.ts
async function sendVerificationCodeService(params) {
  const { target, targetType, purpose } = params;
  const code = generateVerificationCode();
  const codeRecord = await storeVerificationCode(target, targetType, code, purpose);
  if (targetType === "email") {
    await sendVerificationEmail(target, code, purpose);
  } else {
    await sendVerificationSMS(target, code, purpose);
  }
  return {
    success: true,
    expiresAt: codeRecord.expiresAt.toISOString()
  };
}
async function verifyCodeService(params) {
  const { target, targetType, code, purpose } = params;
  const validation = await validateVerificationCode(target, targetType, code, purpose);
  if (!validation.valid) {
    throw new InvalidVerificationCodeError(validation.error || "Invalid verification code");
  }
  await markCodeAsUsed(validation.codeId);
  const verificationToken = createVerificationToken({
    target,
    targetType,
    purpose,
    codeId: validation.codeId
  });
  return {
    valid: true,
    verificationToken
  };
}

// src/server/services/me.service.ts
init_entities();
import { getDatabase as getDatabase4 } from "@spfn/core/db";
import { eq as eq4, and as and4 } from "drizzle-orm";
async function getMeService(userId) {
  const db = getDatabase4();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const userIdNum = typeof userId === "string" ? Number(userId) : Number(userId);
  const [userWithRole] = await db.select({
    userId: users.id,
    email: users.email,
    phone: users.phone,
    roleId: roles.id,
    roleName: roles.name,
    roleDisplayName: roles.displayName,
    rolePriority: roles.priority
  }).from(users).innerJoin(roles, eq4(users.roleId, roles.id)).where(eq4(users.id, userIdNum)).limit(1);
  if (!userWithRole) {
    throw new Error("[Auth] User not found");
  }
  const rolePerms = await db.select({
    id: permissions.id,
    name: permissions.name,
    displayName: permissions.displayName,
    category: permissions.category
  }).from(rolePermissions).innerJoin(permissions, eq4(rolePermissions.permissionId, permissions.id)).where(
    and4(
      eq4(rolePermissions.roleId, userWithRole.roleId),
      eq4(permissions.isActive, true)
    )
  );
  return {
    userId: userWithRole.userId.toString(),
    email: userWithRole.email ?? void 0,
    phone: userWithRole.phone ?? void 0,
    role: {
      id: userWithRole.roleId,
      name: userWithRole.roleName,
      displayName: userWithRole.roleDisplayName,
      priority: userWithRole.rolePriority
    },
    permissions: rolePerms.map((perm) => ({
      id: perm.id,
      name: perm.name,
      displayName: perm.displayName,
      category: perm.category ?? void 0
    }))
  };
}

// src/server/services/rbac.service.ts
init_entities();
import { getDatabase as getDatabase5 } from "@spfn/core/db";
import { logger } from "@spfn/core/logger";
import { eq as eq5, and as and5, inArray } from "drizzle-orm";

// src/lib/config.ts
var globalConfig = {
  sessionTtl: "7d"
  // Default: 7 days
};
function configureAuth(config) {
  globalConfig = {
    ...globalConfig,
    ...config
  };
}

// src/server/services/rbac.service.ts
var authLogger = logger.child("@spfn/auth");
async function initializeAuth(options = {}) {
  const db = getDatabase5();
  if (!db) {
    throw new Error("[Auth] Database not initialized. Call initDatabase() first.");
  }
  authLogger.info("\u{1F510} Initializing RBAC system...");
  if (options.sessionTtl !== void 0) {
    configureAuth({
      sessionTtl: options.sessionTtl
    });
    authLogger.info(`\u23F1\uFE0F  Session TTL: ${options.sessionTtl}`);
  }
  const allRoles = [
    ...Object.values(BUILTIN_ROLES),
    ...options.roles || []
  ];
  for (const roleConfig of allRoles) {
    await upsertRole(roleConfig);
  }
  const allPermissions = [
    ...Object.values(BUILTIN_PERMISSIONS),
    ...options.permissions || []
  ];
  for (const permConfig of allPermissions) {
    await upsertPermission(permConfig);
  }
  const allMappings = { ...BUILTIN_ROLE_PERMISSIONS };
  if (options.rolePermissions) {
    for (const [roleName, permNames] of Object.entries(options.rolePermissions)) {
      if (allMappings[roleName]) {
        allMappings[roleName] = [
          .../* @__PURE__ */ new Set([...allMappings[roleName], ...permNames])
        ];
      } else {
        allMappings[roleName] = permNames;
      }
    }
  }
  for (const [roleName, permNames] of Object.entries(allMappings)) {
    await assignPermissionsToRole(roleName, permNames);
  }
  authLogger.info("\u2705 RBAC initialization complete");
  authLogger.info(`\u{1F4CA} Roles: ${allRoles.length}, Permissions: ${allPermissions.length}`);
  authLogger.info("\u{1F512} Built-in roles: user, admin, superadmin");
}
async function upsertRole(config) {
  const db = getDatabase5();
  const existing = await db.select().from(roles).where(eq5(roles.name, config.name)).limit(1);
  if (existing.length === 0) {
    await db.insert(roles).values({
      name: config.name,
      displayName: config.displayName,
      description: config.description,
      priority: config.priority ?? 10,
      isSystem: config.isSystem ?? false,
      isBuiltin: config.isBuiltin ?? false
    });
    authLogger.info(`  \u2705 Created role: ${config.name}`);
  } else {
    const updateData = {
      displayName: config.displayName,
      description: config.description
    };
    if (!existing[0].isBuiltin) {
      updateData.priority = config.priority ?? existing[0].priority;
    }
    await db.update(roles).set(updateData).where(eq5(roles.id, existing[0].id));
  }
}
async function upsertPermission(config) {
  const db = getDatabase5();
  const existing = await db.select().from(permissions).where(eq5(permissions.name, config.name)).limit(1);
  if (existing.length === 0) {
    await db.insert(permissions).values({
      name: config.name,
      displayName: config.displayName,
      description: config.description,
      category: config.category,
      isSystem: config.isSystem ?? false,
      isBuiltin: config.isBuiltin ?? false
    });
    authLogger.info(`  \u2705 Created permission: ${config.name}`);
  } else {
    await db.update(permissions).set({
      displayName: config.displayName,
      description: config.description,
      category: config.category
    }).where(eq5(permissions.id, existing[0].id));
  }
}
async function assignPermissionsToRole(roleName, permissionNames) {
  const db = getDatabase5();
  const [role] = await db.select().from(roles).where(eq5(roles.name, roleName)).limit(1);
  if (!role) {
    authLogger.warn(`  \u26A0\uFE0F  Role not found: ${roleName}, skipping permission assignment`);
    return;
  }
  const perms = await db.select().from(permissions).where(inArray(permissions.name, permissionNames));
  if (perms.length === 0) {
    authLogger.warn(`  \u26A0\uFE0F  No permissions found for role: ${roleName}`);
    return;
  }
  for (const perm of perms) {
    const existing = await db.select().from(rolePermissions).where(
      and5(
        eq5(rolePermissions.roleId, role.id),
        eq5(rolePermissions.permissionId, perm.id)
      )
    ).limit(1);
    if (existing.length === 0) {
      await db.insert(rolePermissions).values({
        roleId: role.id,
        permissionId: perm.id
      });
    }
  }
}

// src/server/services/permission.service.ts
init_entities();
import { getDatabase as getDatabase6 } from "@spfn/core/db";
import { eq as eq6, and as and6 } from "drizzle-orm";
async function getUserPermissions(userId) {
  const db = getDatabase6();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const userIdNum = typeof userId === "string" ? Number(userId) : Number(userId);
  const [user] = await db.select({ roleId: users.roleId }).from(users).where(eq6(users.id, userIdNum)).limit(1);
  if (!user || !user.roleId) {
    return [];
  }
  const permSet = /* @__PURE__ */ new Set();
  const rolePerms = await db.select({ name: permissions.name }).from(rolePermissions).innerJoin(permissions, eq6(rolePermissions.permissionId, permissions.id)).where(
    and6(
      eq6(rolePermissions.roleId, user.roleId),
      eq6(permissions.isActive, true)
    )
  );
  for (const perm of rolePerms) {
    permSet.add(perm.name);
  }
  const userPerms = await db.select({
    name: permissions.name,
    granted: userPermissions.granted,
    expiresAt: userPermissions.expiresAt
  }).from(userPermissions).innerJoin(permissions, eq6(userPermissions.permissionId, permissions.id)).where(eq6(userPermissions.userId, userIdNum));
  const now = /* @__PURE__ */ new Date();
  for (const userPerm of userPerms) {
    if (userPerm.expiresAt && userPerm.expiresAt < now) {
      continue;
    }
    if (userPerm.granted) {
      permSet.add(userPerm.name);
    } else {
      permSet.delete(userPerm.name);
    }
  }
  return Array.from(permSet);
}
async function hasPermission(userId, permissionName) {
  const perms = await getUserPermissions(userId);
  return perms.includes(permissionName);
}
async function hasAnyPermission(userId, permissionNames) {
  const perms = await getUserPermissions(userId);
  return permissionNames.some((p) => perms.includes(p));
}
async function hasAllPermissions(userId, permissionNames) {
  const perms = await getUserPermissions(userId);
  return permissionNames.every((p) => perms.includes(p));
}
async function hasRole(userId, roleName) {
  const db = getDatabase6();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const userIdNum = typeof userId === "string" ? Number(userId) : Number(userId);
  const [user] = await db.select({ roleId: users.roleId }).from(users).where(eq6(users.id, userIdNum)).limit(1);
  if (!user || !user.roleId) {
    return false;
  }
  const [role] = await db.select({ name: roles.name }).from(roles).where(eq6(roles.id, user.roleId)).limit(1);
  return role?.name === roleName;
}
async function hasAnyRole(userId, roleNames) {
  for (const roleName of roleNames) {
    if (await hasRole(userId, roleName)) {
      return true;
    }
  }
  return false;
}

// src/server/services/index.ts
init_role_service();

// src/server/services/invitation.service.ts
init_entities();
import { getDatabase as getDatabase7 } from "@spfn/core/db";
import { eq as eq7, and as and7, lt, desc, sql as sql2 } from "drizzle-orm";
import crypto2 from "crypto";
function generateInvitationToken() {
  return crypto2.randomUUID();
}
function calculateExpiresAt(days = 7) {
  const expiresAt = /* @__PURE__ */ new Date();
  expiresAt.setDate(expiresAt.getDate() + days);
  return expiresAt;
}
async function createInvitation(params) {
  const db = getDatabase7();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const { email, roleId, invitedBy, expiresInDays = 7, metadata } = params;
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!emailRegex.test(email)) {
    throw new Error("Invalid email format");
  }
  const existingUser = await db.select().from(users).where(eq7(users.email, email)).limit(1);
  if (existingUser.length > 0) {
    throw new Error("User with this email already exists");
  }
  const existingInvitation = await db.select().from(invitations).where(
    and7(
      eq7(invitations.email, email),
      eq7(invitations.status, "pending")
    )
  ).limit(1);
  if (existingInvitation.length > 0) {
    throw new Error("Pending invitation already exists for this email");
  }
  const role = await db.select().from(roles).where(eq7(roles.id, roleId)).limit(1);
  if (role.length === 0) {
    throw new Error(`Role with id ${roleId} not found`);
  }
  const inviter = await db.select().from(users).where(eq7(users.id, invitedBy)).limit(1);
  if (inviter.length === 0) {
    throw new Error(`User with id ${invitedBy} not found`);
  }
  const token = generateInvitationToken();
  const expiresAt = calculateExpiresAt(expiresInDays);
  const [invitation] = await db.insert(invitations).values({
    email,
    token,
    roleId,
    invitedBy,
    status: "pending",
    expiresAt,
    metadata: metadata || null
  }).returning();
  console.log(`[Auth] \u2705 Created invitation: ${email} as ${role[0].name} (expires: ${expiresAt.toISOString()})`);
  return invitation;
}
async function getInvitationByToken(token) {
  const db = getDatabase7();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const result = await db.select().from(invitations).where(eq7(invitations.token, token)).limit(1);
  return result[0] || null;
}
async function getInvitationWithDetails(token) {
  const db = getDatabase7();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const result = await db.select({
    id: invitations.id,
    email: invitations.email,
    token: invitations.token,
    roleId: invitations.roleId,
    invitedBy: invitations.invitedBy,
    status: invitations.status,
    expiresAt: invitations.expiresAt,
    acceptedAt: invitations.acceptedAt,
    cancelledAt: invitations.cancelledAt,
    metadata: invitations.metadata,
    createdAt: invitations.createdAt,
    updatedAt: invitations.updatedAt,
    role: {
      id: roles.id,
      name: roles.name,
      displayName: roles.displayName
    },
    inviter: {
      id: users.id,
      email: users.email
    }
  }).from(invitations).innerJoin(roles, eq7(invitations.roleId, roles.id)).innerJoin(users, eq7(invitations.invitedBy, users.id)).where(eq7(invitations.token, token)).limit(1);
  return result[0] || null;
}
async function validateInvitation(token) {
  const invitation = await getInvitationByToken(token);
  if (!invitation) {
    return { valid: false, error: "Invitation not found" };
  }
  if (invitation.status === "accepted") {
    return { valid: false, error: "Invitation already accepted", invitation };
  }
  if (invitation.status === "cancelled") {
    return { valid: false, error: "Invitation was cancelled", invitation };
  }
  if (invitation.status === "expired") {
    return { valid: false, error: "Invitation has expired", invitation };
  }
  if (/* @__PURE__ */ new Date() > new Date(invitation.expiresAt)) {
    return { valid: false, error: "Invitation has expired", invitation };
  }
  return { valid: true, invitation };
}
async function acceptInvitation(params) {
  const db = getDatabase7();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const { token, password, publicKey, keyId, fingerprint, algorithm } = params;
  const validation = await validateInvitation(token);
  if (!validation.valid || !validation.invitation) {
    throw new Error(validation.error || "Invalid invitation");
  }
  const invitation = validation.invitation;
  const role = await db.select().from(roles).where(eq7(roles.id, invitation.roleId)).limit(1);
  if (role.length === 0) {
    throw new Error("Role not found");
  }
  const passwordHash = await hashPassword(password);
  const result = await db.transaction(async (tx) => {
    const [newUser] = await tx.insert(users).values({
      email: invitation.email,
      passwordHash,
      roleId: invitation.roleId,
      emailVerifiedAt: /* @__PURE__ */ new Date(),
      // Auto-verify invited users
      passwordChangeRequired: false,
      status: "active"
    }).returning();
    const { userPublicKeys: userPublicKeys2 } = await Promise.resolve().then(() => (init_entities(), entities_exports));
    await tx.insert(userPublicKeys2).values({
      userId: newUser.id,
      keyId,
      publicKey,
      algorithm,
      fingerprint,
      isActive: true,
      expiresAt: new Date(Date.now() + 90 * 24 * 60 * 60 * 1e3)
      // 90 days
    });
    await tx.update(invitations).set({
      status: "accepted",
      acceptedAt: /* @__PURE__ */ new Date(),
      updatedAt: /* @__PURE__ */ new Date()
    }).where(eq7(invitations.id, invitation.id));
    return { newUser, role: role[0] };
  });
  console.log(`[Auth] \u2705 Invitation accepted: ${invitation.email} as ${result.role.name}`);
  return {
    userId: result.newUser.id,
    email: result.newUser.email,
    role: result.role.name
  };
}
async function listInvitations(params) {
  const db = getDatabase7();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const { status, invitedBy, page = 1, limit = 20 } = params;
  const offset = (page - 1) * limit;
  const conditions = [];
  if (status) {
    conditions.push(eq7(invitations.status, status));
  }
  if (invitedBy) {
    conditions.push(eq7(invitations.invitedBy, invitedBy));
  }
  const whereClause = conditions.length > 0 ? and7(...conditions) : void 0;
  const countResult = await db.select({ count: sql2`count(*)` }).from(invitations).where(whereClause);
  const total = Number(countResult[0]?.count || 0);
  const results = await db.select({
    id: invitations.id,
    email: invitations.email,
    token: invitations.token,
    roleId: invitations.roleId,
    invitedBy: invitations.invitedBy,
    status: invitations.status,
    expiresAt: invitations.expiresAt,
    acceptedAt: invitations.acceptedAt,
    cancelledAt: invitations.cancelledAt,
    metadata: invitations.metadata,
    createdAt: invitations.createdAt,
    updatedAt: invitations.updatedAt,
    role: {
      id: roles.id,
      name: roles.name,
      displayName: roles.displayName
    },
    inviter: {
      id: users.id,
      email: users.email
    }
  }).from(invitations).innerJoin(roles, eq7(invitations.roleId, roles.id)).innerJoin(users, eq7(invitations.invitedBy, users.id)).where(whereClause).orderBy(desc(invitations.createdAt)).limit(limit).offset(offset);
  return {
    invitations: results,
    total,
    page,
    limit,
    totalPages: Math.ceil(total / limit)
  };
}
async function cancelInvitation(id10, cancelledBy, reason) {
  const db = getDatabase7();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const invitation = await db.select().from(invitations).where(eq7(invitations.id, id10)).limit(1);
  if (invitation.length === 0) {
    throw new Error("Invitation not found");
  }
  if (invitation[0].status !== "pending") {
    throw new Error(`Cannot cancel ${invitation[0].status} invitation`);
  }
  await db.update(invitations).set({
    status: "cancelled",
    cancelledAt: /* @__PURE__ */ new Date(),
    updatedAt: /* @__PURE__ */ new Date(),
    metadata: invitation[0].metadata ? { ...invitation[0].metadata, cancelReason: reason, cancelledBy } : { cancelReason: reason, cancelledBy }
  }).where(eq7(invitations.id, id10));
  console.log(`[Auth] \u26A0\uFE0F  Invitation cancelled: ${invitation[0].email} (reason: ${reason || "none"})`);
}
async function deleteInvitation(id10) {
  const db = getDatabase7();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  await db.delete(invitations).where(eq7(invitations.id, id10));
  console.log(`[Auth] \u{1F5D1}\uFE0F  Invitation deleted: ${id10}`);
}
async function expireOldInvitations() {
  const db = getDatabase7();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const now = /* @__PURE__ */ new Date();
  const expiredInvitations = await db.select().from(invitations).where(
    and7(
      eq7(invitations.status, "pending"),
      lt(invitations.expiresAt, now)
    )
  );
  if (expiredInvitations.length === 0) {
    return 0;
  }
  await db.update(invitations).set({
    status: "expired",
    updatedAt: now
  }).where(
    and7(
      eq7(invitations.status, "pending"),
      lt(invitations.expiresAt, now)
    )
  );
  console.log(`[Auth] \u23F0 Expired ${expiredInvitations.length} old invitations`);
  return expiredInvitations.length;
}
async function resendInvitation(id10, expiresInDays = 7) {
  const db = getDatabase7();
  if (!db) {
    throw new Error("[Auth] Database not initialized");
  }
  const invitation = await db.select().from(invitations).where(eq7(invitations.id, id10)).limit(1);
  if (invitation.length === 0) {
    throw new Error("Invitation not found");
  }
  if (!["pending", "expired"].includes(invitation[0].status)) {
    throw new Error(`Cannot resend ${invitation[0].status} invitation`);
  }
  const newExpiresAt = calculateExpiresAt(expiresInDays);
  const [updated] = await db.update(invitations).set({
    status: "pending",
    expiresAt: newExpiresAt,
    updatedAt: /* @__PURE__ */ new Date()
  }).where(eq7(invitations.id, id10)).returning();
  console.log(`[Auth] \u{1F4E7} Invitation resent: ${invitation[0].email} (new expiry: ${newExpiresAt.toISOString()})`);
  return updated;
}

// src/server/middleware/authenticate.ts
init_jwt();
init_entities();
import { findOne as findOne3, getDatabase as getDatabase8 } from "@spfn/core/db";
import { UnauthorizedError as UnauthorizedError2 } from "@spfn/core/errors";
import { eq as eq8, and as and8 } from "drizzle-orm";
async function authenticate(c, next) {
  const authHeader = c.req.header("Authorization");
  if (!authHeader || !authHeader.startsWith("Bearer ")) {
    throw new UnauthorizedError2("Missing or invalid authorization header");
  }
  const token = authHeader.substring(7);
  const { decodeToken: decodeToken2 } = await Promise.resolve().then(() => (init_jwt(), jwt_exports));
  const decoded = decodeToken2(token);
  if (!decoded || !decoded.keyId) {
    throw new UnauthorizedError2("Invalid token: missing keyId");
  }
  const keyId = decoded.keyId;
  const db = getDatabase8();
  const [keyRecord] = await db.select().from(userPublicKeys).where(
    and8(
      eq8(userPublicKeys.keyId, keyId),
      eq8(userPublicKeys.isActive, true)
    )
  );
  if (!keyRecord) {
    throw new UnauthorizedError2("Invalid or revoked key");
  }
  if (keyRecord.expiresAt && /* @__PURE__ */ new Date() > keyRecord.expiresAt) {
    throw new KeyExpiredError();
  }
  try {
    verifyClientToken(
      token,
      keyRecord.publicKey,
      keyRecord.algorithm
    );
  } catch (err) {
    if (err instanceof Error) {
      if (err.name === "TokenExpiredError") {
        throw new TokenExpiredError();
      }
      if (err.name === "JsonWebTokenError") {
        throw new InvalidTokenError("Invalid token signature");
      }
    }
    throw new UnauthorizedError2("Authentication failed");
  }
  const user = await findOne3(users, { id: keyRecord.userId });
  if (!user) {
    throw new UnauthorizedError2("User not found");
  }
  if (user.status !== "active") {
    throw new AccountDisabledError(user.status);
  }
  db.update(userPublicKeys).set({ lastUsedAt: /* @__PURE__ */ new Date() }).where(eq8(userPublicKeys.id, keyRecord.id)).execute().catch((err) => console.error("Failed to update lastUsedAt:", err));
  c.set("auth", {
    user,
    userId: String(user.id),
    keyId
  });
  await next();
}

// src/server/middleware/require-permission.ts
import { ForbiddenError as ForbiddenError2 } from "@spfn/core/errors";
function requirePermissions(...permissionNames) {
  return async (c, next) => {
    const auth = getAuth(c);
    if (!auth) {
      throw new ForbiddenError2("Authentication required");
    }
    const { userId } = auth;
    const allowed = await hasAllPermissions(userId, permissionNames);
    if (!allowed) {
      throw new ForbiddenError2(
        `Missing required permissions: ${permissionNames.join(", ")}`
      );
    }
    await next();
  };
}
function requireAnyPermission(...permissionNames) {
  return async (c, next) => {
    const auth = getAuth(c);
    if (!auth) {
      throw new ForbiddenError2("Authentication required");
    }
    const { userId } = auth;
    const allowed = await hasAnyPermission(userId, permissionNames);
    if (!allowed) {
      throw new ForbiddenError2(
        `Requires one of: ${permissionNames.join(", ")}`
      );
    }
    await next();
  };
}

// src/server/middleware/require-role.ts
import { ForbiddenError as ForbiddenError3 } from "@spfn/core/errors";
function requireRole(...roleNames) {
  return async (c, next) => {
    const auth = getAuth(c);
    if (!auth) {
      throw new ForbiddenError3("Authentication required");
    }
    const { userId } = auth;
    const allowed = await hasAnyRole(userId, roleNames);
    if (!allowed) {
      throw new ForbiddenError3(
        `Required roles: ${roleNames.join(", ")}`
      );
    }
    await next();
  };
}

// src/server/setup.ts
init_entities();
import { findOne as findOne4, create as create4 } from "@spfn/core/db";
import { logger as logger2 } from "@spfn/core/logger";
init_role_service();
var authLogger2 = logger2.child("@spfn/auth");
function parseAdminAccounts() {
  const accounts = [];
  if (process.env.SPFN_AUTH_ADMIN_ACCOUNTS || process.env.ADMIN_ACCOUNTS) {
    try {
      const accountsJson = process.env.SPFN_AUTH_ADMIN_ACCOUNTS || // New prefixed version (recommended)
      process.env.ADMIN_ACCOUNTS;
      const parsed = JSON.parse(accountsJson);
      if (!Array.isArray(parsed)) {
        authLogger2.error("\u274C SPFN_AUTH_ADMIN_ACCOUNTS must be an array");
        return accounts;
      }
      for (const item of parsed) {
        if (!item.email || !item.password) {
          authLogger2.warn("\u26A0\uFE0F  Skipping account: missing email or password");
          continue;
        }
        accounts.push({
          email: item.email,
          password: item.password,
          role: item.role || "user",
          phone: item.phone,
          passwordChangeRequired: item.passwordChangeRequired !== false
          // Default: true
        });
      }
      return accounts;
    } catch (error) {
      const err = error;
      authLogger2.error("\u274C Failed to parse SPFN_AUTH_ADMIN_ACCOUNTS:", err);
      return accounts;
    }
  }
  const adminEmails = process.env.SPFN_AUTH_ADMIN_EMAILS || // New prefixed version (recommended)
  process.env.ADMIN_EMAILS;
  if (adminEmails) {
    const emails = adminEmails.split(",").map((s) => s.trim());
    const passwords = (process.env.SPFN_AUTH_ADMIN_PASSWORDS || // New prefixed version (recommended)
    process.env.ADMIN_PASSWORDS || // Legacy fallback
    "").split(",").map((s) => s.trim());
    const roles2 = (process.env.SPFN_AUTH_ADMIN_ROLES || // New prefixed version (recommended)
    process.env.ADMIN_ROLES || // Legacy fallback
    "").split(",").map((s) => s.trim());
    if (passwords.length !== emails.length) {
      authLogger2.error("\u274C SPFN_AUTH_ADMIN_EMAILS and SPFN_AUTH_ADMIN_PASSWORDS length mismatch");
      return accounts;
    }
    for (let i = 0; i < emails.length; i++) {
      const email = emails[i];
      const password = passwords[i];
      const role = roles2[i] || "user";
      if (!email || !password) {
        authLogger2.warn(`\u26A0\uFE0F  Skipping account ${i + 1}: missing email or password`);
        continue;
      }
      accounts.push({
        email,
        password,
        role,
        passwordChangeRequired: true
      });
    }
    return accounts;
  }
  const adminEmail = process.env.SPFN_AUTH_ADMIN_EMAIL || // New prefixed version (recommended)
  process.env.ADMIN_EMAIL;
  const adminPassword = process.env.SPFN_AUTH_ADMIN_PASSWORD || // New prefixed version (recommended)
  process.env.ADMIN_PASSWORD;
  if (adminEmail && adminPassword) {
    accounts.push({
      email: adminEmail,
      password: adminPassword,
      role: "superadmin",
      passwordChangeRequired: true
    });
  }
  return accounts;
}
async function ensureAdminExists() {
  const accounts = parseAdminAccounts();
  if (accounts.length === 0) {
    return;
  }
  authLogger2.info(`Creating ${accounts.length} admin account(s)...`);
  let created = 0;
  let skipped = 0;
  let failed = 0;
  for (const account of accounts) {
    authLogger2.info(`Creating ${account.email} admin account(s)...`);
    try {
      const existing = await findOne4(users, { email: account.email });
      if (existing) {
        authLogger2.info(`\u26A0\uFE0F  Account already exists: ${account.email} (skipped)`);
        skipped++;
        continue;
      }
      const roleName = account.role || "user";
      const role = await getRoleByName(roleName);
      if (!role) {
        authLogger2.error(`\u274C Role '${roleName}' not found for ${account.email}. Run initializeAuth() first.`);
        failed++;
        continue;
      }
      const passwordHash = await hashPassword(account.password);
      await create4(users, {
        email: account.email,
        phone: account.phone || null,
        passwordHash,
        roleId: role.id,
        emailVerifiedAt: /* @__PURE__ */ new Date(),
        // Auto-verify admin
        passwordChangeRequired: account.passwordChangeRequired !== false,
        status: "active"
      });
      authLogger2.info(`\u2705 Admin account created: ${account.email} (${roleName})`);
      created++;
    } catch (error) {
      const err = error;
      authLogger2.error(`\u274C Failed to create account ${account.email}:`, err);
      failed++;
    }
  }
  authLogger2.info(`\u{1F4CA} Summary: ${created} created, ${skipped} skipped, ${failed} failed`);
  if (created > 0) {
    authLogger2.info("\u26A0\uFE0F  Please change passwords on first login!");
  }
}
export {
  BUILTIN_PERMISSIONS,
  BUILTIN_ROLES,
  BUILTIN_ROLE_PERMISSIONS,
  acceptInvitation,
  addPermissionToRole,
  authenticate,
  cancelInvitation,
  changePasswordService,
  checkAccountExistsService,
  createInvitation,
  createRole,
  createVerificationToken,
  decodeToken,
  deleteInvitation,
  deleteRole,
  ensureAdminExists,
  expireOldInvitations,
  generateToken,
  generateVerificationCode,
  getAllRoles,
  getAuth,
  getInvitationByToken,
  getInvitationWithDetails,
  getKeyId,
  getMeService,
  getRoleByName,
  getRolePermissions,
  getUser,
  getUserByEmailService,
  getUserByIdService,
  getUserByPhoneService,
  getUserId,
  getUserPermissions,
  hasAllPermissions,
  hasAnyPermission,
  hasAnyRole,
  hasPermission,
  hasRole,
  hashPassword,
  initializeAuth,
  listInvitations,
  loginService,
  logoutService,
  markCodeAsUsed,
  registerPublicKeyService,
  registerService,
  removePermissionFromRole,
  requireAnyPermission,
  requirePermissions,
  requireRole,
  resendInvitation,
  revokeKeyService,
  rotateKeyService,
  sendVerificationCodeService,
  sendVerificationEmail,
  sendVerificationSMS,
  setRolePermissions,
  storeVerificationCode,
  updateLastLoginService,
  updateRole,
  updateUserService,
  validateInvitation,
  validatePasswordStrength,
  validateVerificationCode,
  validateVerificationToken,
  verifyClientToken,
  verifyCodeService,
  verifyKeyFingerprint,
  verifyPassword,
  verifyToken
};
//# sourceMappingURL=server.js.map