@openmdm/core 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +180 -3
- package/dist/index.js +233 -5
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +150 -2
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/dashboard.ts +40 -0
- package/src/device-identity.ts +338 -0
- package/src/index.ts +165 -5
- package/src/types.ts +155 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/logger.ts","../src/webhooks.ts","../src/tenant.ts","../src/authorization.ts","../src/audit.ts","../src/schedule.ts","../src/queue.ts","../src/dashboard.ts","../src/plugin-storage.ts","../src/schema.ts","../src/agent-protocol.ts","../src/index.ts"],"names":["randomUUID","policy","devices","createHmac"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * OpenMDM Core Types\n *\n * These types define the core data structures for the MDM system.\n * Designed to be database-agnostic and framework-agnostic.\n */\n\n// ============================================\n// Device Types\n// ============================================\n\nexport type DeviceStatus = 'pending' | 'enrolled' | 'unenrolled' | 'blocked';\n\nexport interface Device {\n id: string;\n externalId?: string | null;\n enrollmentId: string;\n status: DeviceStatus;\n\n // Device Info\n model?: string | null;\n manufacturer?: string | null;\n osVersion?: string | null;\n serialNumber?: string | null;\n imei?: string | null;\n macAddress?: string | null;\n androidId?: string | null;\n\n // MDM State\n policyId?: string | null;\n agentVersion?: string | null; // MDM agent version installed on device\n lastHeartbeat?: Date | null;\n lastSync?: Date | null;\n\n // Telemetry\n batteryLevel?: number | null;\n storageUsed?: number | null;\n storageTotal?: number | null;\n location?: DeviceLocation | null;\n installedApps?: InstalledApp[] | null;\n\n // Metadata\n tags?: Record<string, string> | null;\n metadata?: Record<string, unknown> | null;\n\n // Timestamps\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface DeviceLocation {\n latitude: number;\n longitude: number;\n accuracy?: number;\n timestamp: Date;\n}\n\nexport interface InstalledApp {\n packageName: string;\n version: string;\n versionCode?: number;\n installedAt?: Date;\n}\n\nexport interface CreateDeviceInput {\n enrollmentId: string;\n externalId?: string;\n model?: string;\n manufacturer?: string;\n osVersion?: string;\n serialNumber?: string;\n imei?: string;\n macAddress?: string;\n androidId?: string;\n policyId?: string;\n tags?: Record<string, string>;\n metadata?: Record<string, unknown>;\n}\n\nexport interface UpdateDeviceInput {\n externalId?: string | null;\n status?: DeviceStatus;\n policyId?: string | null;\n agentVersion?: string | null;\n model?: string;\n manufacturer?: string;\n osVersion?: string;\n batteryLevel?: number | null;\n storageUsed?: number | null;\n storageTotal?: number | null;\n lastHeartbeat?: Date;\n lastSync?: Date;\n installedApps?: InstalledApp[];\n location?: DeviceLocation;\n tags?: Record<string, string>;\n metadata?: Record<string, unknown>;\n}\n\nexport interface DeviceFilter {\n status?: DeviceStatus | DeviceStatus[];\n policyId?: string;\n groupId?: string;\n search?: string;\n tags?: Record<string, string>;\n limit?: number;\n offset?: number;\n}\n\nexport interface DeviceListResult {\n devices: Device[];\n total: number;\n limit: number;\n offset: number;\n}\n\n// ============================================\n// Policy Types\n// ============================================\n\nexport interface Policy {\n id: string;\n name: string;\n description?: string | null;\n isDefault: boolean;\n settings: PolicySettings;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface PolicySettings {\n // Kiosk Mode\n kioskMode?: boolean;\n mainApp?: string;\n allowedApps?: string[];\n kioskExitPassword?: string;\n\n // Lock Features\n lockStatusBar?: boolean;\n lockNavigationBar?: boolean;\n lockSettings?: boolean;\n lockPowerButton?: boolean;\n blockInstall?: boolean;\n blockUninstall?: boolean;\n\n // Hardware Controls\n bluetooth?: HardwareControl;\n wifi?: HardwareControl;\n gps?: HardwareControl;\n mobileData?: HardwareControl;\n camera?: HardwareControl;\n microphone?: HardwareControl;\n usb?: HardwareControl;\n nfc?: HardwareControl;\n\n // Update Settings\n systemUpdatePolicy?: SystemUpdatePolicy;\n updateWindow?: TimeWindow;\n\n // Security\n passwordPolicy?: PasswordPolicy;\n encryptionRequired?: boolean;\n factoryResetProtection?: boolean;\n safeBootDisabled?: boolean;\n\n // Telemetry\n heartbeatInterval?: number;\n locationReportInterval?: number;\n locationEnabled?: boolean;\n\n // Network\n wifiConfigs?: WifiConfig[];\n vpnConfig?: VpnConfig;\n\n // Applications\n applications?: PolicyApplication[];\n\n // Custom settings (for plugins)\n custom?: Record<string, unknown>;\n}\n\nexport type HardwareControl = 'on' | 'off' | 'user';\nexport type SystemUpdatePolicy = 'auto' | 'windowed' | 'postpone' | 'manual';\n\nexport interface TimeWindow {\n start: string; // \"HH:MM\"\n end: string; // \"HH:MM\"\n}\n\nexport interface PasswordPolicy {\n required: boolean;\n minLength?: number;\n complexity?: 'none' | 'numeric' | 'alphanumeric' | 'complex';\n maxFailedAttempts?: number;\n expirationDays?: number;\n historyLength?: number;\n}\n\nexport interface WifiConfig {\n ssid: string;\n securityType: 'none' | 'wep' | 'wpa' | 'wpa2' | 'wpa3';\n password?: string;\n hidden?: boolean;\n autoConnect?: boolean;\n}\n\nexport interface VpnConfig {\n type: 'pptp' | 'l2tp' | 'ipsec' | 'openvpn' | 'wireguard';\n server: string;\n username?: string;\n password?: string;\n certificate?: string;\n config?: Record<string, unknown>;\n}\n\nexport interface PolicyApplication {\n packageName: string;\n action: 'install' | 'update' | 'uninstall';\n version?: string;\n required?: boolean;\n autoUpdate?: boolean;\n}\n\nexport interface CreatePolicyInput {\n name: string;\n description?: string;\n isDefault?: boolean;\n settings: PolicySettings;\n}\n\nexport interface UpdatePolicyInput {\n name?: string;\n description?: string | null;\n isDefault?: boolean;\n settings?: PolicySettings;\n}\n\n// ============================================\n// Application Types\n// ============================================\n\nexport interface Application {\n id: string;\n name: string;\n packageName: string;\n version: string;\n versionCode: number;\n url: string;\n hash?: string | null;\n size?: number | null;\n minSdkVersion?: number | null;\n\n // Deployment settings\n showIcon: boolean;\n runAfterInstall: boolean;\n runAtBoot: boolean;\n isSystem: boolean;\n\n // State\n isActive: boolean;\n\n // Metadata\n metadata?: Record<string, unknown> | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface CreateApplicationInput {\n name: string;\n packageName: string;\n version: string;\n versionCode: number;\n url: string;\n hash?: string;\n size?: number;\n minSdkVersion?: number;\n showIcon?: boolean;\n runAfterInstall?: boolean;\n runAtBoot?: boolean;\n isSystem?: boolean;\n metadata?: Record<string, unknown>;\n}\n\nexport interface UpdateApplicationInput {\n name?: string;\n version?: string;\n versionCode?: number;\n url?: string;\n hash?: string | null;\n size?: number | null;\n minSdkVersion?: number | null;\n showIcon?: boolean;\n runAfterInstall?: boolean;\n runAtBoot?: boolean;\n isActive?: boolean;\n metadata?: Record<string, unknown> | null;\n}\n\nexport interface DeployTarget {\n devices?: string[];\n policies?: string[];\n groups?: string[];\n}\n\n// ============================================\n// App Version & Rollback Types\n// ============================================\n\nexport interface AppVersion {\n id: string;\n applicationId: string;\n packageName: string;\n version: string;\n versionCode: number;\n url: string;\n hash?: string | null;\n size?: number | null;\n releaseNotes?: string | null;\n isMinimumVersion: boolean;\n createdAt: Date;\n}\n\nexport interface AppRollback {\n id: string;\n deviceId: string;\n packageName: string;\n fromVersion: string;\n fromVersionCode: number;\n toVersion: string;\n toVersionCode: number;\n reason?: string | null;\n status: 'pending' | 'in_progress' | 'completed' | 'failed';\n error?: string | null;\n initiatedBy?: string | null;\n createdAt: Date;\n completedAt?: Date | null;\n}\n\nexport interface CreateAppRollbackInput {\n deviceId: string;\n packageName: string;\n toVersionCode: number;\n reason?: string;\n initiatedBy?: string;\n}\n\n// ============================================\n// Command Types\n// ============================================\n\nexport type CommandType =\n | 'reboot'\n | 'shutdown'\n | 'sync'\n | 'lock'\n | 'unlock'\n | 'wipe'\n | 'factoryReset'\n | 'installApp'\n | 'uninstallApp'\n | 'updateApp'\n | 'runApp'\n | 'clearAppData'\n | 'clearAppCache'\n | 'shell'\n | 'setPolicy'\n | 'grantPermissions'\n | 'exitKiosk'\n | 'enterKiosk'\n | 'setWifi'\n | 'screenshot'\n | 'getLocation'\n | 'setVolume'\n | 'sendNotification'\n | 'whitelistBattery' // Whitelist app from battery optimization (Doze)\n | 'enablePermissiveMode' // Enable permissive mode for debugging\n | 'setTimeZone' // Set device timezone\n | 'enableAdb' // Enable/disable ADB debugging\n | 'rollbackApp' // Rollback to previous app version\n | 'updateAgent' // Update MDM agent to a new version\n | 'custom';\n\nexport type CommandStatus =\n | 'pending'\n | 'sent'\n | 'acknowledged'\n | 'completed'\n | 'failed'\n | 'cancelled';\n\nexport interface Command {\n id: string;\n deviceId: string;\n type: CommandType;\n payload?: Record<string, unknown> | null;\n status: CommandStatus;\n result?: CommandResult | null;\n error?: string | null;\n createdAt: Date;\n sentAt?: Date | null;\n acknowledgedAt?: Date | null;\n completedAt?: Date | null;\n}\n\nexport interface CommandResult {\n success: boolean;\n message?: string;\n data?: unknown;\n}\n\nexport interface SendCommandInput {\n deviceId: string;\n type: CommandType;\n payload?: Record<string, unknown>;\n}\n\nexport interface CommandFilter {\n deviceId?: string;\n status?: CommandStatus | CommandStatus[];\n type?: CommandType | CommandType[];\n limit?: number;\n offset?: number;\n}\n\n// ============================================\n// Event Types\n// ============================================\n\nexport type EventType =\n | 'device.enrolled'\n | 'device.unenrolled'\n | 'device.blocked'\n | 'device.heartbeat'\n | 'device.locationUpdated'\n | 'device.statusChanged'\n | 'device.policyChanged'\n | 'app.installed'\n | 'app.uninstalled'\n | 'app.updated'\n | 'app.crashed'\n | 'app.started'\n | 'app.stopped'\n | 'policy.applied'\n | 'policy.failed'\n | 'command.received'\n | 'command.acknowledged'\n | 'command.completed'\n | 'command.failed'\n | 'security.tamper'\n | 'security.rootDetected'\n | 'security.screenLocked'\n | 'security.screenUnlocked'\n | 'custom';\n\nexport interface MDMEvent<T = unknown> {\n id: string;\n deviceId: string;\n type: EventType;\n payload: T;\n createdAt: Date;\n}\n\nexport interface EventFilter {\n deviceId?: string;\n type?: EventType | EventType[];\n startDate?: Date;\n endDate?: Date;\n limit?: number;\n offset?: number;\n}\n\n// ============================================\n// Group Types\n// ============================================\n\nexport interface Group {\n id: string;\n name: string;\n description?: string | null;\n policyId?: string | null;\n parentId?: string | null;\n metadata?: Record<string, unknown> | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface CreateGroupInput {\n name: string;\n description?: string;\n policyId?: string;\n parentId?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface UpdateGroupInput {\n name?: string;\n description?: string | null;\n policyId?: string | null;\n parentId?: string | null;\n metadata?: Record<string, unknown> | null;\n}\n\n// ============================================\n// Enrollment Types\n// ============================================\n\nexport type EnrollmentMethod =\n | 'qr'\n | 'nfc'\n | 'zero-touch'\n | 'knox'\n | 'manual'\n | 'app-only'\n | 'adb';\n\nexport interface EnrollmentRequest {\n // Device identifiers (at least one required)\n macAddress?: string;\n serialNumber?: string;\n imei?: string;\n androidId?: string;\n\n // Device info\n model: string;\n manufacturer: string;\n osVersion: string;\n sdkVersion?: number;\n\n // Agent info\n agentVersion?: string;\n agentPackage?: string;\n\n // Enrollment details\n method: EnrollmentMethod;\n timestamp: string;\n signature: string;\n\n // Optional pre-assigned policy/group\n policyId?: string;\n groupId?: string;\n}\n\nexport interface EnrollmentResponse {\n deviceId: string;\n enrollmentId: string;\n policyId?: string;\n policy?: Policy;\n serverUrl: string;\n pushConfig: PushConfig;\n token: string;\n refreshToken?: string;\n tokenExpiresAt?: Date;\n}\n\nexport interface PushConfig {\n provider: 'fcm' | 'mqtt' | 'websocket' | 'polling';\n fcmSenderId?: string;\n mqttUrl?: string;\n mqttTopic?: string;\n mqttUsername?: string;\n mqttPassword?: string;\n wsUrl?: string;\n pollingInterval?: number;\n}\n\n// ============================================\n// Telemetry Types\n// ============================================\n\nexport interface Heartbeat {\n deviceId: string;\n timestamp: Date;\n\n // Battery\n batteryLevel: number;\n isCharging: boolean;\n batteryHealth?: 'good' | 'overheat' | 'dead' | 'cold' | 'unknown';\n\n // Storage\n storageUsed: number;\n storageTotal: number;\n\n // Memory\n memoryUsed: number;\n memoryTotal: number;\n\n // Network\n networkType?: 'wifi' | 'cellular' | 'ethernet' | 'none';\n networkName?: string; // SSID or carrier\n signalStrength?: number;\n ipAddress?: string;\n\n // Location\n location?: DeviceLocation;\n\n // Apps\n installedApps: InstalledApp[];\n runningApps?: string[];\n\n // Security\n isRooted?: boolean;\n isEncrypted?: boolean;\n screenLockEnabled?: boolean;\n\n // Agent status\n agentVersion?: string;\n policyVersion?: string;\n lastPolicySync?: Date;\n}\n\n// ============================================\n// Push Token Types\n// ============================================\n\nexport interface PushToken {\n id: string;\n deviceId: string;\n provider: 'fcm' | 'mqtt' | 'websocket';\n token: string;\n isActive: boolean;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface RegisterPushTokenInput {\n deviceId: string;\n provider: 'fcm' | 'mqtt' | 'websocket';\n token: string;\n}\n\n// ============================================\n// Configuration Types\n// ============================================\n\nexport interface MDMConfig {\n /** Database adapter for persistence */\n database: DatabaseAdapter;\n\n /** Authentication/authorization configuration */\n auth?: AuthConfig;\n\n /** Push notification provider configuration */\n push?: PushProviderConfig;\n\n /** Device enrollment configuration */\n enrollment?: EnrollmentConfig;\n\n /** Server URL (used in enrollment responses) */\n serverUrl?: string;\n\n /** APK/file storage configuration */\n storage?: StorageConfig;\n\n /** Outbound webhook configuration */\n webhooks?: WebhookConfig;\n\n /** Plugins to extend functionality */\n plugins?: MDMPlugin[];\n\n /** Event handlers */\n onDeviceEnrolled?: (device: Device) => Promise<void>;\n onDeviceUnenrolled?: (device: Device) => Promise<void>;\n onDeviceBlocked?: (device: Device) => Promise<void>;\n onHeartbeat?: (device: Device, heartbeat: Heartbeat) => Promise<void>;\n onCommand?: (command: Command) => Promise<void>;\n onEvent?: (event: MDMEvent) => Promise<void>;\n\n // Enterprise features\n /** Multi-tenancy configuration */\n multiTenancy?: {\n enabled: boolean;\n defaultTenantId?: string;\n tenantResolver?: (context: unknown) => Promise<string | null>;\n };\n\n /** Authorization (RBAC) configuration */\n authorization?: {\n enabled: boolean;\n defaultRole?: string;\n };\n\n /** Audit logging configuration */\n audit?: {\n enabled: boolean;\n retentionDays?: number;\n };\n\n /** Scheduling configuration */\n scheduling?: {\n enabled: boolean;\n timezone?: string;\n };\n\n /** Plugin storage configuration */\n pluginStorage?: {\n adapter: 'database' | 'memory';\n };\n\n /**\n * Structured logger. Replaces OpenMDM's internal `console.*` calls\n * so log output lands in the host application's logging pipeline\n * (pino, winston, bunyan, OTEL collector, etc.) instead of raw\n * stderr.\n *\n * The shape is a strict subset of the pino / winston / bunyan\n * interface — any of those can be passed directly. If omitted, a\n * default logger that writes to the console with an `[openmdm]`\n * prefix is used. To silence OpenMDM entirely, pass a no-op\n * implementation (see `createSilentLogger()` in the package\n * exports).\n */\n logger?: Logger;\n}\n\n/**\n * Minimal structured-logger interface OpenMDM calls internally.\n *\n * The shape is deliberately the pino-compatible subset: an optional\n * context object as the first argument followed by a message string.\n * pino, winston, bunyan, and most other structured loggers accept\n * this shape natively.\n *\n * Implementations should be side-effect-free on unconfigured levels\n * (a production logger filtered to `info` should still accept\n * `.debug()` calls cheaply).\n */\nexport interface Logger {\n /** Human-ignorable, high-volume tracing. Off in production by default. */\n debug(context: LogContext, message: string): void;\n debug(message: string): void;\n\n /** Normal operational events. Enrollment, policy changes, command delivery. */\n info(context: LogContext, message: string): void;\n info(message: string): void;\n\n /** Something is wrong but the server is still running. Retries, fallbacks, degraded modes. */\n warn(context: LogContext, message: string): void;\n warn(message: string): void;\n\n /** Something failed and a request/operation did not complete. */\n error(context: LogContext, message: string): void;\n error(message: string): void;\n\n /**\n * Return a new logger with the given fields attached to every\n * subsequent call. Used by managers and plugins to scope logs to\n * a specific subsystem without repeating context.\n */\n child(bindings: LogContext): Logger;\n}\n\n/**\n * Arbitrary structured context attached to a log line. Values must\n * be JSON-serializable so host loggers can ship them to any backend.\n */\nexport type LogContext = Record<string, unknown>;\n\nexport interface StorageConfig {\n /** Storage provider (s3, local, custom) */\n provider: 's3' | 'local' | 'custom';\n\n /** S3 configuration */\n s3?: {\n bucket: string;\n region: string;\n accessKeyId?: string;\n secretAccessKey?: string;\n endpoint?: string; // For S3-compatible services\n presignedUrlExpiry?: number; // Seconds, default 3600\n };\n\n /** Local storage path */\n localPath?: string;\n\n /** Custom storage adapter */\n customAdapter?: {\n upload: (file: Buffer, key: string) => Promise<string>;\n getUrl: (key: string) => Promise<string>;\n delete: (key: string) => Promise<void>;\n };\n}\n\nexport interface WebhookConfig {\n /** Webhook endpoints to notify */\n endpoints?: WebhookEndpoint[];\n\n /** Retry configuration */\n retry?: {\n maxRetries?: number;\n initialDelay?: number;\n maxDelay?: number;\n };\n\n /** Sign webhooks with HMAC secret */\n signingSecret?: string;\n}\n\nexport interface WebhookEndpoint {\n /** Unique identifier */\n id: string;\n /** Webhook URL */\n url: string;\n /** Events to trigger this webhook */\n events: (EventType | '*')[];\n /** Custom headers */\n headers?: Record<string, string>;\n /** Whether endpoint is active */\n enabled: boolean;\n}\n\nexport interface AuthConfig {\n /** Get current user from request context */\n getUser: <T = unknown>(context: unknown) => Promise<T | null>;\n /** Check if user has admin privileges */\n isAdmin?: (user: unknown) => Promise<boolean>;\n /** Check if user can access specific device */\n canAccessDevice?: (user: unknown, deviceId: string) => Promise<boolean>;\n /** Device JWT secret (for device auth tokens) */\n deviceTokenSecret?: string;\n /** Device token expiration in seconds (default: 365 days) */\n deviceTokenExpiration?: number;\n}\n\nexport interface PushProviderConfig {\n provider: 'fcm' | 'mqtt' | 'websocket' | 'polling';\n\n // FCM configuration\n fcmCredentials?: string | Record<string, unknown>;\n fcmProjectId?: string;\n\n // MQTT configuration\n mqttUrl?: string;\n mqttUsername?: string;\n mqttPassword?: string;\n mqttTopicPrefix?: string;\n\n // WebSocket configuration\n wsPath?: string;\n wsPingInterval?: number;\n\n // Polling fallback\n pollingInterval?: number;\n}\n\nexport interface EnrollmentConfig {\n /** Auto-enroll devices with valid signature */\n autoEnroll?: boolean;\n /** HMAC secret for device signature verification */\n deviceSecret: string;\n /** Allowed enrollment methods */\n allowedMethods?: EnrollmentMethod[];\n /** Default policy for new devices */\n defaultPolicyId?: string;\n /** Default group for new devices */\n defaultGroupId?: string;\n /** Require manual approval for enrollment */\n requireApproval?: boolean;\n /** Custom enrollment validation */\n validate?: (request: EnrollmentRequest) => Promise<boolean>;\n}\n\n// ============================================\n// Adapter Interfaces\n// ============================================\n\nexport interface DatabaseAdapter {\n // Devices\n findDevice(id: string): Promise<Device | null>;\n findDeviceByEnrollmentId(enrollmentId: string): Promise<Device | null>;\n listDevices(filter?: DeviceFilter): Promise<DeviceListResult>;\n createDevice(data: CreateDeviceInput): Promise<Device>;\n updateDevice(id: string, data: UpdateDeviceInput): Promise<Device>;\n deleteDevice(id: string): Promise<void>;\n countDevices(filter?: DeviceFilter): Promise<number>;\n\n // Policies\n findPolicy(id: string): Promise<Policy | null>;\n findDefaultPolicy(): Promise<Policy | null>;\n listPolicies(): Promise<Policy[]>;\n createPolicy(data: CreatePolicyInput): Promise<Policy>;\n updatePolicy(id: string, data: UpdatePolicyInput): Promise<Policy>;\n deletePolicy(id: string): Promise<void>;\n\n // Applications\n findApplication(id: string): Promise<Application | null>;\n findApplicationByPackage(packageName: string, version?: string): Promise<Application | null>;\n listApplications(activeOnly?: boolean): Promise<Application[]>;\n createApplication(data: CreateApplicationInput): Promise<Application>;\n updateApplication(id: string, data: UpdateApplicationInput): Promise<Application>;\n deleteApplication(id: string): Promise<void>;\n\n // Commands\n findCommand(id: string): Promise<Command | null>;\n listCommands(filter?: CommandFilter): Promise<Command[]>;\n createCommand(data: SendCommandInput): Promise<Command>;\n updateCommand(id: string, data: Partial<Command>): Promise<Command | null>;\n getPendingCommands(deviceId: string): Promise<Command[]>;\n\n // Events\n createEvent(event: Omit<MDMEvent, 'id' | 'createdAt'>): Promise<MDMEvent>;\n listEvents(filter?: EventFilter): Promise<MDMEvent[]>;\n\n // Groups\n findGroup(id: string): Promise<Group | null>;\n listGroups(): Promise<Group[]>;\n createGroup(data: CreateGroupInput): Promise<Group>;\n updateGroup(id: string, data: UpdateGroupInput): Promise<Group>;\n deleteGroup(id: string): Promise<void>;\n listDevicesInGroup(groupId: string): Promise<Device[]>;\n addDeviceToGroup(deviceId: string, groupId: string): Promise<void>;\n removeDeviceFromGroup(deviceId: string, groupId: string): Promise<void>;\n getDeviceGroups(deviceId: string): Promise<Group[]>;\n\n // Push Tokens\n findPushToken(deviceId: string, provider: string): Promise<PushToken | null>;\n upsertPushToken(data: RegisterPushTokenInput): Promise<PushToken>;\n deletePushToken(deviceId: string, provider?: string): Promise<void>;\n\n // App Versions (optional - for version tracking)\n listAppVersions?(packageName: string): Promise<AppVersion[]>;\n createAppVersion?(data: Omit<AppVersion, 'id' | 'createdAt'>): Promise<AppVersion>;\n setMinimumVersion?(packageName: string, versionCode: number): Promise<void>;\n getMinimumVersion?(packageName: string): Promise<AppVersion | null>;\n\n // Rollback History (optional)\n createRollback?(data: CreateAppRollbackInput): Promise<AppRollback>;\n updateRollback?(id: string, data: Partial<AppRollback>): Promise<AppRollback>;\n listRollbacks?(filter?: { deviceId?: string; packageName?: string }): Promise<AppRollback[]>;\n\n // Group Hierarchy (optional)\n getGroupChildren?(parentId: string | null): Promise<Group[]>;\n getGroupAncestors?(groupId: string): Promise<Group[]>;\n getGroupDescendants?(groupId: string): Promise<Group[]>;\n getGroupTree?(rootId?: string): Promise<GroupTreeNode[]>;\n getGroupEffectivePolicy?(groupId: string): Promise<Policy | null>;\n moveGroup?(groupId: string, newParentId: string | null): Promise<Group>;\n getGroupHierarchyStats?(): Promise<GroupHierarchyStats>;\n\n // Tenants (optional - for multi-tenancy)\n findTenant?(id: string): Promise<Tenant | null>;\n findTenantBySlug?(slug: string): Promise<Tenant | null>;\n listTenants?(filter?: TenantFilter): Promise<TenantListResult>;\n createTenant?(data: CreateTenantInput): Promise<Tenant>;\n updateTenant?(id: string, data: UpdateTenantInput): Promise<Tenant>;\n deleteTenant?(id: string): Promise<void>;\n getTenantStats?(tenantId: string): Promise<TenantStats>;\n\n // Users (optional - for RBAC)\n findUser?(id: string): Promise<User | null>;\n findUserByEmail?(email: string, tenantId?: string): Promise<User | null>;\n listUsers?(filter?: UserFilter): Promise<UserListResult>;\n createUser?(data: CreateUserInput): Promise<User>;\n updateUser?(id: string, data: UpdateUserInput): Promise<User>;\n deleteUser?(id: string): Promise<void>;\n\n // Roles (optional - for RBAC)\n findRole?(id: string): Promise<Role | null>;\n listRoles?(tenantId?: string): Promise<Role[]>;\n createRole?(data: CreateRoleInput): Promise<Role>;\n updateRole?(id: string, data: UpdateRoleInput): Promise<Role>;\n deleteRole?(id: string): Promise<void>;\n assignRoleToUser?(userId: string, roleId: string): Promise<void>;\n removeRoleFromUser?(userId: string, roleId: string): Promise<void>;\n getUserRoles?(userId: string): Promise<Role[]>;\n\n // Audit Logs (optional - for compliance)\n createAuditLog?(data: CreateAuditLogInput): Promise<AuditLog>;\n listAuditLogs?(filter?: AuditLogFilter): Promise<AuditLogListResult>;\n deleteAuditLogs?(filter: { olderThan?: Date; tenantId?: string }): Promise<number>;\n\n // Scheduled Tasks (optional - for scheduling)\n findScheduledTask?(id: string): Promise<ScheduledTask | null>;\n listScheduledTasks?(filter?: ScheduledTaskFilter): Promise<ScheduledTaskListResult>;\n createScheduledTask?(data: CreateScheduledTaskInput): Promise<ScheduledTask>;\n updateScheduledTask?(id: string, data: UpdateScheduledTaskInput): Promise<ScheduledTask>;\n deleteScheduledTask?(id: string): Promise<void>;\n getUpcomingTasks?(hours: number): Promise<ScheduledTask[]>;\n createTaskExecution?(data: { taskId: string }): Promise<TaskExecution>;\n updateTaskExecution?(id: string, data: Partial<TaskExecution>): Promise<TaskExecution>;\n listTaskExecutions?(taskId: string, limit?: number): Promise<TaskExecution[]>;\n\n // Message Queue (optional - for persistent messaging)\n enqueueMessage?(data: EnqueueMessageInput): Promise<QueuedMessage>;\n dequeueMessages?(deviceId: string, limit?: number): Promise<QueuedMessage[]>;\n peekMessages?(deviceId: string, limit?: number): Promise<QueuedMessage[]>;\n acknowledgeMessage?(messageId: string): Promise<void>;\n failMessage?(messageId: string, error: string): Promise<void>;\n retryFailedMessages?(maxAttempts?: number): Promise<number>;\n purgeExpiredMessages?(): Promise<number>;\n getQueueStats?(tenantId?: string): Promise<QueueStats>;\n\n // Plugin Storage (optional)\n getPluginValue?(pluginName: string, key: string): Promise<unknown | null>;\n setPluginValue?(pluginName: string, key: string, value: unknown): Promise<void>;\n deletePluginValue?(pluginName: string, key: string): Promise<void>;\n listPluginKeys?(pluginName: string, prefix?: string): Promise<string[]>;\n clearPluginData?(pluginName: string): Promise<void>;\n\n // Dashboard (optional - for analytics)\n getDashboardStats?(tenantId?: string): Promise<DashboardStats>;\n getDeviceStatusBreakdown?(tenantId?: string): Promise<DeviceStatusBreakdown>;\n getEnrollmentTrend?(days: number, tenantId?: string): Promise<EnrollmentTrendPoint[]>;\n getCommandSuccessRates?(tenantId?: string): Promise<CommandSuccessRates>;\n getAppInstallationSummary?(tenantId?: string): Promise<AppInstallationSummary>;\n\n // Transactions (optional)\n transaction?<T>(fn: () => Promise<T>): Promise<T>;\n}\n\nexport interface PushAdapter {\n /** Send push message to a device */\n send(deviceId: string, message: PushMessage): Promise<PushResult>;\n /** Send push message to multiple devices */\n sendBatch(deviceIds: string[], message: PushMessage): Promise<PushBatchResult>;\n /** Register device push token */\n registerToken?(deviceId: string, token: string): Promise<void>;\n /** Unregister device push token */\n unregisterToken?(deviceId: string): Promise<void>;\n /** Subscribe device to topic */\n subscribe?(deviceId: string, topic: string): Promise<void>;\n /** Unsubscribe device from topic */\n unsubscribe?(deviceId: string, topic: string): Promise<void>;\n}\n\nexport interface PushMessage {\n type: string;\n payload?: Record<string, unknown>;\n priority?: 'high' | 'normal';\n ttl?: number;\n collapseKey?: string;\n}\n\nexport interface PushResult {\n success: boolean;\n messageId?: string;\n error?: string;\n}\n\nexport interface PushBatchResult {\n successCount: number;\n failureCount: number;\n results: Array<{ deviceId: string; result: PushResult }>;\n}\n\n// ============================================\n// Plugin Interface\n// ============================================\n\nexport interface MDMPlugin {\n /** Unique plugin name */\n name: string;\n /** Plugin version */\n version: string;\n\n /** Called when MDM is initialized */\n onInit?(mdm: MDMInstance): Promise<void>;\n\n /** Called when MDM is destroyed */\n onDestroy?(): Promise<void>;\n\n /** Additional routes to mount */\n routes?: PluginRoute[];\n\n /** Middleware to apply to all routes */\n middleware?: PluginMiddleware[];\n\n /** Extend enrollment process */\n onEnroll?(device: Device, request: EnrollmentRequest): Promise<void>;\n\n /** Extend device processing */\n onDeviceEnrolled?(device: Device): Promise<void>;\n onDeviceUnenrolled?(device: Device): Promise<void>;\n onHeartbeat?(device: Device, heartbeat: Heartbeat): Promise<void>;\n\n /** Extend policy processing */\n policySchema?: Record<string, unknown>;\n validatePolicy?(settings: PolicySettings): Promise<{ valid: boolean; errors?: string[] }>;\n applyPolicy?(device: Device, policy: Policy): Promise<void>;\n\n /** Extend command processing */\n commandTypes?: CommandType[];\n executeCommand?(device: Device, command: Command): Promise<CommandResult>;\n}\n\nexport interface PluginRoute {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n path: string;\n handler: (context: unknown) => Promise<unknown>;\n auth?: boolean;\n admin?: boolean;\n}\n\nexport type PluginMiddleware = (\n context: unknown,\n next: () => Promise<unknown>\n) => Promise<unknown>;\n\n// ============================================\n// MDM Instance Interface\n// ============================================\n\nexport interface WebhookManager {\n /** Deliver an event to all matching webhook endpoints */\n deliver<T>(event: MDMEvent<T>): Promise<WebhookDeliveryResult[]>;\n /** Add a webhook endpoint at runtime */\n addEndpoint(endpoint: WebhookEndpoint): void;\n /** Remove a webhook endpoint */\n removeEndpoint(endpointId: string): void;\n /** Update a webhook endpoint */\n updateEndpoint(endpointId: string, updates: Partial<WebhookEndpoint>): void;\n /** Get all configured endpoints */\n getEndpoints(): WebhookEndpoint[];\n /** Test a webhook endpoint with a test payload */\n testEndpoint(endpointId: string): Promise<WebhookDeliveryResult>;\n}\n\nexport interface WebhookDeliveryResult {\n endpointId: string;\n success: boolean;\n statusCode?: number;\n error?: string;\n retryCount: number;\n deliveredAt?: Date;\n}\n\nexport interface MDMInstance {\n /** Device management */\n devices: DeviceManager;\n /** Policy management */\n policies: PolicyManager;\n /** Application management */\n apps: ApplicationManager;\n /** Command management */\n commands: CommandManager;\n /** Group management */\n groups: GroupManager;\n\n /** Tenant management (if multi-tenancy enabled) */\n tenants?: TenantManager;\n /** Authorization management (RBAC) */\n authorization?: AuthorizationManager;\n /** Audit logging */\n audit?: AuditManager;\n /** Scheduled task management */\n schedules?: ScheduleManager;\n /** Persistent message queue */\n messageQueue?: MessageQueueManager;\n /** Dashboard analytics */\n dashboard?: DashboardManager;\n /** Plugin storage */\n pluginStorage?: PluginStorageAdapter;\n\n /** Push notification service */\n push: PushAdapter;\n\n /** Webhook delivery (if configured) */\n webhooks?: WebhookManager;\n\n /** Database adapter */\n db: DatabaseAdapter;\n\n /** Structured logger. Already scoped to the `openmdm` namespace. Plugins should call `.child({...})` to scope further. */\n logger: Logger;\n\n /** Configuration */\n config: MDMConfig;\n\n /** Subscribe to events */\n on<T extends EventType>(event: T, handler: EventHandler<T>): () => void;\n /** Emit an event */\n emit<T extends EventType>(event: T, data: EventPayloadMap[T]): Promise<void>;\n\n /** Process device enrollment */\n enroll(request: EnrollmentRequest): Promise<EnrollmentResponse>;\n /** Process device heartbeat */\n processHeartbeat(deviceId: string, heartbeat: Heartbeat): Promise<void>;\n /** Verify device token */\n verifyDeviceToken(token: string): Promise<{ deviceId: string } | null>;\n\n /** Get loaded plugins */\n getPlugins(): MDMPlugin[];\n /** Get plugin by name */\n getPlugin(name: string): MDMPlugin | undefined;\n}\n\n// ============================================\n// Manager Interfaces\n// ============================================\n\nexport interface DeviceManager {\n get(id: string): Promise<Device | null>;\n getByEnrollmentId(enrollmentId: string): Promise<Device | null>;\n list(filter?: DeviceFilter): Promise<DeviceListResult>;\n create(data: CreateDeviceInput): Promise<Device>;\n update(id: string, data: UpdateDeviceInput): Promise<Device>;\n delete(id: string): Promise<void>;\n assignPolicy(deviceId: string, policyId: string | null): Promise<Device>;\n addToGroup(deviceId: string, groupId: string): Promise<void>;\n removeFromGroup(deviceId: string, groupId: string): Promise<void>;\n getGroups(deviceId: string): Promise<Group[]>;\n sendCommand(deviceId: string, input: Omit<SendCommandInput, 'deviceId'>): Promise<Command>;\n sync(deviceId: string): Promise<Command>;\n reboot(deviceId: string): Promise<Command>;\n lock(deviceId: string, message?: string): Promise<Command>;\n wipe(deviceId: string, preserveData?: boolean): Promise<Command>;\n}\n\nexport interface PolicyManager {\n get(id: string): Promise<Policy | null>;\n getDefault(): Promise<Policy | null>;\n list(): Promise<Policy[]>;\n create(data: CreatePolicyInput): Promise<Policy>;\n update(id: string, data: UpdatePolicyInput): Promise<Policy>;\n delete(id: string): Promise<void>;\n setDefault(id: string): Promise<Policy>;\n getDevices(policyId: string): Promise<Device[]>;\n applyToDevice(policyId: string, deviceId: string): Promise<void>;\n}\n\nexport interface ApplicationManager {\n get(id: string): Promise<Application | null>;\n getByPackage(packageName: string, version?: string): Promise<Application | null>;\n list(activeOnly?: boolean): Promise<Application[]>;\n register(data: CreateApplicationInput): Promise<Application>;\n update(id: string, data: UpdateApplicationInput): Promise<Application>;\n delete(id: string): Promise<void>;\n activate(id: string): Promise<Application>;\n deactivate(id: string): Promise<Application>;\n deploy(packageName: string, target: DeployTarget): Promise<void>;\n installOnDevice(packageName: string, deviceId: string, version?: string): Promise<Command>;\n uninstallFromDevice(packageName: string, deviceId: string): Promise<Command>;\n}\n\nexport interface CommandManager {\n get(id: string): Promise<Command | null>;\n list(filter?: CommandFilter): Promise<Command[]>;\n send(input: SendCommandInput): Promise<Command>;\n cancel(id: string): Promise<Command>;\n acknowledge(id: string): Promise<Command>;\n complete(id: string, result: CommandResult): Promise<Command>;\n fail(id: string, error: string): Promise<Command>;\n getPending(deviceId: string): Promise<Command[]>;\n}\n\nexport interface GroupManager {\n // Basic CRUD operations\n get(id: string): Promise<Group | null>;\n list(): Promise<Group[]>;\n create(data: CreateGroupInput): Promise<Group>;\n update(id: string, data: UpdateGroupInput): Promise<Group>;\n delete(id: string): Promise<void>;\n\n // Device management\n getDevices(groupId: string): Promise<Device[]>;\n addDevice(groupId: string, deviceId: string): Promise<void>;\n removeDevice(groupId: string, deviceId: string): Promise<void>;\n\n // Hierarchy operations\n getChildren(groupId: string): Promise<Group[]>;\n getTree(rootId?: string): Promise<GroupTreeNode[]>;\n getAncestors(groupId: string): Promise<Group[]>;\n getDescendants(groupId: string): Promise<Group[]>;\n move(groupId: string, newParentId: string | null): Promise<Group>;\n getEffectivePolicy(groupId: string): Promise<Policy | null>;\n getHierarchyStats(): Promise<GroupHierarchyStats>;\n}\n\n// ============================================\n// Group Hierarchy Types\n// ============================================\n\nexport interface GroupTreeNode extends Group {\n children: GroupTreeNode[];\n depth: number;\n path: string[];\n effectivePolicyId?: string | null;\n}\n\nexport interface GroupHierarchyStats {\n totalGroups: number;\n maxDepth: number;\n groupsWithDevices: number;\n groupsWithPolicies: number;\n}\n\n// ============================================\n// Tenant Types (Multi-tenancy)\n// ============================================\n\nexport type TenantStatus = 'active' | 'suspended' | 'pending';\n\nexport interface Tenant {\n id: string;\n name: string;\n slug: string;\n status: TenantStatus;\n settings?: TenantSettings | null;\n metadata?: Record<string, unknown> | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface TenantSettings {\n maxDevices?: number;\n maxUsers?: number;\n features?: string[];\n branding?: {\n logo?: string;\n primaryColor?: string;\n };\n}\n\nexport interface CreateTenantInput {\n name: string;\n slug: string;\n settings?: TenantSettings;\n metadata?: Record<string, unknown>;\n}\n\nexport interface UpdateTenantInput {\n name?: string;\n slug?: string;\n status?: TenantStatus;\n settings?: TenantSettings;\n metadata?: Record<string, unknown>;\n}\n\nexport interface TenantFilter {\n status?: TenantStatus;\n search?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface TenantListResult {\n tenants: Tenant[];\n total: number;\n limit: number;\n offset: number;\n}\n\nexport interface TenantStats {\n deviceCount: number;\n userCount: number;\n policyCount: number;\n appCount: number;\n}\n\n// ============================================\n// RBAC Types (Role-Based Access Control)\n// ============================================\n\nexport type PermissionAction = 'create' | 'read' | 'update' | 'delete' | 'manage' | '*';\nexport type PermissionResource = 'devices' | 'policies' | 'apps' | 'groups' | 'commands' | 'users' | 'roles' | 'tenants' | 'audit' | '*';\n\nexport interface Permission {\n action: PermissionAction;\n resource: PermissionResource;\n resourceId?: string;\n}\n\nexport interface Role {\n id: string;\n tenantId?: string | null;\n name: string;\n description?: string | null;\n permissions: Permission[];\n isSystem: boolean;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface CreateRoleInput {\n tenantId?: string;\n name: string;\n description?: string;\n permissions: Permission[];\n}\n\nexport interface UpdateRoleInput {\n name?: string;\n description?: string;\n permissions?: Permission[];\n}\n\nexport interface User {\n id: string;\n tenantId?: string | null;\n email: string;\n name?: string | null;\n status: 'active' | 'inactive' | 'pending';\n metadata?: Record<string, unknown> | null;\n lastLoginAt?: Date | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface UserWithRoles extends User {\n roles: Role[];\n}\n\nexport interface CreateUserInput {\n tenantId?: string;\n email: string;\n name?: string;\n status?: 'active' | 'inactive' | 'pending';\n metadata?: Record<string, unknown>;\n}\n\nexport interface UpdateUserInput {\n email?: string;\n name?: string;\n status?: 'active' | 'inactive' | 'pending';\n metadata?: Record<string, unknown>;\n}\n\nexport interface UserFilter {\n tenantId?: string;\n status?: 'active' | 'inactive' | 'pending';\n search?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface UserListResult {\n users: User[];\n total: number;\n limit: number;\n offset: number;\n}\n\n// ============================================\n// Audit Types\n// ============================================\n\nexport type AuditAction = 'create' | 'read' | 'update' | 'delete' | 'login' | 'logout' | 'enroll' | 'unenroll' | 'command' | 'export' | 'import' | 'custom';\n\nexport interface AuditLog {\n id: string;\n tenantId?: string | null;\n userId?: string | null;\n action: AuditAction;\n resource: string;\n resourceId?: string | null;\n status: 'success' | 'failure';\n error?: string | null;\n details?: Record<string, unknown> | null;\n ipAddress?: string | null;\n userAgent?: string | null;\n createdAt: Date;\n}\n\nexport interface CreateAuditLogInput {\n tenantId?: string;\n userId?: string;\n action: AuditAction;\n resource: string;\n resourceId?: string;\n status?: 'success' | 'failure';\n error?: string;\n details?: Record<string, unknown>;\n ipAddress?: string;\n userAgent?: string;\n}\n\nexport interface AuditConfig {\n enabled: boolean;\n retentionDays?: number;\n skipReadOperations?: boolean;\n logActions?: AuditAction[];\n logResources?: string[];\n}\n\nexport interface AuditSummary {\n totalLogs: number;\n byAction: Record<AuditAction, number>;\n byResource: Record<string, number>;\n byStatus: { success: number; failure: number };\n topUsers: Array<{ userId: string; count: number }>;\n recentFailures: AuditLog[];\n}\n\nexport interface AuditLogFilter {\n tenantId?: string;\n userId?: string;\n action?: string;\n resource?: string;\n resourceId?: string;\n startDate?: Date;\n endDate?: Date;\n limit?: number;\n offset?: number;\n}\n\nexport interface AuditLogListResult {\n logs: AuditLog[];\n total: number;\n limit: number;\n offset: number;\n}\n\n// ============================================\n// Schedule Types\n// ============================================\n\nexport type TaskType = 'command' | 'policy_update' | 'app_install' | 'maintenance' | 'custom';\nexport type ScheduledTaskStatus = 'active' | 'paused' | 'completed' | 'failed';\n\nexport interface MaintenanceWindow {\n daysOfWeek: number[];\n startTime: string;\n endTime: string;\n timezone: string;\n}\n\nexport interface TaskSchedule {\n type: 'once' | 'recurring' | 'window';\n executeAt?: Date;\n cron?: string;\n window?: MaintenanceWindow;\n}\n\nexport interface ScheduledTask {\n id: string;\n tenantId?: string | null;\n name: string;\n description?: string | null;\n taskType: TaskType;\n schedule: TaskSchedule;\n target?: DeployTarget;\n payload?: Record<string, unknown> | null;\n status: ScheduledTaskStatus;\n nextRunAt?: Date | null;\n lastRunAt?: Date | null;\n maxRetries: number;\n retryCount: number;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface CreateScheduledTaskInput {\n tenantId?: string;\n name: string;\n description?: string;\n taskType: TaskType;\n schedule: TaskSchedule;\n target?: DeployTarget;\n payload?: Record<string, unknown>;\n maxRetries?: number;\n}\n\nexport interface UpdateScheduledTaskInput {\n name?: string;\n description?: string;\n schedule?: TaskSchedule;\n target?: DeployTarget;\n payload?: Record<string, unknown>;\n status?: ScheduledTaskStatus;\n maxRetries?: number;\n}\n\nexport interface ScheduledTaskFilter {\n tenantId?: string;\n taskType?: TaskType | TaskType[];\n status?: ScheduledTaskStatus | ScheduledTaskStatus[];\n limit?: number;\n offset?: number;\n}\n\nexport interface ScheduledTaskListResult {\n tasks: ScheduledTask[];\n total: number;\n limit: number;\n offset: number;\n}\n\nexport interface TaskExecution {\n id: string;\n taskId: string;\n status: 'running' | 'completed' | 'failed';\n startedAt: Date;\n completedAt?: Date | null;\n devicesProcessed: number;\n devicesSucceeded: number;\n devicesFailed: number;\n error?: string | null;\n details?: Record<string, unknown> | null;\n}\n\n// ============================================\n// Message Queue Types\n// ============================================\n\nexport type QueueMessageStatus = 'pending' | 'processing' | 'delivered' | 'failed' | 'expired';\n\nexport interface QueuedMessage {\n id: string;\n tenantId?: string | null;\n deviceId: string;\n messageType: string;\n payload: Record<string, unknown>;\n priority: 'high' | 'normal' | 'low';\n status: QueueMessageStatus;\n attempts: number;\n maxAttempts: number;\n lastAttemptAt?: Date | null;\n lastError?: string | null;\n expiresAt?: Date | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface EnqueueMessageInput {\n tenantId?: string;\n deviceId: string;\n messageType: string;\n payload: Record<string, unknown>;\n priority?: 'high' | 'normal' | 'low';\n maxAttempts?: number;\n ttlSeconds?: number;\n}\n\nexport interface QueueStats {\n pending: number;\n processing: number;\n delivered: number;\n failed: number;\n expired: number;\n byDevice: Record<string, number>;\n oldestPending?: Date;\n}\n\n// ============================================\n// Dashboard Types\n// ============================================\n\nexport interface DashboardStats {\n devices: {\n total: number;\n enrolled: number;\n active: number;\n blocked: number;\n pending: number;\n };\n policies: {\n total: number;\n deployed: number;\n };\n applications: {\n total: number;\n deployed: number;\n };\n commands: {\n pendingCount: number;\n last24hTotal: number;\n last24hSuccess: number;\n last24hFailed: number;\n };\n groups: {\n total: number;\n withDevices: number;\n };\n}\n\nexport interface DeviceStatusBreakdown {\n byStatus: Record<DeviceStatus, number>;\n byOs: Record<string, number>;\n byManufacturer: Record<string, number>;\n byModel: Record<string, number>;\n}\n\nexport interface EnrollmentTrendPoint {\n date: Date;\n enrolled: number;\n unenrolled: number;\n netChange: number;\n totalDevices: number;\n}\n\nexport interface CommandSuccessRates {\n overall: {\n total: number;\n completed: number;\n failed: number;\n successRate: number;\n };\n byType: Record<string, {\n total: number;\n completed: number;\n failed: number;\n successRate: number;\n avgExecutionTimeMs?: number;\n }>;\n last24h: {\n total: number;\n completed: number;\n failed: number;\n pending: number;\n };\n}\n\nexport interface AppInstallationSummary {\n total: number;\n byStatus: Record<string, number>;\n recentFailures: Array<{\n packageName: string;\n deviceId: string;\n error: string;\n timestamp: Date;\n }>;\n topInstalled: Array<{\n packageName: string;\n name: string;\n installedCount: number;\n }>;\n}\n\n// ============================================\n// Plugin Storage Types\n// ============================================\n\nexport interface PluginStorageAdapter {\n get<T>(pluginName: string, key: string): Promise<T | null>;\n set<T>(pluginName: string, key: string, value: T): Promise<void>;\n delete(pluginName: string, key: string): Promise<void>;\n list(pluginName: string, prefix?: string): Promise<string[]>;\n clear(pluginName: string): Promise<void>;\n}\n\nexport interface PluginStorageEntry {\n pluginName: string;\n key: string;\n value: unknown;\n createdAt: Date;\n updatedAt: Date;\n}\n\n// ============================================\n// Enterprise Manager Interfaces\n// ============================================\n\nexport interface TenantManager {\n get(id: string): Promise<Tenant | null>;\n getBySlug(slug: string): Promise<Tenant | null>;\n list(filter?: TenantFilter): Promise<TenantListResult>;\n create(data: CreateTenantInput): Promise<Tenant>;\n update(id: string, data: UpdateTenantInput): Promise<Tenant>;\n delete(id: string, cascade?: boolean): Promise<void>;\n getStats(tenantId: string): Promise<TenantStats>;\n activate(id: string): Promise<Tenant>;\n deactivate(id: string): Promise<Tenant>;\n}\n\nexport interface AuthorizationManager {\n createRole(data: CreateRoleInput): Promise<Role>;\n getRole(id: string): Promise<Role | null>;\n listRoles(tenantId?: string): Promise<Role[]>;\n updateRole(id: string, data: UpdateRoleInput): Promise<Role>;\n deleteRole(id: string): Promise<void>;\n createUser(data: CreateUserInput): Promise<User>;\n getUser(id: string): Promise<UserWithRoles | null>;\n getUserByEmail(email: string, tenantId?: string): Promise<UserWithRoles | null>;\n listUsers(filter?: UserFilter): Promise<UserListResult>;\n updateUser(id: string, data: UpdateUserInput): Promise<User>;\n deleteUser(id: string): Promise<void>;\n assignRole(userId: string, roleId: string): Promise<void>;\n removeRole(userId: string, roleId: string): Promise<void>;\n getUserRoles(userId: string): Promise<Role[]>;\n can(userId: string, action: PermissionAction, resource: PermissionResource, resourceId?: string): Promise<boolean>;\n canAny(userId: string, permissions: Array<{ action: PermissionAction; resource: PermissionResource }>): Promise<boolean>;\n requirePermission(userId: string, action: PermissionAction, resource: PermissionResource, resourceId?: string): Promise<void>;\n isAdmin(userId: string): Promise<boolean>;\n}\n\nexport interface AuditManager {\n log(entry: CreateAuditLogInput): Promise<AuditLog>;\n list(filter?: AuditLogFilter): Promise<AuditLogListResult>;\n getByResource(resource: string, resourceId: string): Promise<AuditLog[]>;\n getByUser(userId: string, filter?: AuditLogFilter): Promise<AuditLogListResult>;\n export(filter: AuditLogFilter, format: 'json' | 'csv'): Promise<string>;\n purge(olderThanDays?: number): Promise<number>;\n getSummary(tenantId?: string, days?: number): Promise<AuditSummary>;\n}\n\nexport interface ScheduleManager {\n get(id: string): Promise<ScheduledTask | null>;\n list(filter?: ScheduledTaskFilter): Promise<ScheduledTaskListResult>;\n create(data: CreateScheduledTaskInput): Promise<ScheduledTask>;\n update(id: string, data: UpdateScheduledTaskInput): Promise<ScheduledTask>;\n delete(id: string): Promise<void>;\n pause(id: string): Promise<ScheduledTask>;\n resume(id: string): Promise<ScheduledTask>;\n runNow(id: string): Promise<TaskExecution>;\n getUpcoming(hours: number): Promise<ScheduledTask[]>;\n getExecutions(taskId: string, limit?: number): Promise<TaskExecution[]>;\n calculateNextRun(schedule: TaskSchedule): Date | null;\n}\n\nexport interface MessageQueueManager {\n enqueue(message: EnqueueMessageInput): Promise<QueuedMessage>;\n enqueueBatch(messages: EnqueueMessageInput[]): Promise<QueuedMessage[]>;\n dequeue(deviceId: string, limit?: number): Promise<QueuedMessage[]>;\n acknowledge(messageId: string): Promise<void>;\n fail(messageId: string, error: string): Promise<void>;\n retryFailed(maxAttempts?: number): Promise<number>;\n purgeExpired(): Promise<number>;\n getStats(tenantId?: string): Promise<QueueStats>;\n peek(deviceId: string, limit?: number): Promise<QueuedMessage[]>;\n}\n\nexport interface DashboardManager {\n getStats(tenantId?: string): Promise<DashboardStats>;\n getDeviceStatusBreakdown(tenantId?: string): Promise<DeviceStatusBreakdown>;\n getEnrollmentTrend(days: number, tenantId?: string): Promise<EnrollmentTrendPoint[]>;\n getCommandSuccessRates(tenantId?: string): Promise<CommandSuccessRates>;\n getAppInstallationSummary(tenantId?: string): Promise<AppInstallationSummary>;\n}\n\n// ============================================\n// Event Handler Types\n// ============================================\n\nexport type EventHandler<T extends EventType> = (\n event: MDMEvent<EventPayloadMap[T]>\n) => Promise<void> | void;\n\nexport interface EventPayloadMap {\n 'device.enrolled': { device: Device };\n 'device.unenrolled': { device: Device; reason?: string };\n 'device.blocked': { device: Device; reason: string };\n 'device.heartbeat': { device: Device; heartbeat: Heartbeat };\n 'device.locationUpdated': { device: Device; location: DeviceLocation };\n 'device.statusChanged': { device: Device; oldStatus: DeviceStatus; newStatus: DeviceStatus };\n 'device.policyChanged': { device: Device; oldPolicyId?: string; newPolicyId?: string };\n 'app.installed': { device: Device; app: InstalledApp };\n 'app.uninstalled': { device: Device; packageName: string };\n 'app.updated': { device: Device; app: InstalledApp; oldVersion: string };\n 'app.crashed': { device: Device; packageName: string; error?: string };\n 'app.started': { device: Device; packageName: string };\n 'app.stopped': { device: Device; packageName: string };\n 'policy.applied': { device: Device; policy: Policy };\n 'policy.failed': { device: Device; policy: Policy; error: string };\n 'command.received': { device: Device; command: Command };\n 'command.acknowledged': { device: Device; command: Command };\n 'command.completed': { device: Device; command: Command; result: CommandResult };\n 'command.failed': { device: Device; command: Command; error: string };\n 'security.tamper': { device: Device; type: string; details?: unknown };\n 'security.rootDetected': { device: Device };\n 'security.screenLocked': { device: Device };\n 'security.screenUnlocked': { device: Device };\n custom: Record<string, unknown>;\n}\n\n// ============================================\n// Error Types\n// ============================================\n\nexport class MDMError extends Error {\n constructor(\n message: string,\n public code: string,\n public statusCode: number = 500,\n public details?: unknown\n ) {\n super(message);\n this.name = 'MDMError';\n }\n}\n\nexport class DeviceNotFoundError extends MDMError {\n constructor(deviceId: string) {\n super(`Device not found: ${deviceId}`, 'DEVICE_NOT_FOUND', 404);\n }\n}\n\nexport class PolicyNotFoundError extends MDMError {\n constructor(policyId: string) {\n super(`Policy not found: ${policyId}`, 'POLICY_NOT_FOUND', 404);\n }\n}\n\nexport class ApplicationNotFoundError extends MDMError {\n constructor(identifier: string) {\n super(`Application not found: ${identifier}`, 'APPLICATION_NOT_FOUND', 404);\n }\n}\n\nexport class CommandNotFoundError extends MDMError {\n constructor(commandId: string) {\n super(`Command not found: ${commandId}`, 'COMMAND_NOT_FOUND', 404);\n }\n}\n\nexport class TenantNotFoundError extends MDMError {\n constructor(identifier: string) {\n super(`Tenant not found: ${identifier}`, 'TENANT_NOT_FOUND', 404);\n }\n}\n\nexport class RoleNotFoundError extends MDMError {\n constructor(identifier: string) {\n super(`Role not found: ${identifier}`, 'ROLE_NOT_FOUND', 404);\n }\n}\n\nexport class GroupNotFoundError extends MDMError {\n constructor(identifier: string) {\n super(`Group not found: ${identifier}`, 'GROUP_NOT_FOUND', 404);\n }\n}\n\nexport class UserNotFoundError extends MDMError {\n constructor(identifier: string) {\n super(`User not found: ${identifier}`, 'USER_NOT_FOUND', 404);\n }\n}\n\nexport class EnrollmentError extends MDMError {\n constructor(message: string, details?: unknown) {\n super(message, 'ENROLLMENT_ERROR', 400, details);\n }\n}\n\nexport class AuthenticationError extends MDMError {\n constructor(message: string = 'Authentication required') {\n super(message, 'AUTHENTICATION_ERROR', 401);\n }\n}\n\nexport class AuthorizationError extends MDMError {\n constructor(message: string = 'Access denied') {\n super(message, 'AUTHORIZATION_ERROR', 403);\n }\n}\n\nexport class ValidationError extends MDMError {\n constructor(message: string, details?: unknown) {\n super(message, 'VALIDATION_ERROR', 400, details);\n }\n}\n","/**\n * OpenMDM Logger\n *\n * Default logger implementations and helpers. Production users are\n * expected to pass their own pino/winston/bunyan instance via\n * `createMDM({ logger })`; these defaults are for development and\n * for the zero-config path.\n */\n\nimport type { Logger, LogContext } from './types';\n\n/**\n * Resolve (context, message) or (message) argument forms into a\n * single shape. Matches the pino call convention used by the Logger\n * interface.\n */\nfunction normalize(\n ...args: [LogContext, string] | [string]\n): { context: LogContext | undefined; message: string } {\n if (args.length === 1) {\n return { context: undefined, message: args[0] };\n }\n return { context: args[0], message: args[1] };\n}\n\n/**\n * Console-backed logger. Writes JSON-ish lines to stdout/stderr with\n * an `[openmdm]` prefix so they stand out in a mixed-log stream.\n *\n * This is the zero-config default — it intentionally does the\n * minimum viable thing. Hosts running in production should replace\n * it with a real structured logger.\n */\nexport function createConsoleLogger(scope: string[] = []): Logger {\n const prefix = scope.length > 0 ? `[openmdm:${scope.join(':')}]` : '[openmdm]';\n\n const render = (context: LogContext | undefined): string => {\n if (!context || Object.keys(context).length === 0) return '';\n // Keep single-line to remain friendly to `grep`. JSON.stringify is\n // the cheapest structured-output format that every production\n // logger can consume as-is.\n try {\n return ' ' + JSON.stringify(context);\n } catch {\n // Fall back to a string cast when the context has a circular\n // reference — losing structure is better than crashing the call\n // site.\n return ' ' + String(context);\n }\n };\n\n return {\n debug: (...args: [LogContext, string] | [string]) => {\n const { context, message } = normalize(...args);\n // Debug is off by default when no DEBUG env var is set — keeps\n // the dev experience quiet unless someone opts in.\n if (!process.env.DEBUG) return;\n console.debug(`${prefix} ${message}${render(context)}`);\n },\n info: (...args: [LogContext, string] | [string]) => {\n const { context, message } = normalize(...args);\n console.log(`${prefix} ${message}${render(context)}`);\n },\n warn: (...args: [LogContext, string] | [string]) => {\n const { context, message } = normalize(...args);\n console.warn(`${prefix} ${message}${render(context)}`);\n },\n error: (...args: [LogContext, string] | [string]) => {\n const { context, message } = normalize(...args);\n console.error(`${prefix} ${message}${render(context)}`);\n },\n child: (bindings: LogContext): Logger => {\n // Console logger's `child` extends the scope with any\n // `component` field if provided, otherwise appends nothing\n // meaningful and just returns a new logger with the same\n // scope. Real loggers (pino) properly attach bindings to every\n // subsequent call — we do the simplest thing that won't lie.\n const componentPart =\n typeof bindings.component === 'string' ? [bindings.component] : [];\n return createConsoleLogger([...scope, ...componentPart]);\n },\n };\n}\n\n/**\n * No-op logger. Use to silence OpenMDM entirely — e.g. in tests or in\n * environments where log noise is inappropriate.\n */\nexport function createSilentLogger(): Logger {\n const silent: Logger = {\n debug: () => undefined,\n info: () => undefined,\n warn: () => undefined,\n error: () => undefined,\n child: () => silent,\n };\n return silent;\n}\n","/**\n * OpenMDM Webhook Delivery System\n *\n * Handles outbound webhook delivery with HMAC signing and retry logic.\n */\n\nimport { createHmac, randomUUID } from 'crypto';\nimport type {\n WebhookConfig,\n WebhookEndpoint,\n EventType,\n MDMEvent,\n Logger,\n} from './types';\nimport { createSilentLogger } from './logger';\n\n// ============================================\n// Types\n// ============================================\n\nexport interface WebhookDeliveryResult {\n endpointId: string;\n success: boolean;\n statusCode?: number;\n error?: string;\n retryCount: number;\n deliveredAt?: Date;\n}\n\nexport interface WebhookPayload<T = unknown> {\n id: string;\n event: EventType;\n timestamp: string;\n data: T;\n}\n\nexport interface WebhookManager {\n /**\n * Deliver an event to all matching webhook endpoints\n */\n deliver<T>(event: MDMEvent<T>): Promise<WebhookDeliveryResult[]>;\n\n /**\n * Add a webhook endpoint at runtime\n */\n addEndpoint(endpoint: WebhookEndpoint): void;\n\n /**\n * Remove a webhook endpoint\n */\n removeEndpoint(endpointId: string): void;\n\n /**\n * Update a webhook endpoint\n */\n updateEndpoint(endpointId: string, updates: Partial<WebhookEndpoint>): void;\n\n /**\n * Get all configured endpoints\n */\n getEndpoints(): WebhookEndpoint[];\n\n /**\n * Test a webhook endpoint with a test payload\n */\n testEndpoint(endpointId: string): Promise<WebhookDeliveryResult>;\n}\n\n// ============================================\n// Implementation\n// ============================================\n\nconst DEFAULT_RETRY_CONFIG = {\n maxRetries: 3,\n initialDelay: 1000,\n maxDelay: 30000,\n};\n\n/**\n * Create a webhook manager instance\n */\nexport function createWebhookManager(\n config: WebhookConfig,\n logger: Logger = createSilentLogger(),\n): WebhookManager {\n const endpoints = new Map<string, WebhookEndpoint>();\n const retryConfig = { ...DEFAULT_RETRY_CONFIG, ...config.retry };\n const log = logger.child({ component: 'webhooks' });\n\n // Initialize with configured endpoints\n if (config.endpoints) {\n for (const endpoint of config.endpoints) {\n endpoints.set(endpoint.id, endpoint);\n }\n }\n\n /**\n * Sign a webhook payload with HMAC-SHA256\n */\n function signPayload(payload: string, secret: string): string {\n return createHmac('sha256', secret).update(payload).digest('hex');\n }\n\n /**\n * Calculate exponential backoff delay\n */\n function getBackoffDelay(retryCount: number): number {\n const delay = retryConfig.initialDelay * Math.pow(2, retryCount);\n return Math.min(delay, retryConfig.maxDelay);\n }\n\n /**\n * Check if an endpoint should receive this event\n */\n function shouldDeliverToEndpoint(\n endpoint: WebhookEndpoint,\n eventType: EventType\n ): boolean {\n if (!endpoint.enabled) {\n return false;\n }\n\n // Wildcard matches all events\n if (endpoint.events.includes('*')) {\n return true;\n }\n\n return endpoint.events.includes(eventType);\n }\n\n /**\n * Deliver payload to a single endpoint with retry logic\n */\n async function deliverToEndpoint(\n endpoint: WebhookEndpoint,\n payload: WebhookPayload\n ): Promise<WebhookDeliveryResult> {\n const payloadString = JSON.stringify(payload);\n let lastError: string | undefined;\n let lastStatusCode: number | undefined;\n\n for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {\n try {\n // Prepare headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-OpenMDM-Event': payload.event,\n 'X-OpenMDM-Delivery': payload.id,\n 'X-OpenMDM-Timestamp': payload.timestamp,\n ...endpoint.headers,\n };\n\n // Add signature if signing secret is configured\n if (config.signingSecret) {\n const signature = signPayload(payloadString, config.signingSecret);\n headers['X-OpenMDM-Signature'] = `sha256=${signature}`;\n }\n\n // Make the request\n const response = await fetch(endpoint.url, {\n method: 'POST',\n headers,\n body: payloadString,\n signal: AbortSignal.timeout(30000), // 30 second timeout\n });\n\n lastStatusCode = response.status;\n\n // 2xx is success\n if (response.ok) {\n return {\n endpointId: endpoint.id,\n success: true,\n statusCode: response.status,\n retryCount: attempt,\n deliveredAt: new Date(),\n };\n }\n\n // 4xx errors (except 429) should not be retried\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n return {\n endpointId: endpoint.id,\n success: false,\n statusCode: response.status,\n error: `HTTP ${response.status}: ${response.statusText}`,\n retryCount: attempt,\n };\n }\n\n // 5xx and 429 should be retried\n lastError = `HTTP ${response.status}: ${response.statusText}`;\n } catch (error) {\n lastError = error instanceof Error ? error.message : String(error);\n }\n\n // Wait before retry (unless this was the last attempt)\n if (attempt < retryConfig.maxRetries) {\n const delay = getBackoffDelay(attempt);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n return {\n endpointId: endpoint.id,\n success: false,\n statusCode: lastStatusCode,\n error: lastError || 'Max retries exceeded',\n retryCount: retryConfig.maxRetries,\n };\n }\n\n return {\n async deliver<T>(event: MDMEvent<T>): Promise<WebhookDeliveryResult[]> {\n const matchingEndpoints = Array.from(endpoints.values()).filter((ep) =>\n shouldDeliverToEndpoint(ep, event.type)\n );\n\n if (matchingEndpoints.length === 0) {\n return [];\n }\n\n // Prepare webhook payload\n const payload: WebhookPayload<T> = {\n id: randomUUID(),\n event: event.type,\n timestamp: new Date().toISOString(),\n data: event.payload,\n };\n\n // Deliver to all matching endpoints in parallel\n const deliveryPromises = matchingEndpoints.map((endpoint) =>\n deliverToEndpoint(endpoint, payload as WebhookPayload)\n );\n\n const results = await Promise.all(deliveryPromises);\n\n // Log failures\n for (const result of results) {\n if (!result.success) {\n log.error(\n {\n endpointId: result.endpointId,\n statusCode: result.statusCode,\n retryCount: result.retryCount,\n err: result.error,\n },\n 'Webhook delivery failed',\n );\n }\n }\n\n return results;\n },\n\n addEndpoint(endpoint: WebhookEndpoint): void {\n endpoints.set(endpoint.id, endpoint);\n },\n\n removeEndpoint(endpointId: string): void {\n endpoints.delete(endpointId);\n },\n\n updateEndpoint(endpointId: string, updates: Partial<WebhookEndpoint>): void {\n const existing = endpoints.get(endpointId);\n if (existing) {\n endpoints.set(endpointId, { ...existing, ...updates });\n }\n },\n\n getEndpoints(): WebhookEndpoint[] {\n return Array.from(endpoints.values());\n },\n\n async testEndpoint(endpointId: string): Promise<WebhookDeliveryResult> {\n const endpoint = endpoints.get(endpointId);\n if (!endpoint) {\n return {\n endpointId,\n success: false,\n error: 'Endpoint not found',\n retryCount: 0,\n };\n }\n\n const testPayload: WebhookPayload = {\n id: randomUUID(),\n event: 'device.heartbeat',\n timestamp: new Date().toISOString(),\n data: {\n test: true,\n message: 'OpenMDM webhook test',\n },\n };\n\n return deliverToEndpoint(endpoint, testPayload);\n },\n };\n}\n\n/**\n * Verify a webhook signature from incoming requests\n * (Utility for consumers to verify our webhooks)\n */\nexport function verifyWebhookSignature(\n payload: string,\n signature: string,\n secret: string\n): boolean {\n const expectedSignature = `sha256=${createHmac('sha256', secret)\n .update(payload)\n .digest('hex')}`;\n\n // Constant-time comparison\n if (signature.length !== expectedSignature.length) {\n return false;\n }\n\n let result = 0;\n for (let i = 0; i < signature.length; i++) {\n result |= signature.charCodeAt(i) ^ expectedSignature.charCodeAt(i);\n }\n\n return result === 0;\n}\n","/**\n * OpenMDM Tenant Manager\n *\n * Provides multi-tenancy support for the MDM system.\n * Enables organization isolation, tenant management, and resource quotas.\n */\n\nimport type {\n Tenant,\n TenantManager,\n TenantFilter,\n TenantListResult,\n TenantStats,\n CreateTenantInput,\n UpdateTenantInput,\n DatabaseAdapter,\n} from './types';\nimport { TenantNotFoundError, ValidationError } from './types';\n\n/**\n * Generate a unique ID for entities\n */\nfunction generateId(): string {\n return crypto.randomUUID();\n}\n\n/**\n * Validate tenant slug format\n */\nfunction validateSlug(slug: string): boolean {\n // Slug must be lowercase alphanumeric with hyphens, 3-50 chars\n const slugRegex = /^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$/;\n return slugRegex.test(slug);\n}\n\n/**\n * Create a TenantManager instance\n */\nexport function createTenantManager(db: DatabaseAdapter): TenantManager {\n return {\n async get(id: string): Promise<Tenant | null> {\n if (!db.findTenant) {\n throw new Error('Database adapter does not support tenant operations');\n }\n return db.findTenant(id);\n },\n\n async getBySlug(slug: string): Promise<Tenant | null> {\n if (!db.findTenantBySlug) {\n throw new Error('Database adapter does not support tenant operations');\n }\n return db.findTenantBySlug(slug);\n },\n\n async list(filter?: TenantFilter): Promise<TenantListResult> {\n if (!db.listTenants) {\n throw new Error('Database adapter does not support tenant operations');\n }\n return db.listTenants(filter);\n },\n\n async create(data: CreateTenantInput): Promise<Tenant> {\n if (!db.createTenant || !db.findTenantBySlug) {\n throw new Error('Database adapter does not support tenant operations');\n }\n\n // Validate slug format\n if (!validateSlug(data.slug)) {\n throw new ValidationError(\n 'Invalid slug format. Must be 3-50 lowercase alphanumeric characters with hyphens.',\n { slug: data.slug }\n );\n }\n\n // Check for duplicate slug\n const existing = await db.findTenantBySlug(data.slug);\n if (existing) {\n throw new ValidationError(`Tenant with slug '${data.slug}' already exists`, {\n slug: data.slug,\n });\n }\n\n return db.createTenant({\n ...data,\n slug: data.slug.toLowerCase(),\n });\n },\n\n async update(id: string, data: UpdateTenantInput): Promise<Tenant> {\n if (!db.updateTenant || !db.findTenant || !db.findTenantBySlug) {\n throw new Error('Database adapter does not support tenant operations');\n }\n\n const tenant = await db.findTenant(id);\n if (!tenant) {\n throw new TenantNotFoundError(id);\n }\n\n // Validate new slug if provided\n if (data.slug) {\n if (!validateSlug(data.slug)) {\n throw new ValidationError(\n 'Invalid slug format. Must be 3-50 lowercase alphanumeric characters with hyphens.',\n { slug: data.slug }\n );\n }\n\n // Check for duplicate slug\n const existing = await db.findTenantBySlug(data.slug);\n if (existing && existing.id !== id) {\n throw new ValidationError(`Tenant with slug '${data.slug}' already exists`, {\n slug: data.slug,\n });\n }\n\n data.slug = data.slug.toLowerCase();\n }\n\n return db.updateTenant(id, data);\n },\n\n async delete(id: string, cascade: boolean = false): Promise<void> {\n if (!db.deleteTenant || !db.findTenant) {\n throw new Error('Database adapter does not support tenant operations');\n }\n\n const tenant = await db.findTenant(id);\n if (!tenant) {\n throw new TenantNotFoundError(id);\n }\n\n // If cascade is true, the database adapter should handle\n // deletion of all related resources (devices, policies, etc.)\n // This is typically done via ON DELETE CASCADE in the schema\n\n await db.deleteTenant(id);\n },\n\n async getStats(tenantId: string): Promise<TenantStats> {\n if (!db.getTenantStats || !db.findTenant) {\n throw new Error('Database adapter does not support tenant operations');\n }\n\n const tenant = await db.findTenant(tenantId);\n if (!tenant) {\n throw new TenantNotFoundError(tenantId);\n }\n\n return db.getTenantStats(tenantId);\n },\n\n async activate(id: string): Promise<Tenant> {\n if (!db.updateTenant || !db.findTenant) {\n throw new Error('Database adapter does not support tenant operations');\n }\n\n const tenant = await db.findTenant(id);\n if (!tenant) {\n throw new TenantNotFoundError(id);\n }\n\n if (tenant.status === 'active') {\n return tenant;\n }\n\n return db.updateTenant(id, { status: 'active' });\n },\n\n async deactivate(id: string): Promise<Tenant> {\n if (!db.updateTenant || !db.findTenant) {\n throw new Error('Database adapter does not support tenant operations');\n }\n\n const tenant = await db.findTenant(id);\n if (!tenant) {\n throw new TenantNotFoundError(id);\n }\n\n if (tenant.status === 'suspended') {\n return tenant;\n }\n\n return db.updateTenant(id, { status: 'suspended' });\n },\n };\n}\n\n/**\n * Default system roles that can be used across tenants\n */\nexport const DEFAULT_SYSTEM_ROLES = {\n SUPER_ADMIN: {\n name: 'Super Admin',\n description: 'Full system access across all tenants',\n permissions: [{ action: '*' as const, resource: '*' as const }],\n isSystem: true,\n },\n TENANT_ADMIN: {\n name: 'Tenant Admin',\n description: 'Full access within the tenant',\n permissions: [\n { action: 'manage' as const, resource: 'devices' as const },\n { action: 'manage' as const, resource: 'policies' as const },\n { action: 'manage' as const, resource: 'applications' as const },\n { action: 'manage' as const, resource: 'commands' as const },\n { action: 'manage' as const, resource: 'groups' as const },\n { action: 'manage' as const, resource: 'users' as const },\n { action: 'read' as const, resource: 'audit' as const },\n ],\n isSystem: true,\n },\n DEVICE_MANAGER: {\n name: 'Device Manager',\n description: 'Manage devices and send commands',\n permissions: [\n { action: 'manage' as const, resource: 'devices' as const },\n { action: 'manage' as const, resource: 'commands' as const },\n { action: 'read' as const, resource: 'policies' as const },\n { action: 'read' as const, resource: 'groups' as const },\n ],\n isSystem: true,\n },\n VIEWER: {\n name: 'Viewer',\n description: 'Read-only access to all resources',\n permissions: [\n { action: 'read' as const, resource: 'devices' as const },\n { action: 'read' as const, resource: 'policies' as const },\n { action: 'read' as const, resource: 'applications' as const },\n { action: 'read' as const, resource: 'commands' as const },\n { action: 'read' as const, resource: 'groups' as const },\n ],\n isSystem: true,\n },\n};\n\nexport type SystemRoleName = keyof typeof DEFAULT_SYSTEM_ROLES;\n","/**\n * OpenMDM Authorization Manager\n *\n * Provides Role-Based Access Control (RBAC) for the MDM system.\n * Enables fine-grained permission management for users and resources.\n */\n\nimport type {\n Role,\n User,\n UserWithRoles,\n Permission,\n PermissionAction,\n PermissionResource,\n AuthorizationManager,\n CreateRoleInput,\n UpdateRoleInput,\n CreateUserInput,\n UpdateUserInput,\n UserFilter,\n UserListResult,\n DatabaseAdapter,\n} from './types';\nimport {\n UserNotFoundError,\n RoleNotFoundError,\n AuthorizationError,\n ValidationError,\n} from './types';\n\n/**\n * Check if an action matches the required action\n */\nfunction actionMatches(required: PermissionAction, granted: PermissionAction): boolean {\n if (granted === '*') return true;\n if (granted === 'manage') {\n // 'manage' implies all CRUD operations\n return ['create', 'read', 'update', 'delete', 'manage'].includes(required);\n }\n return required === granted;\n}\n\n/**\n * Check if a resource matches the required resource\n */\nfunction resourceMatches(required: PermissionResource, granted: PermissionResource): boolean {\n if (granted === '*') return true;\n return required === granted;\n}\n\n/**\n * Check if a permission matches the required permission\n */\nfunction permissionMatches(\n required: { action: PermissionAction; resource: PermissionResource },\n granted: Permission\n): boolean {\n return (\n actionMatches(required.action, granted.action) &&\n resourceMatches(required.resource, granted.resource)\n );\n}\n\n/**\n * Check if any permission in the list grants the required access\n */\nfunction hasPermission(\n permissions: Permission[],\n action: PermissionAction,\n resource: PermissionResource\n): boolean {\n return permissions.some((p) => permissionMatches({ action, resource }, p));\n}\n\n/**\n * Check if user has admin permissions (full access)\n */\nfunction isAdminPermission(permissions: Permission[]): boolean {\n return permissions.some(\n (p) => p.action === '*' && p.resource === '*'\n );\n}\n\n/**\n * Validate email format\n */\nfunction validateEmail(email: string): boolean {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email);\n}\n\n/**\n * Create an AuthorizationManager instance\n */\nexport function createAuthorizationManager(db: DatabaseAdapter): AuthorizationManager {\n /**\n * Get all permissions for a user from all their roles\n */\n async function getAllUserPermissions(userId: string): Promise<Permission[]> {\n if (!db.getUserRoles) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const roles = await db.getUserRoles(userId);\n const permissions: Permission[] = [];\n\n for (const role of roles) {\n permissions.push(...role.permissions);\n }\n\n return permissions;\n }\n\n return {\n // ========================================\n // Role Management\n // ========================================\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n if (!db.createRole) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n // Validate permissions array\n if (!data.permissions || !Array.isArray(data.permissions)) {\n throw new ValidationError('Permissions must be an array');\n }\n\n for (const permission of data.permissions) {\n if (!permission.action || !permission.resource) {\n throw new ValidationError('Each permission must have action and resource');\n }\n }\n\n return db.createRole(data);\n },\n\n async getRole(id: string): Promise<Role | null> {\n if (!db.findRole) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n return db.findRole(id);\n },\n\n async listRoles(tenantId?: string): Promise<Role[]> {\n if (!db.listRoles) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n return db.listRoles(tenantId);\n },\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n if (!db.updateRole || !db.findRole) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const role = await db.findRole(id);\n if (!role) {\n throw new RoleNotFoundError(id);\n }\n\n // Cannot update system roles\n if (role.isSystem) {\n throw new AuthorizationError('Cannot modify system roles');\n }\n\n // Validate permissions if provided\n if (data.permissions) {\n if (!Array.isArray(data.permissions)) {\n throw new ValidationError('Permissions must be an array');\n }\n\n for (const permission of data.permissions) {\n if (!permission.action || !permission.resource) {\n throw new ValidationError('Each permission must have action and resource');\n }\n }\n }\n\n return db.updateRole(id, data);\n },\n\n async deleteRole(id: string): Promise<void> {\n if (!db.deleteRole || !db.findRole) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const role = await db.findRole(id);\n if (!role) {\n throw new RoleNotFoundError(id);\n }\n\n // Cannot delete system roles\n if (role.isSystem) {\n throw new AuthorizationError('Cannot delete system roles');\n }\n\n await db.deleteRole(id);\n },\n\n // ========================================\n // User Management\n // ========================================\n\n async createUser(data: CreateUserInput): Promise<User> {\n if (!db.createUser || !db.findUserByEmail) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n // Validate email\n if (!validateEmail(data.email)) {\n throw new ValidationError('Invalid email format', { email: data.email });\n }\n\n // Check for duplicate email within tenant\n const existing = await db.findUserByEmail(data.email, data.tenantId);\n if (existing) {\n throw new ValidationError(`User with email '${data.email}' already exists`, {\n email: data.email,\n });\n }\n\n return db.createUser({\n ...data,\n email: data.email.toLowerCase(),\n });\n },\n\n async getUser(id: string): Promise<UserWithRoles | null> {\n if (!db.findUser || !db.getUserRoles) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(id);\n if (!user) return null;\n\n const roles = await db.getUserRoles(id);\n return { ...user, roles };\n },\n\n async getUserByEmail(email: string, tenantId?: string): Promise<UserWithRoles | null> {\n if (!db.findUserByEmail || !db.getUserRoles) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUserByEmail(email.toLowerCase(), tenantId);\n if (!user) return null;\n\n const roles = await db.getUserRoles(user.id);\n return { ...user, roles };\n },\n\n async listUsers(filter?: UserFilter): Promise<UserListResult> {\n if (!db.listUsers) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n return db.listUsers(filter);\n },\n\n async updateUser(id: string, data: UpdateUserInput): Promise<User> {\n if (!db.updateUser || !db.findUser) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(id);\n if (!user) {\n throw new UserNotFoundError(id);\n }\n\n // Validate email if provided\n if (data.email) {\n if (!validateEmail(data.email)) {\n throw new ValidationError('Invalid email format', { email: data.email });\n }\n data.email = data.email.toLowerCase();\n }\n\n return db.updateUser(id, data);\n },\n\n async deleteUser(id: string): Promise<void> {\n if (!db.deleteUser || !db.findUser) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(id);\n if (!user) {\n throw new UserNotFoundError(id);\n }\n\n await db.deleteUser(id);\n },\n\n // ========================================\n // Role Assignment\n // ========================================\n\n async assignRole(userId: string, roleId: string): Promise<void> {\n if (!db.assignRoleToUser || !db.findUser || !db.findRole) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(userId);\n if (!user) {\n throw new UserNotFoundError(userId);\n }\n\n const role = await db.findRole(roleId);\n if (!role) {\n throw new RoleNotFoundError(roleId);\n }\n\n // Verify tenant compatibility\n if (role.tenantId && user.tenantId && role.tenantId !== user.tenantId) {\n throw new AuthorizationError('Role belongs to a different tenant');\n }\n\n await db.assignRoleToUser(userId, roleId);\n },\n\n async removeRole(userId: string, roleId: string): Promise<void> {\n if (!db.removeRoleFromUser || !db.findUser) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(userId);\n if (!user) {\n throw new UserNotFoundError(userId);\n }\n\n await db.removeRoleFromUser(userId, roleId);\n },\n\n async getUserRoles(userId: string): Promise<Role[]> {\n if (!db.getUserRoles || !db.findUser) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(userId);\n if (!user) {\n throw new UserNotFoundError(userId);\n }\n\n return db.getUserRoles(userId);\n },\n\n // ========================================\n // Permission Checking\n // ========================================\n\n async can(\n userId: string,\n action: PermissionAction,\n resource: PermissionResource,\n _resourceId?: string\n ): Promise<boolean> {\n if (!db.findUser) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(userId);\n if (!user) return false;\n\n // Inactive users have no permissions\n if (user.status !== 'active') return false;\n\n const permissions = await getAllUserPermissions(userId);\n return hasPermission(permissions, action, resource);\n },\n\n async requirePermission(\n userId: string,\n action: PermissionAction,\n resource: PermissionResource,\n resourceId?: string\n ): Promise<void> {\n const allowed = await this.can(userId, action, resource, resourceId);\n if (!allowed) {\n throw new AuthorizationError(\n `Permission denied: ${action} on ${resource}${resourceId ? ` (${resourceId})` : ''}`\n );\n }\n },\n\n async canAny(\n userId: string,\n permissions: Array<{ action: PermissionAction; resource: PermissionResource }>\n ): Promise<boolean> {\n if (!db.findUser) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(userId);\n if (!user) return false;\n\n // Inactive users have no permissions\n if (user.status !== 'active') return false;\n\n const userPermissions = await getAllUserPermissions(userId);\n\n return permissions.some((required) =>\n hasPermission(userPermissions, required.action, required.resource)\n );\n },\n\n async isAdmin(userId: string): Promise<boolean> {\n if (!db.findUser) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(userId);\n if (!user || user.status !== 'active') return false;\n\n const permissions = await getAllUserPermissions(userId);\n return isAdminPermission(permissions);\n },\n };\n}\n","/**\n * OpenMDM Audit Manager\n *\n * Provides audit logging for compliance and tracking.\n * Records all significant operations for security auditing.\n */\n\nimport type {\n AuditLog,\n AuditAction,\n AuditManager,\n AuditSummary,\n CreateAuditLogInput,\n AuditLogFilter,\n AuditLogListResult,\n DatabaseAdapter,\n AuditConfig,\n} from './types';\n\n/**\n * Default audit retention in days\n */\nconst DEFAULT_RETENTION_DAYS = 90;\n\n/**\n * Convert audit log to CSV row\n */\nfunction auditLogToCsvRow(log: AuditLog): string {\n const fields = [\n log.id,\n log.tenantId || '',\n log.userId || '',\n log.action,\n log.resource,\n log.resourceId || '',\n log.status,\n log.ipAddress || '',\n log.userAgent || '',\n log.error || '',\n log.createdAt.toISOString(),\n JSON.stringify(log.details || {}),\n ];\n return fields.map((f) => `\"${String(f).replace(/\"/g, '\"\"')}\"`).join(',');\n}\n\n/**\n * CSV header for audit log export\n */\nconst CSV_HEADER =\n 'id,tenant_id,user_id,action,resource,resource_id,status,ip_address,user_agent,error,created_at,details';\n\n/**\n * Create an AuditManager instance\n */\nexport function createAuditManager(\n db: DatabaseAdapter,\n config?: AuditConfig\n): AuditManager {\n const retentionDays = config?.retentionDays ?? DEFAULT_RETENTION_DAYS;\n\n /**\n * Check if an action should be logged based on configuration\n */\n function shouldLog(action: AuditAction, resource: string): boolean {\n if (!config?.enabled) return false;\n\n // Skip read operations if configured\n if (config.skipReadOperations && action === 'read') {\n return false;\n }\n\n // Check action filter\n if (config.logActions && config.logActions.length > 0) {\n if (!config.logActions.includes(action)) {\n return false;\n }\n }\n\n // Check resource filter\n if (config.logResources && config.logResources.length > 0) {\n if (!config.logResources.includes(resource)) {\n return false;\n }\n }\n\n return true;\n }\n\n return {\n async log(entry: CreateAuditLogInput): Promise<AuditLog> {\n if (!db.createAuditLog) {\n throw new Error('Database adapter does not support audit operations');\n }\n\n // Check if we should log this action\n if (config && !shouldLog(entry.action, entry.resource)) {\n // Return a stub audit log without persisting\n return {\n id: 'skipped',\n ...entry,\n createdAt: new Date(),\n } as AuditLog;\n }\n\n return db.createAuditLog(entry);\n },\n\n async list(filter?: AuditLogFilter): Promise<AuditLogListResult> {\n if (!db.listAuditLogs) {\n throw new Error('Database adapter does not support audit operations');\n }\n return db.listAuditLogs(filter);\n },\n\n async getByResource(resource: string, resourceId: string): Promise<AuditLog[]> {\n if (!db.listAuditLogs) {\n throw new Error('Database adapter does not support audit operations');\n }\n\n const result = await db.listAuditLogs({\n resource,\n resourceId,\n limit: 1000, // Reasonable limit for resource-specific queries\n });\n\n return result.logs;\n },\n\n async getByUser(\n userId: string,\n filter?: Omit<AuditLogFilter, 'userId'>\n ): Promise<AuditLogListResult> {\n if (!db.listAuditLogs) {\n throw new Error('Database adapter does not support audit operations');\n }\n\n return db.listAuditLogs({\n ...filter,\n userId,\n });\n },\n\n async export(filter: AuditLogFilter, format: 'csv' | 'json'): Promise<string> {\n if (!db.listAuditLogs) {\n throw new Error('Database adapter does not support audit operations');\n }\n\n // Fetch all matching logs (with a reasonable limit)\n const allLogs: AuditLog[] = [];\n let offset = 0;\n const batchSize = 1000;\n\n while (true) {\n const result = await db.listAuditLogs({\n ...filter,\n limit: batchSize,\n offset,\n });\n\n allLogs.push(...result.logs);\n\n if (result.logs.length < batchSize || allLogs.length >= 100000) {\n break;\n }\n\n offset += batchSize;\n }\n\n if (format === 'json') {\n return JSON.stringify(allLogs, null, 2);\n }\n\n // CSV format\n const rows = allLogs.map(auditLogToCsvRow);\n return [CSV_HEADER, ...rows].join('\\n');\n },\n\n async purge(olderThanDays?: number): Promise<number> {\n if (!db.deleteAuditLogs) {\n throw new Error('Database adapter does not support audit operations');\n }\n\n const days = olderThanDays ?? retentionDays;\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - days);\n\n return db.deleteAuditLogs({ olderThan: cutoffDate });\n },\n\n async getSummary(tenantId?: string, days: number = 30): Promise<AuditSummary> {\n if (!db.listAuditLogs) {\n throw new Error('Database adapter does not support audit operations');\n }\n\n const startDate = new Date();\n startDate.setDate(startDate.getDate() - days);\n\n // Fetch logs for the period\n const result = await db.listAuditLogs({\n tenantId,\n startDate,\n limit: 10000, // Reasonable limit for summary\n });\n\n const logs = result.logs;\n\n // Calculate summary statistics\n const byAction: Record<AuditAction, number> = {} as Record<AuditAction, number>;\n const byResource: Record<string, number> = {};\n const byStatus = { success: 0, failure: 0 };\n const userCounts: Record<string, number> = {};\n const recentFailures: AuditLog[] = [];\n\n for (const log of logs) {\n // By action\n byAction[log.action] = (byAction[log.action] || 0) + 1;\n\n // By resource\n byResource[log.resource] = (byResource[log.resource] || 0) + 1;\n\n // By status\n byStatus[log.status]++;\n\n // By user\n if (log.userId) {\n userCounts[log.userId] = (userCounts[log.userId] || 0) + 1;\n }\n\n // Collect failures\n if (log.status === 'failure' && recentFailures.length < 10) {\n recentFailures.push(log);\n }\n }\n\n // Get top users\n const topUsers = Object.entries(userCounts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n .map(([userId, count]) => ({ userId, count }));\n\n return {\n totalLogs: result.total,\n byAction,\n byResource,\n byStatus,\n topUsers,\n recentFailures,\n };\n },\n };\n}\n\n/**\n * Helper function to create audit log entries with common fields\n */\nexport function createAuditEntry(\n action: AuditAction,\n resource: string,\n options: {\n resourceId?: string;\n tenantId?: string;\n userId?: string;\n details?: Record<string, unknown>;\n ipAddress?: string;\n userAgent?: string;\n status?: 'success' | 'failure';\n error?: string;\n } = {}\n): CreateAuditLogInput {\n return {\n action,\n resource,\n resourceId: options.resourceId,\n tenantId: options.tenantId,\n userId: options.userId,\n details: options.details,\n ipAddress: options.ipAddress,\n userAgent: options.userAgent,\n status: options.status ?? 'success',\n error: options.error,\n };\n}\n\n/**\n * Audit decorator for wrapping async functions with audit logging\n */\nexport function withAudit<T extends (...args: unknown[]) => Promise<unknown>>(\n manager: AuditManager,\n action: AuditAction,\n resource: string,\n getContext: (...args: Parameters<T>) => Partial<CreateAuditLogInput>\n) {\n return function decorator(target: T): T {\n return (async (...args: Parameters<T>) => {\n const context = getContext(...args);\n try {\n const result = await target(...args);\n await manager.log({\n action,\n resource,\n status: 'success',\n ...context,\n });\n return result;\n } catch (error) {\n await manager.log({\n action,\n resource,\n status: 'failure',\n error: error instanceof Error ? error.message : String(error),\n ...context,\n });\n throw error;\n }\n }) as T;\n };\n}\n","/**\n * OpenMDM Schedule Manager\n *\n * Provides scheduled task management for the MDM system.\n * Enables scheduling of recurring operations, maintenance windows, and one-time tasks.\n */\n\nimport type {\n ScheduleManager,\n ScheduledTask,\n ScheduledTaskFilter,\n ScheduledTaskListResult,\n CreateScheduledTaskInput,\n UpdateScheduledTaskInput,\n TaskSchedule,\n TaskExecution,\n DatabaseAdapter,\n} from './types';\n\n/**\n * Parse cron expression and calculate next run time\n * Supports: minute hour dayOfMonth month dayOfWeek\n */\nfunction parseCronNextRun(cron: string, from: Date = new Date()): Date | null {\n try {\n const parts = cron.trim().split(/\\s+/);\n if (parts.length !== 5) return null;\n\n const [minute, hour, dayOfMonth, month, dayOfWeek] = parts;\n\n // Simple cron parsing - handles basic patterns\n const now = new Date(from);\n const next = new Date(now);\n\n // Start from the next minute\n next.setSeconds(0);\n next.setMilliseconds(0);\n next.setMinutes(next.getMinutes() + 1);\n\n // Try to find next valid time (up to 1 year)\n const maxIterations = 365 * 24 * 60; // 1 year in minutes\n for (let i = 0; i < maxIterations; i++) {\n const matches =\n matchesCronField(minute, next.getMinutes()) &&\n matchesCronField(hour, next.getHours()) &&\n matchesCronField(dayOfMonth, next.getDate()) &&\n matchesCronField(month, next.getMonth() + 1) &&\n matchesCronField(dayOfWeek, next.getDay());\n\n if (matches) {\n return next;\n }\n\n next.setMinutes(next.getMinutes() + 1);\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if a value matches a cron field pattern\n */\nfunction matchesCronField(pattern: string, value: number): boolean {\n if (pattern === '*') return true;\n\n // Handle step values: */5, */15, etc.\n if (pattern.startsWith('*/')) {\n const step = parseInt(pattern.slice(2), 10);\n return value % step === 0;\n }\n\n // Handle ranges: 1-5\n if (pattern.includes('-')) {\n const [start, end] = pattern.split('-').map((n) => parseInt(n, 10));\n return value >= start && value <= end;\n }\n\n // Handle lists: 1,3,5\n if (pattern.includes(',')) {\n const values = pattern.split(',').map((n) => parseInt(n, 10));\n return values.includes(value);\n }\n\n // Simple number\n return parseInt(pattern, 10) === value;\n}\n\n/**\n * Check if current time is within a maintenance window\n */\nfunction isInMaintenanceWindow(\n window: TaskSchedule['window'],\n now: Date = new Date()\n): boolean {\n if (!window) return false;\n\n const dayOfWeek = now.getDay();\n if (!window.daysOfWeek.includes(dayOfWeek)) return false;\n\n // Parse times\n const [startHour, startMin] = window.startTime.split(':').map(Number);\n const [endHour, endMin] = window.endTime.split(':').map(Number);\n\n const currentMinutes = now.getHours() * 60 + now.getMinutes();\n const startMinutes = startHour * 60 + startMin;\n const endMinutes = endHour * 60 + endMin;\n\n // Handle overnight windows\n if (endMinutes < startMinutes) {\n return currentMinutes >= startMinutes || currentMinutes < endMinutes;\n }\n\n return currentMinutes >= startMinutes && currentMinutes < endMinutes;\n}\n\n/**\n * Calculate next run time for a maintenance window\n */\nfunction calculateNextWindowRun(\n window: TaskSchedule['window'],\n from: Date = new Date()\n): Date | null {\n if (!window) return null;\n\n const [startHour, startMin] = window.startTime.split(':').map(Number);\n\n // Try each day for the next 7 days\n for (let dayOffset = 0; dayOffset <= 7; dayOffset++) {\n const candidate = new Date(from);\n candidate.setDate(candidate.getDate() + dayOffset);\n candidate.setHours(startHour, startMin, 0, 0);\n\n // Skip if in the past\n if (candidate <= from) continue;\n\n // Check if day matches\n if (window.daysOfWeek.includes(candidate.getDay())) {\n return candidate;\n }\n }\n\n return null;\n}\n\n/**\n * Create a ScheduleManager instance\n */\nexport function createScheduleManager(db: DatabaseAdapter): ScheduleManager {\n /**\n * Calculate the next run time for a schedule\n */\n function calculateNextRun(schedule: TaskSchedule): Date | null {\n const now = new Date();\n\n switch (schedule.type) {\n case 'once':\n // For one-time tasks, return the scheduled time if it's in the future\n if (schedule.executeAt && new Date(schedule.executeAt) > now) {\n return new Date(schedule.executeAt);\n }\n return null;\n\n case 'recurring':\n // Parse cron expression\n if (schedule.cron) {\n return parseCronNextRun(schedule.cron, now);\n }\n return null;\n\n case 'window':\n // Calculate next maintenance window start\n if (schedule.window) {\n return calculateNextWindowRun(schedule.window, now);\n }\n return null;\n\n default:\n return null;\n }\n }\n\n return {\n async get(id: string): Promise<ScheduledTask | null> {\n if (!db.findScheduledTask) {\n throw new Error('Database adapter does not support task scheduling');\n }\n return db.findScheduledTask(id);\n },\n\n async list(filter?: ScheduledTaskFilter): Promise<ScheduledTaskListResult> {\n if (!db.listScheduledTasks) {\n throw new Error('Database adapter does not support task scheduling');\n }\n return db.listScheduledTasks(filter);\n },\n\n async create(data: CreateScheduledTaskInput): Promise<ScheduledTask> {\n if (!db.createScheduledTask) {\n throw new Error('Database adapter does not support task scheduling');\n }\n\n // Calculate initial next run time\n const nextRunAt = calculateNextRun(data.schedule);\n\n // Create task with calculated next run\n const task = await db.createScheduledTask({\n ...data,\n // Note: nextRunAt is set by the database adapter based on schedule\n });\n\n // Update next run time if needed\n if (nextRunAt && db.updateScheduledTask) {\n return db.updateScheduledTask(task.id, {\n ...data,\n });\n }\n\n return task;\n },\n\n async update(id: string, data: UpdateScheduledTaskInput): Promise<ScheduledTask> {\n if (!db.updateScheduledTask || !db.findScheduledTask) {\n throw new Error('Database adapter does not support task scheduling');\n }\n\n const existing = await db.findScheduledTask(id);\n if (!existing) {\n throw new Error(`Scheduled task not found: ${id}`);\n }\n\n return db.updateScheduledTask(id, data);\n },\n\n async delete(id: string): Promise<void> {\n if (!db.deleteScheduledTask) {\n throw new Error('Database adapter does not support task scheduling');\n }\n await db.deleteScheduledTask(id);\n },\n\n async pause(id: string): Promise<ScheduledTask> {\n if (!db.updateScheduledTask || !db.findScheduledTask) {\n throw new Error('Database adapter does not support task scheduling');\n }\n\n const task = await db.findScheduledTask(id);\n if (!task) {\n throw new Error(`Scheduled task not found: ${id}`);\n }\n\n if (task.status === 'paused') {\n return task;\n }\n\n return db.updateScheduledTask(id, { status: 'paused' });\n },\n\n async resume(id: string): Promise<ScheduledTask> {\n if (!db.updateScheduledTask || !db.findScheduledTask) {\n throw new Error('Database adapter does not support task scheduling');\n }\n\n const task = await db.findScheduledTask(id);\n if (!task) {\n throw new Error(`Scheduled task not found: ${id}`);\n }\n\n if (task.status !== 'paused') {\n return task;\n }\n\n // Recalculate next run time\n const nextRunAt = calculateNextRun(task.schedule);\n\n return db.updateScheduledTask(id, { status: 'active' });\n },\n\n async runNow(id: string): Promise<TaskExecution> {\n if (\n !db.findScheduledTask ||\n !db.createTaskExecution ||\n !db.updateScheduledTask\n ) {\n throw new Error('Database adapter does not support task scheduling');\n }\n\n const task = await db.findScheduledTask(id);\n if (!task) {\n throw new Error(`Scheduled task not found: ${id}`);\n }\n\n // Create execution record\n const execution = await db.createTaskExecution({ taskId: id });\n\n // Update task last run time\n await db.updateScheduledTask(id, {});\n\n return execution;\n },\n\n async getUpcoming(hours: number): Promise<ScheduledTask[]> {\n if (!db.getUpcomingTasks) {\n throw new Error('Database adapter does not support task scheduling');\n }\n return db.getUpcomingTasks(hours);\n },\n\n async getExecutions(taskId: string, limit: number = 10): Promise<TaskExecution[]> {\n if (!db.listTaskExecutions) {\n throw new Error('Database adapter does not support task scheduling');\n }\n return db.listTaskExecutions(taskId, limit);\n },\n\n calculateNextRun,\n };\n}\n\n/**\n * Export utility functions\n */\nexport { parseCronNextRun, isInMaintenanceWindow, calculateNextWindowRun };\n","/**\n * OpenMDM Message Queue Manager\n *\n * Provides persistent message queue management for the MDM system.\n * Ensures reliable message delivery with retry and expiration handling.\n */\n\nimport type {\n MessageQueueManager,\n QueuedMessage,\n EnqueueMessageInput,\n QueueStats,\n DatabaseAdapter,\n} from './types';\n\n/**\n * Default maximum attempts for message delivery\n */\nconst DEFAULT_MAX_ATTEMPTS = 3;\n\n/**\n * Default TTL in seconds (24 hours)\n */\nconst DEFAULT_TTL_SECONDS = 86400;\n\n/**\n * Create a MessageQueueManager instance\n */\nexport function createMessageQueueManager(db: DatabaseAdapter): MessageQueueManager {\n return {\n async enqueue(message: EnqueueMessageInput): Promise<QueuedMessage> {\n if (!db.enqueueMessage) {\n throw new Error('Database adapter does not support message queue');\n }\n\n // Set defaults\n const enrichedMessage: EnqueueMessageInput = {\n ...message,\n priority: message.priority ?? 'normal',\n maxAttempts: message.maxAttempts ?? DEFAULT_MAX_ATTEMPTS,\n ttlSeconds: message.ttlSeconds ?? DEFAULT_TTL_SECONDS,\n };\n\n return db.enqueueMessage(enrichedMessage);\n },\n\n async enqueueBatch(messages: EnqueueMessageInput[]): Promise<QueuedMessage[]> {\n if (!db.enqueueMessage) {\n throw new Error('Database adapter does not support message queue');\n }\n\n const results: QueuedMessage[] = [];\n\n for (const message of messages) {\n const enrichedMessage: EnqueueMessageInput = {\n ...message,\n priority: message.priority ?? 'normal',\n maxAttempts: message.maxAttempts ?? DEFAULT_MAX_ATTEMPTS,\n ttlSeconds: message.ttlSeconds ?? DEFAULT_TTL_SECONDS,\n };\n\n const queued = await db.enqueueMessage(enrichedMessage);\n results.push(queued);\n }\n\n return results;\n },\n\n async dequeue(deviceId: string, limit: number = 10): Promise<QueuedMessage[]> {\n if (!db.dequeueMessages) {\n throw new Error('Database adapter does not support message queue');\n }\n return db.dequeueMessages(deviceId, limit);\n },\n\n async acknowledge(messageId: string): Promise<void> {\n if (!db.acknowledgeMessage) {\n throw new Error('Database adapter does not support message queue');\n }\n await db.acknowledgeMessage(messageId);\n },\n\n async fail(messageId: string, error: string): Promise<void> {\n if (!db.failMessage) {\n throw new Error('Database adapter does not support message queue');\n }\n await db.failMessage(messageId, error);\n },\n\n async retryFailed(maxAttempts: number = DEFAULT_MAX_ATTEMPTS): Promise<number> {\n if (!db.retryFailedMessages) {\n throw new Error('Database adapter does not support message queue');\n }\n return db.retryFailedMessages(maxAttempts);\n },\n\n async purgeExpired(): Promise<number> {\n if (!db.purgeExpiredMessages) {\n throw new Error('Database adapter does not support message queue');\n }\n return db.purgeExpiredMessages();\n },\n\n async getStats(tenantId?: string): Promise<QueueStats> {\n if (!db.getQueueStats) {\n throw new Error('Database adapter does not support message queue');\n }\n return db.getQueueStats(tenantId);\n },\n\n async peek(deviceId: string, limit: number = 10): Promise<QueuedMessage[]> {\n if (!db.peekMessages) {\n throw new Error('Database adapter does not support message queue');\n }\n return db.peekMessages(deviceId, limit);\n },\n };\n}\n\n/**\n * Message priority weights for sorting\n */\nexport const PRIORITY_WEIGHTS = {\n high: 3,\n normal: 2,\n low: 1,\n} as const;\n\n/**\n * Compare messages by priority (higher priority first)\n */\nexport function compareByPriority(a: QueuedMessage, b: QueuedMessage): number {\n return PRIORITY_WEIGHTS[b.priority] - PRIORITY_WEIGHTS[a.priority];\n}\n\n/**\n * Check if a message has expired\n */\nexport function isMessageExpired(message: QueuedMessage): boolean {\n if (!message.expiresAt) return false;\n return new Date(message.expiresAt) < new Date();\n}\n\n/**\n * Check if a message can be retried\n */\nexport function canRetryMessage(message: QueuedMessage): boolean {\n return message.status === 'failed' && message.attempts < message.maxAttempts;\n}\n\n/**\n * Calculate exponential backoff delay for retries\n */\nexport function calculateBackoffDelay(\n attempts: number,\n baseDelayMs: number = 1000,\n maxDelayMs: number = 300000 // 5 minutes\n): number {\n const delay = baseDelayMs * Math.pow(2, attempts - 1);\n return Math.min(delay, maxDelayMs);\n}\n","/**\n * OpenMDM Dashboard Manager\n *\n * Provides analytics and statistics for the MDM dashboard.\n * Aggregates data from devices, commands, and applications.\n */\n\nimport type {\n DashboardManager,\n DashboardStats,\n DeviceStatusBreakdown,\n EnrollmentTrendPoint,\n CommandSuccessRates,\n AppInstallationSummary,\n DatabaseAdapter,\n DeviceStatus,\n} from './types';\n\n/**\n * Create a DashboardManager instance\n */\nexport function createDashboardManager(db: DatabaseAdapter): DashboardManager {\n return {\n async getStats(_tenantId?: string): Promise<DashboardStats> {\n // Use database method if available\n if (db.getDashboardStats) {\n return db.getDashboardStats(_tenantId);\n }\n\n // Fallback: compute from individual queries\n const devices = await db.listDevices({\n limit: 10000, // Get all for counting\n });\n\n const deviceStats = {\n total: devices.total,\n enrolled: devices.devices.filter((d) => d.status === 'enrolled').length,\n active: devices.devices.filter((d) => d.status === 'enrolled').length, // 'active' = 'enrolled' for dashboard\n blocked: devices.devices.filter((d) => d.status === 'blocked').length,\n pending: devices.devices.filter((d) => d.status === 'pending').length,\n };\n\n const allPolicies = await db.listPolicies();\n const policyStats = {\n total: allPolicies.length,\n deployed: allPolicies.filter((p) => p.isDefault).length,\n };\n\n const allApps = await db.listApplications();\n const appStats = {\n total: allApps.length,\n deployed: allApps.length, // All apps in db are considered deployed\n };\n\n // Command stats - get recent commands\n const now = new Date();\n const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);\n const allCommands = await db.listCommands({ limit: 10000 });\n\n const pendingCommands = allCommands.filter((c) => c.status === 'pending');\n const last24hCommands = allCommands.filter(\n (c) => new Date(c.createdAt) >= yesterday\n );\n\n const commandStats = {\n pendingCount: pendingCommands.length,\n last24hTotal: last24hCommands.length,\n last24hSuccess: last24hCommands.filter((c) => c.status === 'completed').length,\n last24hFailed: last24hCommands.filter((c) => c.status === 'failed').length,\n };\n\n // Group stats\n const allGroups = await db.listGroups();\n let groupsWithDevices = 0;\n for (const group of allGroups) {\n const groupDevices = await db.listDevicesInGroup(group.id);\n if (groupDevices.length > 0) groupsWithDevices++;\n }\n\n return {\n devices: deviceStats,\n policies: policyStats,\n applications: appStats,\n commands: commandStats,\n groups: {\n total: allGroups.length,\n withDevices: groupsWithDevices,\n },\n };\n },\n\n async getDeviceStatusBreakdown(_tenantId?: string): Promise<DeviceStatusBreakdown> {\n if (db.getDeviceStatusBreakdown) {\n return db.getDeviceStatusBreakdown(_tenantId);\n }\n\n const devices = await db.listDevices({\n limit: 10000,\n });\n\n const byStatus: Record<DeviceStatus, number> = {\n pending: 0,\n enrolled: 0,\n blocked: 0,\n unenrolled: 0,\n };\n\n const byOs: Record<string, number> = {};\n const byManufacturer: Record<string, number> = {};\n const byModel: Record<string, number> = {};\n\n for (const device of devices.devices) {\n // By status\n byStatus[device.status]++;\n\n // By OS version\n const osKey = device.osVersion || 'Unknown';\n byOs[osKey] = (byOs[osKey] || 0) + 1;\n\n // By manufacturer\n const mfr = device.manufacturer || 'Unknown';\n byManufacturer[mfr] = (byManufacturer[mfr] || 0) + 1;\n\n // By model\n const model = device.model || 'Unknown';\n byModel[model] = (byModel[model] || 0) + 1;\n }\n\n return {\n byStatus,\n byOs,\n byManufacturer,\n byModel,\n };\n },\n\n async getEnrollmentTrend(days: number, _tenantId?: string): Promise<EnrollmentTrendPoint[]> {\n if (db.getEnrollmentTrend) {\n return db.getEnrollmentTrend(days, _tenantId);\n }\n\n // Generate trend data from event history\n const now = new Date();\n const startDate = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);\n\n // Get enrollment events\n const events = await db.listEvents({\n type: 'device.enrolled',\n startDate,\n limit: 10000,\n });\n\n const unenrollEvents = await db.listEvents({\n type: 'device.unenrolled',\n startDate,\n limit: 10000,\n });\n\n // Group by date\n const trendByDate = new Map<string, { enrolled: number; unenrolled: number }>();\n\n // Initialize all dates\n for (let i = 0; i < days; i++) {\n const date = new Date(startDate.getTime() + i * 24 * 60 * 60 * 1000);\n const dateKey = date.toISOString().split('T')[0];\n trendByDate.set(dateKey, { enrolled: 0, unenrolled: 0 });\n }\n\n // Count events\n for (const event of events) {\n const dateKey = new Date(event.createdAt).toISOString().split('T')[0];\n const entry = trendByDate.get(dateKey);\n if (entry) {\n entry.enrolled++;\n }\n }\n\n for (const event of unenrollEvents) {\n const dateKey = new Date(event.createdAt).toISOString().split('T')[0];\n const entry = trendByDate.get(dateKey);\n if (entry) {\n entry.unenrolled++;\n }\n }\n\n // Get initial device count\n const initialDevices = await db.listDevices({\n limit: 10000,\n });\n let runningTotal = initialDevices.total;\n\n // Build trend points\n const result: EnrollmentTrendPoint[] = [];\n const sortedDates = Array.from(trendByDate.keys()).sort();\n\n for (const dateKey of sortedDates) {\n const entry = trendByDate.get(dateKey)!;\n const netChange = entry.enrolled - entry.unenrolled;\n runningTotal += netChange;\n\n result.push({\n date: new Date(dateKey),\n enrolled: entry.enrolled,\n unenrolled: entry.unenrolled,\n netChange,\n totalDevices: runningTotal,\n });\n }\n\n return result;\n },\n\n async getCommandSuccessRates(_tenantId?: string): Promise<CommandSuccessRates> {\n if (db.getCommandSuccessRates) {\n return db.getCommandSuccessRates(_tenantId);\n }\n\n const now = new Date();\n const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);\n\n const commands = await db.listCommands({ limit: 10000 });\n\n // Overall stats\n const completed = commands.filter((c) => c.status === 'completed').length;\n const failed = commands.filter((c) => c.status === 'failed').length;\n const total = commands.length;\n\n // By type\n const byType: CommandSuccessRates['byType'] = {};\n for (const cmd of commands) {\n if (!byType[cmd.type]) {\n byType[cmd.type] = {\n total: 0,\n completed: 0,\n failed: 0,\n successRate: 0,\n };\n }\n byType[cmd.type].total++;\n if (cmd.status === 'completed') byType[cmd.type].completed++;\n if (cmd.status === 'failed') byType[cmd.type].failed++;\n }\n\n // Calculate success rates\n for (const type of Object.keys(byType)) {\n const stats = byType[type];\n const finishedCount = stats.completed + stats.failed;\n stats.successRate = finishedCount > 0 ? (stats.completed / finishedCount) * 100 : 0;\n }\n\n // Last 24h\n const last24hCommands = commands.filter(\n (c) => new Date(c.createdAt) >= yesterday\n );\n\n return {\n overall: {\n total,\n completed,\n failed,\n successRate:\n completed + failed > 0 ? (completed / (completed + failed)) * 100 : 0,\n },\n byType,\n last24h: {\n total: last24hCommands.length,\n completed: last24hCommands.filter((c) => c.status === 'completed').length,\n failed: last24hCommands.filter((c) => c.status === 'failed').length,\n pending: last24hCommands.filter((c) => c.status === 'pending').length,\n },\n };\n },\n\n async getAppInstallationSummary(_tenantId?: string): Promise<AppInstallationSummary> {\n if (db.getAppInstallationSummary) {\n return db.getAppInstallationSummary(_tenantId);\n }\n\n // Get all apps\n const apps = await db.listApplications();\n const appMap = new Map(apps.map((a) => [a.packageName, a]));\n\n // Get installation statuses if available\n const byStatus: Record<string, number> = {\n installed: 0,\n installing: 0,\n failed: 0,\n pending: 0,\n };\n\n // Count installed apps per device\n const installCounts: Record<string, number> = {};\n\n // Get devices to count installations\n const devices = await db.listDevices({\n limit: 10000,\n });\n\n for (const device of devices.devices) {\n if (device.installedApps) {\n for (const app of device.installedApps) {\n const key = app.packageName;\n installCounts[key] = (installCounts[key] || 0) + 1;\n byStatus['installed']++;\n }\n }\n }\n\n // Top installed apps\n const topInstalled = Object.entries(installCounts)\n .sort(([, a], [, b]) => b - a)\n .slice(0, 10)\n .map(([packageName, count]) => ({\n packageName,\n name: appMap.get(packageName)?.name || packageName,\n installedCount: count,\n }));\n\n return {\n total: Object.values(byStatus).reduce((a, b) => a + b, 0),\n byStatus,\n recentFailures: [], // Would need installation status tracking\n topInstalled,\n };\n },\n };\n}\n","/**\n * OpenMDM Plugin Storage Manager\n *\n * Provides persistent storage for plugin state.\n * Supports both database-backed and in-memory storage.\n */\n\nimport type { PluginStorageAdapter, DatabaseAdapter } from './types';\n\n/**\n * Create a PluginStorageAdapter backed by the database\n */\nexport function createPluginStorageAdapter(db: DatabaseAdapter): PluginStorageAdapter {\n return {\n async get<T>(pluginName: string, key: string): Promise<T | null> {\n if (db.getPluginValue) {\n const value = await db.getPluginValue(pluginName, key);\n return value as T | null;\n }\n\n // Fallback: not supported\n // Silently no-op: the plugin-storage contract treats missing\n // adapter methods as \"not configured\", which is the same\n // branch plugins handle via their in-memory fallback. A warn\n // log here would flood production with one line per hit.\n //\n return null;\n },\n\n async set<T>(pluginName: string, key: string, value: T): Promise<void> {\n if (db.setPluginValue) {\n await db.setPluginValue(pluginName, key, value);\n return;\n }\n\n // Silently no-op: the plugin-storage contract treats missing\n // adapter methods as \"not configured\", which is the same\n // branch plugins handle via their in-memory fallback. A warn\n // log here would flood production with one line per hit.\n //\n },\n\n async delete(pluginName: string, key: string): Promise<void> {\n if (db.deletePluginValue) {\n await db.deletePluginValue(pluginName, key);\n return;\n }\n\n // Silently no-op: the plugin-storage contract treats missing\n // adapter methods as \"not configured\", which is the same\n // branch plugins handle via their in-memory fallback. A warn\n // log here would flood production with one line per hit.\n //\n },\n\n async list(pluginName: string, prefix?: string): Promise<string[]> {\n if (db.listPluginKeys) {\n return db.listPluginKeys(pluginName, prefix);\n }\n\n // Silently no-op: the plugin-storage contract treats missing\n // adapter methods as \"not configured\", which is the same\n // branch plugins handle via their in-memory fallback. A warn\n // log here would flood production with one line per hit.\n //\n return [];\n },\n\n async clear(pluginName: string): Promise<void> {\n if (db.clearPluginData) {\n await db.clearPluginData(pluginName);\n return;\n }\n\n // Silently no-op: the plugin-storage contract treats missing\n // adapter methods as \"not configured\", which is the same\n // branch plugins handle via their in-memory fallback. A warn\n // log here would flood production with one line per hit.\n //\n },\n };\n}\n\n/**\n * Create an in-memory PluginStorageAdapter for testing\n */\nexport function createMemoryPluginStorageAdapter(): PluginStorageAdapter {\n const store = new Map<string, Map<string, unknown>>();\n\n function getPluginStore(pluginName: string): Map<string, unknown> {\n if (!store.has(pluginName)) {\n store.set(pluginName, new Map());\n }\n return store.get(pluginName)!;\n }\n\n return {\n async get<T>(pluginName: string, key: string): Promise<T | null> {\n const pluginStore = getPluginStore(pluginName);\n const value = pluginStore.get(key);\n return value === undefined ? null : (value as T);\n },\n\n async set<T>(pluginName: string, key: string, value: T): Promise<void> {\n const pluginStore = getPluginStore(pluginName);\n pluginStore.set(key, value);\n },\n\n async delete(pluginName: string, key: string): Promise<void> {\n const pluginStore = getPluginStore(pluginName);\n pluginStore.delete(key);\n },\n\n async list(pluginName: string, prefix?: string): Promise<string[]> {\n const pluginStore = getPluginStore(pluginName);\n const keys = Array.from(pluginStore.keys());\n\n if (prefix) {\n return keys.filter((k) => k.startsWith(prefix));\n }\n\n return keys;\n },\n\n async clear(pluginName: string): Promise<void> {\n store.delete(pluginName);\n },\n };\n}\n\n/**\n * Plugin storage utilities\n */\n\n/**\n * Create a namespaced key for plugin storage\n */\nexport function createPluginKey(namespace: string, ...parts: string[]): string {\n return [namespace, ...parts].join(':');\n}\n\n/**\n * Parse a namespaced key\n */\nexport function parsePluginKey(key: string): { namespace: string; parts: string[] } {\n const [namespace, ...parts] = key.split(':');\n return { namespace, parts };\n}\n","/**\n * OpenMDM Database Schema Definition\n *\n * This schema defines the structure for MDM data storage.\n * Database adapters implement this schema for their specific ORM/database.\n *\n * Tables:\n * - mdm_devices: Enrolled devices and their state\n * - mdm_policies: Device policies and configurations\n * - mdm_applications: Registered applications for deployment\n * - mdm_commands: Command queue for device operations\n * - mdm_events: Event log for device activities\n * - mdm_groups: Device grouping for bulk operations\n * - mdm_device_groups: Many-to-many device-group relationships\n * - mdm_push_tokens: FCM/MQTT push notification tokens\n * - mdm_app_deployments: App-to-policy/group deployment mappings\n * - mdm_app_versions: App version history for rollback support\n * - mdm_rollbacks: Rollback operation history and status\n * - mdm_webhook_endpoints: Outbound webhook configuration\n * - mdm_webhook_deliveries: Webhook delivery history\n * - mdm_tenants: Multi-tenant organization isolation\n * - mdm_roles: RBAC role definitions\n * - mdm_users: User accounts for authorization\n * - mdm_user_roles: User-role mapping\n * - mdm_audit_logs: Compliance and audit trail\n * - mdm_scheduled_tasks: Scheduled task definitions\n * - mdm_task_executions: Task execution history\n * - mdm_message_queue: Persistent push message queue\n * - mdm_plugin_storage: Plugin state persistence\n */\n\n// ============================================\n// Schema Column Types\n// ============================================\n\nexport type ColumnType =\n | 'string'\n | 'text'\n | 'integer'\n | 'bigint'\n | 'boolean'\n | 'datetime'\n | 'json'\n | 'enum';\n\nexport interface ColumnDefinition {\n type: ColumnType;\n nullable?: boolean;\n primaryKey?: boolean;\n unique?: boolean;\n default?: unknown;\n enumValues?: string[];\n references?: {\n table: string;\n column: string;\n onDelete?: 'cascade' | 'set null' | 'restrict';\n };\n}\n\nexport interface IndexDefinition {\n columns: string[];\n unique?: boolean;\n name?: string;\n}\n\nexport interface TableDefinition {\n columns: Record<string, ColumnDefinition>;\n indexes?: IndexDefinition[];\n}\n\nexport interface SchemaDefinition {\n tables: Record<string, TableDefinition>;\n}\n\n// ============================================\n// OpenMDM Schema\n// ============================================\n\nexport const mdmSchema: SchemaDefinition = {\n tables: {\n // ----------------------------------------\n // Devices Table\n // ----------------------------------------\n mdm_devices: {\n columns: {\n id: { type: 'string', primaryKey: true },\n external_id: { type: 'string', nullable: true },\n enrollment_id: { type: 'string', unique: true },\n status: {\n type: 'enum',\n enumValues: ['pending', 'enrolled', 'unenrolled', 'blocked'],\n default: 'pending',\n },\n\n // Device Info\n model: { type: 'string', nullable: true },\n manufacturer: { type: 'string', nullable: true },\n os_version: { type: 'string', nullable: true },\n serial_number: { type: 'string', nullable: true },\n imei: { type: 'string', nullable: true },\n mac_address: { type: 'string', nullable: true },\n android_id: { type: 'string', nullable: true },\n\n // MDM State\n policy_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_policies', column: 'id', onDelete: 'set null' },\n },\n agent_version: { type: 'string', nullable: true }, // MDM agent version installed on device\n last_heartbeat: { type: 'datetime', nullable: true },\n last_sync: { type: 'datetime', nullable: true },\n\n // Telemetry (denormalized for quick access)\n battery_level: { type: 'integer', nullable: true },\n storage_used: { type: 'bigint', nullable: true },\n storage_total: { type: 'bigint', nullable: true },\n latitude: { type: 'string', nullable: true }, // Stored as string for precision\n longitude: { type: 'string', nullable: true },\n location_timestamp: { type: 'datetime', nullable: true },\n\n // JSON fields\n installed_apps: { type: 'json', nullable: true },\n tags: { type: 'json', nullable: true },\n metadata: { type: 'json', nullable: true },\n\n // Timestamps\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['enrollment_id'], unique: true },\n { columns: ['status'] },\n { columns: ['policy_id'] },\n { columns: ['last_heartbeat'] },\n { columns: ['mac_address'] },\n { columns: ['serial_number'] },\n ],\n },\n\n // ----------------------------------------\n // Policies Table\n // ----------------------------------------\n mdm_policies: {\n columns: {\n id: { type: 'string', primaryKey: true },\n name: { type: 'string' },\n description: { type: 'text', nullable: true },\n is_default: { type: 'boolean', default: false },\n settings: { type: 'json' },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['name'] },\n { columns: ['is_default'] },\n ],\n },\n\n // ----------------------------------------\n // Applications Table\n // ----------------------------------------\n mdm_applications: {\n columns: {\n id: { type: 'string', primaryKey: true },\n name: { type: 'string' },\n package_name: { type: 'string' },\n version: { type: 'string' },\n version_code: { type: 'integer' },\n url: { type: 'string' },\n hash: { type: 'string', nullable: true }, // SHA-256\n size: { type: 'bigint', nullable: true },\n min_sdk_version: { type: 'integer', nullable: true },\n\n // Deployment settings\n show_icon: { type: 'boolean', default: true },\n run_after_install: { type: 'boolean', default: false },\n run_at_boot: { type: 'boolean', default: false },\n is_system: { type: 'boolean', default: false },\n\n // State\n is_active: { type: 'boolean', default: true },\n\n // Metadata\n metadata: { type: 'json', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['package_name'] },\n { columns: ['package_name', 'version'], unique: true },\n { columns: ['is_active'] },\n ],\n },\n\n // ----------------------------------------\n // Commands Table\n // ----------------------------------------\n mdm_commands: {\n columns: {\n id: { type: 'string', primaryKey: true },\n device_id: {\n type: 'string',\n references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },\n },\n type: { type: 'string' },\n payload: { type: 'json', nullable: true },\n status: {\n type: 'enum',\n enumValues: ['pending', 'sent', 'acknowledged', 'completed', 'failed', 'cancelled'],\n default: 'pending',\n },\n result: { type: 'json', nullable: true },\n error: { type: 'text', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n sent_at: { type: 'datetime', nullable: true },\n acknowledged_at: { type: 'datetime', nullable: true },\n completed_at: { type: 'datetime', nullable: true },\n },\n indexes: [\n { columns: ['device_id'] },\n { columns: ['status'] },\n { columns: ['device_id', 'status'] },\n { columns: ['created_at'] },\n ],\n },\n\n // ----------------------------------------\n // Events Table\n // ----------------------------------------\n mdm_events: {\n columns: {\n id: { type: 'string', primaryKey: true },\n device_id: {\n type: 'string',\n references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },\n },\n type: { type: 'string' },\n payload: { type: 'json' },\n created_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['device_id'] },\n { columns: ['type'] },\n { columns: ['device_id', 'type'] },\n { columns: ['created_at'] },\n ],\n },\n\n // ----------------------------------------\n // Groups Table\n // ----------------------------------------\n mdm_groups: {\n columns: {\n id: { type: 'string', primaryKey: true },\n name: { type: 'string' },\n description: { type: 'text', nullable: true },\n policy_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_policies', column: 'id', onDelete: 'set null' },\n },\n parent_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_groups', column: 'id', onDelete: 'set null' },\n },\n metadata: { type: 'json', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['name'] },\n { columns: ['policy_id'] },\n { columns: ['parent_id'] },\n ],\n },\n\n // ----------------------------------------\n // Device Groups (Many-to-Many)\n // ----------------------------------------\n mdm_device_groups: {\n columns: {\n device_id: {\n type: 'string',\n references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },\n },\n group_id: {\n type: 'string',\n references: { table: 'mdm_groups', column: 'id', onDelete: 'cascade' },\n },\n created_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['device_id', 'group_id'], unique: true },\n { columns: ['group_id'] },\n ],\n },\n\n // ----------------------------------------\n // Push Tokens (for FCM/MQTT registration)\n // ----------------------------------------\n mdm_push_tokens: {\n columns: {\n id: { type: 'string', primaryKey: true },\n device_id: {\n type: 'string',\n references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },\n },\n provider: {\n type: 'enum',\n enumValues: ['fcm', 'mqtt', 'websocket'],\n },\n token: { type: 'string' },\n is_active: { type: 'boolean', default: true },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['device_id'] },\n { columns: ['provider', 'token'], unique: true },\n { columns: ['is_active'] },\n ],\n },\n\n // ----------------------------------------\n // Application Deployments (Which apps go to which policies/groups)\n // ----------------------------------------\n mdm_app_deployments: {\n columns: {\n id: { type: 'string', primaryKey: true },\n application_id: {\n type: 'string',\n references: { table: 'mdm_applications', column: 'id', onDelete: 'cascade' },\n },\n // Target can be policy or group\n target_type: {\n type: 'enum',\n enumValues: ['policy', 'group'],\n },\n target_id: { type: 'string' },\n action: {\n type: 'enum',\n enumValues: ['install', 'update', 'uninstall'],\n default: 'install',\n },\n is_required: { type: 'boolean', default: false },\n created_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['application_id'] },\n { columns: ['target_type', 'target_id'] },\n ],\n },\n\n // ----------------------------------------\n // App Versions (Version history for rollback support)\n // ----------------------------------------\n mdm_app_versions: {\n columns: {\n id: { type: 'string', primaryKey: true },\n application_id: {\n type: 'string',\n references: { table: 'mdm_applications', column: 'id', onDelete: 'cascade' },\n },\n package_name: { type: 'string' },\n version: { type: 'string' },\n version_code: { type: 'integer' },\n url: { type: 'string' },\n hash: { type: 'string', nullable: true },\n size: { type: 'bigint', nullable: true },\n release_notes: { type: 'text', nullable: true },\n is_minimum_version: { type: 'boolean', default: false },\n created_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['application_id'] },\n { columns: ['package_name'] },\n { columns: ['package_name', 'version_code'], unique: true },\n { columns: ['is_minimum_version'] },\n ],\n },\n\n // ----------------------------------------\n // App Rollbacks (Rollback history and status)\n // ----------------------------------------\n mdm_rollbacks: {\n columns: {\n id: { type: 'string', primaryKey: true },\n device_id: {\n type: 'string',\n references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },\n },\n package_name: { type: 'string' },\n from_version: { type: 'string' },\n from_version_code: { type: 'integer' },\n to_version: { type: 'string' },\n to_version_code: { type: 'integer' },\n reason: { type: 'text', nullable: true },\n status: {\n type: 'enum',\n enumValues: ['pending', 'in_progress', 'completed', 'failed'],\n default: 'pending',\n },\n error: { type: 'text', nullable: true },\n initiated_by: { type: 'string', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n completed_at: { type: 'datetime', nullable: true },\n },\n indexes: [\n { columns: ['device_id'] },\n { columns: ['package_name'] },\n { columns: ['device_id', 'package_name'] },\n { columns: ['status'] },\n { columns: ['created_at'] },\n ],\n },\n\n // ----------------------------------------\n // Webhook Endpoints (For outbound webhook configuration storage)\n // ----------------------------------------\n mdm_webhook_endpoints: {\n columns: {\n id: { type: 'string', primaryKey: true },\n url: { type: 'string' },\n events: { type: 'json' }, // Array of event types or ['*']\n headers: { type: 'json', nullable: true },\n enabled: { type: 'boolean', default: true },\n description: { type: 'text', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['enabled'] },\n ],\n },\n\n // ----------------------------------------\n // Webhook Deliveries (Delivery history and status)\n // ----------------------------------------\n mdm_webhook_deliveries: {\n columns: {\n id: { type: 'string', primaryKey: true },\n endpoint_id: {\n type: 'string',\n references: { table: 'mdm_webhook_endpoints', column: 'id', onDelete: 'cascade' },\n },\n event_id: { type: 'string' },\n event_type: { type: 'string' },\n payload: { type: 'json' },\n status: {\n type: 'enum',\n enumValues: ['pending', 'success', 'failed'],\n default: 'pending',\n },\n status_code: { type: 'integer', nullable: true },\n error: { type: 'text', nullable: true },\n retry_count: { type: 'integer', default: 0 },\n created_at: { type: 'datetime', default: 'now' },\n delivered_at: { type: 'datetime', nullable: true },\n },\n indexes: [\n { columns: ['endpoint_id'] },\n { columns: ['event_type'] },\n { columns: ['status'] },\n { columns: ['created_at'] },\n ],\n },\n\n // ----------------------------------------\n // Tenants Table (Multi-tenancy)\n // ----------------------------------------\n mdm_tenants: {\n columns: {\n id: { type: 'string', primaryKey: true },\n name: { type: 'string' },\n slug: { type: 'string', unique: true },\n status: {\n type: 'enum',\n enumValues: ['active', 'suspended', 'pending'],\n default: 'pending',\n },\n settings: { type: 'json', nullable: true },\n metadata: { type: 'json', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['slug'], unique: true },\n { columns: ['status'] },\n ],\n },\n\n // ----------------------------------------\n // Roles Table (RBAC)\n // ----------------------------------------\n mdm_roles: {\n columns: {\n id: { type: 'string', primaryKey: true },\n tenant_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_tenants', column: 'id', onDelete: 'cascade' },\n },\n name: { type: 'string' },\n description: { type: 'text', nullable: true },\n permissions: { type: 'json' },\n is_system: { type: 'boolean', default: false },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['tenant_id'] },\n { columns: ['name'] },\n { columns: ['tenant_id', 'name'], unique: true },\n ],\n },\n\n // ----------------------------------------\n // Users Table (RBAC)\n // ----------------------------------------\n mdm_users: {\n columns: {\n id: { type: 'string', primaryKey: true },\n tenant_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_tenants', column: 'id', onDelete: 'cascade' },\n },\n email: { type: 'string' },\n name: { type: 'string', nullable: true },\n status: {\n type: 'enum',\n enumValues: ['active', 'inactive', 'pending'],\n default: 'pending',\n },\n metadata: { type: 'json', nullable: true },\n last_login_at: { type: 'datetime', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['tenant_id'] },\n { columns: ['email'] },\n { columns: ['tenant_id', 'email'], unique: true },\n { columns: ['status'] },\n ],\n },\n\n // ----------------------------------------\n // User Roles (Many-to-Many)\n // ----------------------------------------\n mdm_user_roles: {\n columns: {\n user_id: {\n type: 'string',\n references: { table: 'mdm_users', column: 'id', onDelete: 'cascade' },\n },\n role_id: {\n type: 'string',\n references: { table: 'mdm_roles', column: 'id', onDelete: 'cascade' },\n },\n created_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['user_id', 'role_id'], unique: true },\n { columns: ['user_id'] },\n { columns: ['role_id'] },\n ],\n },\n\n // ----------------------------------------\n // Audit Logs Table\n // ----------------------------------------\n mdm_audit_logs: {\n columns: {\n id: { type: 'string', primaryKey: true },\n tenant_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_tenants', column: 'id', onDelete: 'cascade' },\n },\n user_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_users', column: 'id', onDelete: 'set null' },\n },\n action: { type: 'string' },\n resource: { type: 'string' },\n resource_id: { type: 'string', nullable: true },\n details: { type: 'json', nullable: true },\n ip_address: { type: 'string', nullable: true },\n user_agent: { type: 'text', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['tenant_id'] },\n { columns: ['user_id'] },\n { columns: ['action'] },\n { columns: ['resource'] },\n { columns: ['resource', 'resource_id'] },\n { columns: ['created_at'] },\n ],\n },\n\n // ----------------------------------------\n // Scheduled Tasks Table\n // ----------------------------------------\n mdm_scheduled_tasks: {\n columns: {\n id: { type: 'string', primaryKey: true },\n tenant_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_tenants', column: 'id', onDelete: 'cascade' },\n },\n name: { type: 'string' },\n description: { type: 'text', nullable: true },\n task_type: {\n type: 'enum',\n enumValues: ['command', 'policy_update', 'app_install', 'maintenance', 'custom'],\n },\n schedule: { type: 'json' },\n target: { type: 'json', nullable: true },\n payload: { type: 'json', nullable: true },\n status: {\n type: 'enum',\n enumValues: ['active', 'paused', 'completed', 'failed'],\n default: 'active',\n },\n next_run_at: { type: 'datetime', nullable: true },\n last_run_at: { type: 'datetime', nullable: true },\n max_retries: { type: 'integer', default: 3 },\n retry_count: { type: 'integer', default: 0 },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['tenant_id'] },\n { columns: ['task_type'] },\n { columns: ['status'] },\n { columns: ['next_run_at'] },\n ],\n },\n\n // ----------------------------------------\n // Task Executions Table\n // ----------------------------------------\n mdm_task_executions: {\n columns: {\n id: { type: 'string', primaryKey: true },\n task_id: {\n type: 'string',\n references: { table: 'mdm_scheduled_tasks', column: 'id', onDelete: 'cascade' },\n },\n status: {\n type: 'enum',\n enumValues: ['running', 'completed', 'failed'],\n default: 'running',\n },\n started_at: { type: 'datetime', default: 'now' },\n completed_at: { type: 'datetime', nullable: true },\n devices_processed: { type: 'integer', default: 0 },\n devices_succeeded: { type: 'integer', default: 0 },\n devices_failed: { type: 'integer', default: 0 },\n error: { type: 'text', nullable: true },\n details: { type: 'json', nullable: true },\n },\n indexes: [\n { columns: ['task_id'] },\n { columns: ['status'] },\n { columns: ['started_at'] },\n ],\n },\n\n // ----------------------------------------\n // Message Queue Table\n // ----------------------------------------\n mdm_message_queue: {\n columns: {\n id: { type: 'string', primaryKey: true },\n tenant_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_tenants', column: 'id', onDelete: 'cascade' },\n },\n device_id: {\n type: 'string',\n references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },\n },\n message_type: { type: 'string' },\n payload: { type: 'json' },\n priority: {\n type: 'enum',\n enumValues: ['high', 'normal', 'low'],\n default: 'normal',\n },\n status: {\n type: 'enum',\n enumValues: ['pending', 'processing', 'delivered', 'failed', 'expired'],\n default: 'pending',\n },\n attempts: { type: 'integer', default: 0 },\n max_attempts: { type: 'integer', default: 3 },\n last_attempt_at: { type: 'datetime', nullable: true },\n last_error: { type: 'text', nullable: true },\n expires_at: { type: 'datetime', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['tenant_id'] },\n { columns: ['device_id'] },\n { columns: ['status'] },\n { columns: ['priority'] },\n { columns: ['expires_at'] },\n { columns: ['device_id', 'status', 'priority'] },\n ],\n },\n\n // ----------------------------------------\n // Plugin Storage Table\n // ----------------------------------------\n mdm_plugin_storage: {\n columns: {\n plugin_name: { type: 'string' },\n key: { type: 'string' },\n value: { type: 'json' },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['plugin_name', 'key'], unique: true },\n { columns: ['plugin_name'] },\n ],\n },\n },\n};\n\n// ============================================\n// Schema Helper Functions\n// ============================================\n\n/**\n * Get all table names from the schema\n */\nexport function getTableNames(): string[] {\n return Object.keys(mdmSchema.tables);\n}\n\n/**\n * Get column names for a table\n */\nexport function getColumnNames(tableName: string): string[] {\n const table = mdmSchema.tables[tableName];\n if (!table) throw new Error(`Table ${tableName} not found in schema`);\n return Object.keys(table.columns);\n}\n\n/**\n * Get the primary key column for a table\n */\nexport function getPrimaryKey(tableName: string): string | null {\n const table = mdmSchema.tables[tableName];\n if (!table) throw new Error(`Table ${tableName} not found in schema`);\n\n for (const [name, def] of Object.entries(table.columns)) {\n if (def.primaryKey) return name;\n }\n return null;\n}\n\n/**\n * Convert snake_case column name to camelCase\n */\nexport function snakeToCamel(str: string): string {\n return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());\n}\n\n/**\n * Convert camelCase to snake_case\n */\nexport function camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/**\n * Transform object keys from snake_case to camelCase\n */\nexport function transformToCamelCase<T extends Record<string, unknown>>(\n obj: T\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[snakeToCamel(key)] = value;\n }\n return result;\n}\n\n/**\n * Transform object keys from camelCase to snake_case\n */\nexport function transformToSnakeCase<T extends Record<string, unknown>>(\n obj: T\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[camelToSnake(key)] = value;\n }\n return result;\n}\n","/**\n * OpenMDM Agent Wire Protocol v2.\n *\n * A unified response envelope for every `/agent/*` endpoint, plus the\n * version-selection rules that let the server serve v1 and v2 clients\n * simultaneously during a fleet rollout.\n *\n * ## Background\n *\n * Until now, agent-facing handlers returned either a bare JSON body\n * on success or raised an `HTTPException(401|404|5xx)` on failure.\n * The agent had to interpret five different HTTP status codes and\n * infer what to do about each — which in practice meant \"on auth\n * error, wipe local enrollment state and re-enroll\". That single\n * ambiguity produced the auto-unenroll behavior we saw in production:\n * a transient 401 or 404 was indistinguishable from \"you are really\n * unenrolled\", so the agent self-destructed.\n *\n * ## Protocol v2\n *\n * Every agent-facing endpoint replies with HTTP 200 and a body of\n * shape {@link AgentResponse}:\n *\n * ```json\n * { \"ok\": true, \"action\": \"none\", \"data\": { ... } }\n * { \"ok\": false, \"action\": \"retry\", \"message\": \"...\" }\n * { \"ok\": false, \"action\": \"reauth\", \"message\": \"...\" }\n * { \"ok\": false, \"action\": \"unenroll\", \"message\": \"...\" }\n * ```\n *\n * - `ok` is the boolean the agent checks first.\n * - `action` is the *only* field the agent reads to decide what to do\n * next. There is exactly one handler per action on the client, so\n * adding a new server response path is a matter of picking an\n * existing action.\n * - `data` carries the handler-specific payload (heartbeat response,\n * policy update, etc.) on success.\n * - `message` is a human-readable hint, for logs.\n *\n * HTTP 5xx is still used for real infrastructure failures (the Lambda\n * timed out, the database connection dropped, etc.). v2 envelopes are\n * reserved for *application-level* failures the agent can reason about.\n *\n * ## Versioning and rollout\n *\n * The agent opts into v2 by sending the header\n * `X-Openmdm-Protocol: 2` on every request. When absent, the server\n * falls back to the legacy v1 behavior — bare JSON on success,\n * `HTTPException(401|404|…)` on failure — so a fleet still running\n * older APKs keeps working during rollout.\n *\n * After the fleet has been upgraded, v1 can be dropped in a future\n * major release by ignoring the header and always emitting v2.\n */\n\n/**\n * Instruction the server gives the agent on how to react to this\n * response. This is the entire client-side decision space.\n *\n * - `none`: happy path. The agent consumes `data` and continues.\n * - `retry`: transient problem. The agent re-tries later without\n * touching local state.\n * - `reauth`: the agent's access token is no longer valid. It should\n * call the refresh flow. It must NOT wipe enrollment state.\n * - `unenroll`: the server-side record for this device is gone or\n * blocked and the agent's credentials will never work again. The\n * agent should stop making requests and surface this to the user.\n * In Phase 2b this will be further softened: the agent will attempt\n * a hardware-identity-based rebind before treating this as terminal.\n */\nexport type AgentAction = 'none' | 'retry' | 'reauth' | 'unenroll';\n\n/**\n * Unified response envelope for every `/agent/*` endpoint under\n * protocol v2.\n *\n * Successful responses carry `data`; failure responses carry\n * `message`. The envelope never carries both the happy-path payload\n * and an error hint at the same time.\n */\nexport type AgentResponse<T = unknown> =\n | {\n ok: true;\n action: 'none';\n data: T;\n }\n | {\n ok: false;\n action: Exclude<AgentAction, 'none'>;\n message?: string;\n };\n\n/**\n * HTTP header an agent sends to opt into protocol v2. Case-insensitive\n * on the wire; use the constant to avoid typos.\n */\nexport const AGENT_PROTOCOL_HEADER = 'X-Openmdm-Protocol';\n\n/**\n * Current wire-protocol version. Agents that send\n * `X-Openmdm-Protocol: 2` get envelope responses. Absent or older\n * values are served with the legacy flat shape.\n */\nexport const AGENT_PROTOCOL_V2 = '2';\n\n/**\n * Helper: build a success envelope.\n */\nexport function agentOk<T>(data: T): AgentResponse<T> {\n return { ok: true, action: 'none', data };\n}\n\n/**\n * Helper: build a failure envelope.\n */\nexport function agentFail(\n action: Exclude<AgentAction, 'none'>,\n message?: string,\n): AgentResponse<never> {\n return { ok: false, action, message };\n}\n\n/**\n * Returns `true` iff the caller should be served protocol v2. The\n * input is the value of the {@link AGENT_PROTOCOL_HEADER} header,\n * which may be undefined.\n */\nexport function wantsAgentProtocolV2(headerValue: string | undefined | null): boolean {\n return headerValue === AGENT_PROTOCOL_V2;\n}\n","/**\n * OpenMDM Core\n *\n * A flexible, embeddable MDM (Mobile Device Management) SDK.\n * Inspired by better-auth's design philosophy.\n *\n * @example\n * ```typescript\n * import { createMDM } from '@openmdm/core';\n * import { drizzleAdapter } from '@openmdm/drizzle-adapter';\n *\n * const mdm = createMDM({\n * database: drizzleAdapter(db),\n * enrollment: {\n * deviceSecret: process.env.DEVICE_HMAC_SECRET!,\n * autoEnroll: true,\n * },\n * });\n *\n * // Use in your routes\n * const devices = await mdm.devices.list();\n * ```\n */\n\nimport { createHmac, timingSafeEqual, randomUUID } from 'crypto';\nimport type {\n MDMConfig,\n MDMInstance,\n Device,\n Policy,\n Application,\n Command,\n Group,\n Heartbeat,\n EnrollmentRequest,\n EnrollmentResponse,\n DeviceFilter,\n DeviceListResult,\n CreateDeviceInput,\n UpdateDeviceInput,\n CreatePolicyInput,\n UpdatePolicyInput,\n CreateApplicationInput,\n UpdateApplicationInput,\n SendCommandInput,\n CommandFilter,\n CreateGroupInput,\n UpdateGroupInput,\n DeployTarget,\n DeviceManager,\n PolicyManager,\n ApplicationManager,\n CommandManager,\n GroupManager,\n PushAdapter,\n PushResult,\n PushBatchResult,\n PushMessage,\n EventType,\n EventHandler,\n EventPayloadMap,\n MDMEvent,\n MDMPlugin,\n CommandResult,\n InstalledApp,\n WebhookManager,\n TenantManager,\n AuthorizationManager,\n AuditManager,\n ScheduleManager,\n MessageQueueManager,\n DashboardManager,\n PluginStorageAdapter,\n GroupTreeNode,\n GroupHierarchyStats,\n Logger,\n} from './types';\nimport {\n DeviceNotFoundError,\n ApplicationNotFoundError,\n CommandNotFoundError,\n EnrollmentError,\n} from './types';\nimport { createWebhookManager } from './webhooks';\nimport { createTenantManager } from './tenant';\nimport { createAuthorizationManager } from './authorization';\nimport { createAuditManager } from './audit';\nimport { createScheduleManager } from './schedule';\nimport { createMessageQueueManager } from './queue';\nimport { createDashboardManager } from './dashboard';\nimport { createPluginStorageAdapter, createMemoryPluginStorageAdapter } from './plugin-storage';\nimport { createConsoleLogger, createSilentLogger } from './logger';\n\n// Re-export all types\nexport * from './types';\nexport * from './schema';\nexport * from './agent-protocol';\nexport { createWebhookManager, verifyWebhookSignature } from './webhooks';\nexport type { WebhookPayload } from './webhooks';\nexport { createConsoleLogger, createSilentLogger } from './logger';\n\n// Re-export enterprise manager factories\nexport { createTenantManager } from './tenant';\nexport { createAuthorizationManager } from './authorization';\nexport { createAuditManager } from './audit';\nexport { createScheduleManager } from './schedule';\nexport { createMessageQueueManager } from './queue';\nexport { createDashboardManager } from './dashboard';\nexport { createPluginStorageAdapter, createMemoryPluginStorageAdapter, createPluginKey, parsePluginKey } from './plugin-storage';\n\n/**\n * Create an MDM instance with the given configuration.\n */\nexport function createMDM(config: MDMConfig): MDMInstance {\n const { database, push, enrollment, webhooks: webhooksConfig, plugins = [] } = config;\n\n // Structured logger. Falls back to the console-backed default if\n // the host doesn't pass one. Host code is expected to pass a real\n // pino/winston instance in production.\n const logger = config.logger ?? createConsoleLogger();\n\n // Extract a stable message from an unknown thrown value so it\n // survives JSON serialization into the log context. Error objects\n // stringify to `{}` otherwise, which is the #1 cause of \"we can't\n // tell why this failed\" in production logs.\n const errorMessage = (err: unknown): string => {\n if (err instanceof Error) return err.message;\n if (typeof err === 'string') return err;\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n };\n\n // Event handlers registry\n const eventHandlers = new Map<EventType, Set<EventHandler<EventType>>>();\n\n // Create push adapter\n const pushAdapter: PushAdapter = push\n ? createPushAdapter(push, database, logger)\n : createStubPushAdapter(logger);\n\n // Create webhook manager if configured\n const webhookManager: WebhookManager | undefined = webhooksConfig\n ? createWebhookManager(webhooksConfig, logger)\n : undefined;\n\n // ============================================\n // Enterprise Managers (optional)\n // ============================================\n\n // Create tenant manager if multi-tenancy is enabled\n const tenantManager: TenantManager | undefined = config.multiTenancy?.enabled\n ? createTenantManager(database)\n : undefined;\n\n // Create authorization manager if authorization is enabled\n const authorizationManager: AuthorizationManager | undefined = config.authorization?.enabled\n ? createAuthorizationManager(database)\n : undefined;\n\n // Create audit manager if audit logging is enabled\n const auditManager: AuditManager | undefined = config.audit?.enabled\n ? createAuditManager(database)\n : undefined;\n\n // Create schedule manager if scheduling is enabled\n const scheduleManager: ScheduleManager | undefined = config.scheduling?.enabled\n ? createScheduleManager(database)\n : undefined;\n\n // Create message queue manager if the database supports it\n const messageQueueManager: MessageQueueManager | undefined = database.enqueueMessage\n ? createMessageQueueManager(database)\n : undefined;\n\n // Create dashboard manager (always available, uses database fallbacks)\n const dashboardManager: DashboardManager = createDashboardManager(database);\n\n // Create plugin storage adapter\n const pluginStorageAdapter: PluginStorageAdapter | undefined =\n config.pluginStorage?.adapter === 'database'\n ? createPluginStorageAdapter(database)\n : config.pluginStorage?.adapter === 'memory'\n ? createMemoryPluginStorageAdapter()\n : undefined;\n\n // Event subscription\n const on = <T extends EventType>(\n event: T,\n handler: EventHandler<T>\n ): (() => void) => {\n if (!eventHandlers.has(event)) {\n eventHandlers.set(event, new Set());\n }\n const handlers = eventHandlers.get(event)!;\n handlers.add(handler as EventHandler<EventType>);\n\n // Return unsubscribe function\n return () => {\n handlers.delete(handler as EventHandler<EventType>);\n };\n };\n\n // Event emission\n const emit = async <T extends EventType>(\n event: T,\n data: EventPayloadMap[T]\n ): Promise<void> => {\n const handlers = eventHandlers.get(event);\n\n // Create event record\n const eventRecord: MDMEvent<EventPayloadMap[T]> = {\n id: randomUUID(),\n deviceId: (data as any).device?.id || (data as any).deviceId || '',\n type: event,\n payload: data,\n createdAt: new Date(),\n };\n\n // Persist event\n try {\n await database.createEvent({\n deviceId: eventRecord.deviceId,\n type: eventRecord.type,\n payload: eventRecord.payload as Record<string, unknown>,\n });\n } catch (error) {\n logger.error({ err: errorMessage(error), event }, 'Failed to persist event');\n }\n\n // Deliver webhooks (async, don't wait)\n if (webhookManager) {\n webhookManager.deliver(eventRecord).catch((error) => {\n logger.error(\n { err: errorMessage(error), event },\n 'Webhook delivery error',\n );\n });\n }\n\n // Call handlers\n if (handlers) {\n for (const handler of handlers) {\n try {\n await handler(eventRecord);\n } catch (error) {\n logger.error(\n { err: errorMessage(error), event },\n 'Event handler threw',\n );\n }\n }\n }\n\n // Call config hook if defined\n if (config.onEvent) {\n try {\n await config.onEvent(eventRecord);\n } catch (error) {\n logger.error({ err: errorMessage(error) }, 'onEvent hook threw');\n }\n }\n };\n\n // ============================================\n // Device Manager\n // ============================================\n\n const devices: DeviceManager = {\n async get(id: string): Promise<Device | null> {\n return database.findDevice(id);\n },\n\n async getByEnrollmentId(enrollmentId: string): Promise<Device | null> {\n return database.findDeviceByEnrollmentId(enrollmentId);\n },\n\n async list(filter?: DeviceFilter): Promise<DeviceListResult> {\n return database.listDevices(filter);\n },\n\n async create(data: CreateDeviceInput): Promise<Device> {\n const device = await database.createDevice(data);\n\n await emit('device.enrolled', { device });\n\n if (config.onDeviceEnrolled) {\n await config.onDeviceEnrolled(device);\n }\n\n return device;\n },\n\n async update(id: string, data: UpdateDeviceInput): Promise<Device> {\n const oldDevice = await database.findDevice(id);\n if (!oldDevice) {\n throw new DeviceNotFoundError(id);\n }\n\n const device = await database.updateDevice(id, data);\n\n // Emit status change event if status changed\n if (data.status && data.status !== oldDevice.status) {\n await emit('device.statusChanged', {\n device,\n oldStatus: oldDevice.status,\n newStatus: data.status,\n });\n }\n\n // Emit policy change event if policy changed\n if (data.policyId !== undefined && data.policyId !== oldDevice.policyId) {\n await emit('device.policyChanged', {\n device,\n oldPolicyId: oldDevice.policyId || undefined,\n newPolicyId: data.policyId || undefined,\n });\n }\n\n return device;\n },\n\n async delete(id: string): Promise<void> {\n const device = await database.findDevice(id);\n if (device) {\n await database.deleteDevice(id);\n await emit('device.unenrolled', { device });\n\n if (config.onDeviceUnenrolled) {\n await config.onDeviceUnenrolled(device);\n }\n }\n },\n\n async assignPolicy(\n deviceId: string,\n policyId: string | null\n ): Promise<Device> {\n const device = await this.update(deviceId, { policyId });\n\n // Notify device of policy change\n await pushAdapter.send(deviceId, {\n type: 'policy.updated',\n payload: { policyId },\n priority: 'high',\n });\n\n return device;\n },\n\n async addToGroup(deviceId: string, groupId: string): Promise<void> {\n await database.addDeviceToGroup(deviceId, groupId);\n },\n\n async removeFromGroup(deviceId: string, groupId: string): Promise<void> {\n await database.removeDeviceFromGroup(deviceId, groupId);\n },\n\n async getGroups(deviceId: string): Promise<Group[]> {\n return database.getDeviceGroups(deviceId);\n },\n\n async sendCommand(\n deviceId: string,\n input: Omit<SendCommandInput, 'deviceId'>\n ): Promise<Command> {\n const command = await database.createCommand({\n ...input,\n deviceId,\n });\n\n // Send via push\n const pushResult = await pushAdapter.send(deviceId, {\n type: `command.${input.type}`,\n payload: {\n commandId: command.id,\n type: input.type,\n ...input.payload,\n },\n priority: 'high',\n });\n\n // Update command status\n if (pushResult.success) {\n await database.updateCommand(command.id, {\n status: 'sent',\n sentAt: new Date(),\n });\n }\n\n if (config.onCommand) {\n await config.onCommand(command);\n }\n\n return database.findCommand(command.id) as Promise<Command>;\n },\n\n async sync(deviceId: string): Promise<Command> {\n return this.sendCommand(deviceId, { type: 'sync' });\n },\n\n async reboot(deviceId: string): Promise<Command> {\n return this.sendCommand(deviceId, { type: 'reboot' });\n },\n\n async lock(deviceId: string, message?: string): Promise<Command> {\n return this.sendCommand(deviceId, {\n type: 'lock',\n payload: message ? { message } : undefined,\n });\n },\n\n async wipe(deviceId: string, preserveData?: boolean): Promise<Command> {\n return this.sendCommand(deviceId, {\n type: preserveData ? 'wipe' : 'factoryReset',\n payload: { preserveData },\n });\n },\n };\n\n // ============================================\n // Policy Manager\n // ============================================\n\n const policies: PolicyManager = {\n async get(id: string): Promise<Policy | null> {\n return database.findPolicy(id);\n },\n\n async getDefault(): Promise<Policy | null> {\n return database.findDefaultPolicy();\n },\n\n async list(): Promise<Policy[]> {\n return database.listPolicies();\n },\n\n async create(data: CreatePolicyInput): Promise<Policy> {\n // If this is being set as default, clear other defaults first\n if (data.isDefault) {\n const existingPolicies = await database.listPolicies();\n for (const policy of existingPolicies) {\n if (policy.isDefault) {\n await database.updatePolicy(policy.id, { isDefault: false });\n }\n }\n }\n\n return database.createPolicy(data);\n },\n\n async update(id: string, data: UpdatePolicyInput): Promise<Policy> {\n // If setting as default, clear other defaults first\n if (data.isDefault) {\n const existingPolicies = await database.listPolicies();\n for (const policy of existingPolicies) {\n if (policy.isDefault && policy.id !== id) {\n await database.updatePolicy(policy.id, { isDefault: false });\n }\n }\n }\n\n const policy = await database.updatePolicy(id, data);\n\n // Notify all devices with this policy\n const devicesResult = await database.listDevices({ policyId: id });\n if (devicesResult.devices.length > 0) {\n const deviceIds = devicesResult.devices.map((d) => d.id);\n await pushAdapter.sendBatch(deviceIds, {\n type: 'policy.updated',\n payload: { policyId: id },\n priority: 'high',\n });\n }\n\n return policy;\n },\n\n async delete(id: string): Promise<void> {\n // Check if any devices use this policy\n const devicesResult = await database.listDevices({ policyId: id });\n if (devicesResult.devices.length > 0) {\n // Remove policy from devices first\n for (const device of devicesResult.devices) {\n await database.updateDevice(device.id, { policyId: null });\n }\n }\n\n await database.deletePolicy(id);\n },\n\n async setDefault(id: string): Promise<Policy> {\n return this.update(id, { isDefault: true });\n },\n\n async getDevices(policyId: string): Promise<Device[]> {\n const result = await database.listDevices({ policyId });\n return result.devices;\n },\n\n async applyToDevice(policyId: string, deviceId: string): Promise<void> {\n await devices.assignPolicy(deviceId, policyId);\n },\n };\n\n // ============================================\n // Application Manager\n // ============================================\n\n const apps: ApplicationManager = {\n async get(id: string): Promise<Application | null> {\n return database.findApplication(id);\n },\n\n async getByPackage(\n packageName: string,\n version?: string\n ): Promise<Application | null> {\n return database.findApplicationByPackage(packageName, version);\n },\n\n async list(activeOnly?: boolean): Promise<Application[]> {\n return database.listApplications(activeOnly);\n },\n\n async register(data: CreateApplicationInput): Promise<Application> {\n return database.createApplication(data);\n },\n\n async update(id: string, data: UpdateApplicationInput): Promise<Application> {\n return database.updateApplication(id, data);\n },\n\n async delete(id: string): Promise<void> {\n await database.deleteApplication(id);\n },\n\n async activate(id: string): Promise<Application> {\n return database.updateApplication(id, { isActive: true });\n },\n\n async deactivate(id: string): Promise<Application> {\n return database.updateApplication(id, { isActive: false });\n },\n\n async deploy(packageName: string, target: DeployTarget): Promise<void> {\n const app = await database.findApplicationByPackage(packageName);\n if (!app) {\n throw new ApplicationNotFoundError(packageName);\n }\n\n const deviceIds: string[] = [];\n\n // Collect target devices\n if (target.devices) {\n deviceIds.push(...target.devices);\n }\n\n if (target.groups) {\n for (const groupId of target.groups) {\n const groupDevices = await database.listDevicesInGroup(groupId);\n deviceIds.push(...groupDevices.map((d) => d.id));\n }\n }\n\n if (target.policies) {\n for (const policyId of target.policies) {\n const result = await database.listDevices({ policyId });\n deviceIds.push(...result.devices.map((d) => d.id));\n }\n }\n\n // Deduplicate\n const uniqueDeviceIds = [...new Set(deviceIds)];\n\n // Send install command to all devices\n if (uniqueDeviceIds.length > 0) {\n await pushAdapter.sendBatch(uniqueDeviceIds, {\n type: 'command.installApp',\n payload: {\n packageName: app.packageName,\n version: app.version,\n versionCode: app.versionCode,\n url: app.url,\n hash: app.hash,\n },\n priority: 'high',\n });\n\n // Create command records for each device\n for (const deviceId of uniqueDeviceIds) {\n await database.createCommand({\n deviceId,\n type: 'installApp',\n payload: {\n packageName: app.packageName,\n version: app.version,\n url: app.url,\n },\n });\n }\n }\n },\n\n async installOnDevice(\n packageName: string,\n deviceId: string,\n version?: string\n ): Promise<Command> {\n const app = await database.findApplicationByPackage(packageName, version);\n if (!app) {\n throw new ApplicationNotFoundError(packageName);\n }\n\n return devices.sendCommand(deviceId, {\n type: 'installApp',\n payload: {\n packageName: app.packageName,\n version: app.version,\n versionCode: app.versionCode,\n url: app.url,\n hash: app.hash,\n },\n });\n },\n\n async uninstallFromDevice(\n packageName: string,\n deviceId: string\n ): Promise<Command> {\n return devices.sendCommand(deviceId, {\n type: 'uninstallApp',\n payload: { packageName },\n });\n },\n };\n\n // ============================================\n // Command Manager\n // ============================================\n\n const commands: CommandManager = {\n async get(id: string): Promise<Command | null> {\n return database.findCommand(id);\n },\n\n async list(filter?: CommandFilter): Promise<Command[]> {\n return database.listCommands(filter);\n },\n\n async send(input: SendCommandInput): Promise<Command> {\n return devices.sendCommand(input.deviceId, {\n type: input.type,\n payload: input.payload,\n });\n },\n\n async cancel(id: string): Promise<Command> {\n const command = await database.updateCommand(id, { status: 'cancelled' });\n if (!command) {\n throw new CommandNotFoundError(id);\n }\n return command;\n },\n\n async acknowledge(id: string): Promise<Command> {\n const command = await database.updateCommand(id, {\n status: 'acknowledged',\n acknowledgedAt: new Date(),\n });\n\n if (!command) {\n throw new CommandNotFoundError(id);\n }\n\n const device = await database.findDevice(command.deviceId);\n if (device) {\n await emit('command.acknowledged', { device, command });\n }\n\n return command;\n },\n\n async complete(id: string, result: CommandResult): Promise<Command> {\n const command = await database.updateCommand(id, {\n status: 'completed',\n result,\n completedAt: new Date(),\n });\n\n if (!command) {\n throw new CommandNotFoundError(id);\n }\n\n const device = await database.findDevice(command.deviceId);\n if (device) {\n await emit('command.completed', { device, command, result });\n }\n\n return command;\n },\n\n async fail(id: string, error: string): Promise<Command> {\n const command = await database.updateCommand(id, {\n status: 'failed',\n error,\n completedAt: new Date(),\n });\n\n if (!command) {\n throw new CommandNotFoundError(id);\n }\n\n const device = await database.findDevice(command.deviceId);\n if (device) {\n await emit('command.failed', { device, command, error });\n }\n\n return command;\n },\n\n async getPending(deviceId: string): Promise<Command[]> {\n return database.getPendingCommands(deviceId);\n },\n };\n\n // ============================================\n // Group Manager\n // ============================================\n\n const groups: GroupManager = {\n async get(id: string): Promise<Group | null> {\n return database.findGroup(id);\n },\n\n async list(): Promise<Group[]> {\n return database.listGroups();\n },\n\n async create(data: CreateGroupInput): Promise<Group> {\n return database.createGroup(data);\n },\n\n async update(id: string, data: UpdateGroupInput): Promise<Group> {\n return database.updateGroup(id, data);\n },\n\n async delete(id: string): Promise<void> {\n await database.deleteGroup(id);\n },\n\n async getDevices(groupId: string): Promise<Device[]> {\n return database.listDevicesInGroup(groupId);\n },\n\n async addDevice(groupId: string, deviceId: string): Promise<void> {\n await database.addDeviceToGroup(deviceId, groupId);\n },\n\n async removeDevice(groupId: string, deviceId: string): Promise<void> {\n await database.removeDeviceFromGroup(deviceId, groupId);\n },\n\n async getChildren(groupId: string): Promise<Group[]> {\n const allGroups = await database.listGroups();\n return allGroups.filter((g) => g.parentId === groupId);\n },\n\n async getTree(rootId?: string): Promise<GroupTreeNode[]> {\n // Use database implementation if available\n if (database.getGroupTree) {\n return database.getGroupTree(rootId);\n }\n\n // Fallback: Build tree from flat list\n const allGroups = await database.listGroups();\n const groupMap = new Map(allGroups.map((g) => [g.id, g]));\n\n const buildNode = (group: Group, depth: number, path: string[]): GroupTreeNode => {\n const children = allGroups\n .filter((g) => g.parentId === group.id)\n .map((child) => buildNode(child, depth + 1, [...path, group.id]));\n\n return {\n ...group,\n children,\n depth,\n path,\n effectivePolicyId: group.policyId,\n };\n };\n\n // Find root groups (those with no parent or matching rootId)\n const roots = allGroups.filter((g) =>\n rootId ? g.id === rootId : !g.parentId\n );\n\n return roots.map((root) => buildNode(root, 0, []));\n },\n\n async getAncestors(groupId: string): Promise<Group[]> {\n // Use database implementation if available\n if (database.getGroupAncestors) {\n return database.getGroupAncestors(groupId);\n }\n\n // Fallback: Traverse up the tree\n const ancestors: Group[] = [];\n const allGroups = await database.listGroups();\n const groupMap = new Map(allGroups.map((g) => [g.id, g]));\n\n let current = groupMap.get(groupId);\n while (current?.parentId) {\n const parent = groupMap.get(current.parentId);\n if (parent) {\n ancestors.push(parent);\n current = parent;\n } else {\n break;\n }\n }\n\n return ancestors;\n },\n\n async getDescendants(groupId: string): Promise<Group[]> {\n // Use database implementation if available\n if (database.getGroupDescendants) {\n return database.getGroupDescendants(groupId);\n }\n\n // Fallback: Find all descendants recursively\n const allGroups = await database.listGroups();\n const descendants: Group[] = [];\n\n const findDescendants = (parentId: string) => {\n const children = allGroups.filter((g) => g.parentId === parentId);\n for (const child of children) {\n descendants.push(child);\n findDescendants(child.id);\n }\n };\n\n findDescendants(groupId);\n return descendants;\n },\n\n async move(groupId: string, newParentId: string | null): Promise<Group> {\n // Validate that we're not creating a cycle\n if (newParentId) {\n const ancestors = await this.getAncestors(newParentId);\n if (ancestors.some((a) => a.id === groupId)) {\n throw new Error('Cannot move group: would create circular reference');\n }\n }\n\n return database.updateGroup(groupId, { parentId: newParentId });\n },\n\n async getEffectivePolicy(groupId: string): Promise<Policy | null> {\n // Use database implementation if available\n if (database.getGroupEffectivePolicy) {\n return database.getGroupEffectivePolicy(groupId);\n }\n\n // Fallback: Walk up the tree to find first policy\n const group = await database.findGroup(groupId);\n if (!group) return null;\n\n if (group.policyId) {\n return database.findPolicy(group.policyId);\n }\n\n // Check ancestors\n const ancestors = await this.getAncestors(groupId);\n for (const ancestor of ancestors) {\n if (ancestor.policyId) {\n return database.findPolicy(ancestor.policyId);\n }\n }\n\n return null;\n },\n\n async getHierarchyStats(): Promise<GroupHierarchyStats> {\n // Use database implementation if available\n if (database.getGroupHierarchyStats) {\n return database.getGroupHierarchyStats();\n }\n\n // Fallback: Compute from flat list\n const allGroups = await database.listGroups();\n let maxDepth = 0;\n let groupsWithDevices = 0;\n let groupsWithPolicies = 0;\n\n for (const group of allGroups) {\n // Calculate depth\n const ancestors = await this.getAncestors(group.id);\n maxDepth = Math.max(maxDepth, ancestors.length);\n\n // Check for devices\n const devices = await database.listDevicesInGroup(group.id);\n if (devices.length > 0) groupsWithDevices++;\n\n // Check for policies\n if (group.policyId) groupsWithPolicies++;\n }\n\n return {\n totalGroups: allGroups.length,\n maxDepth,\n groupsWithDevices,\n groupsWithPolicies,\n };\n },\n };\n\n // ============================================\n // Enrollment\n // ============================================\n\n const enroll = async (\n request: EnrollmentRequest\n ): Promise<EnrollmentResponse> => {\n // Validate method if restricted\n if (\n enrollment?.allowedMethods &&\n !enrollment.allowedMethods.includes(request.method)\n ) {\n throw new EnrollmentError(\n `Enrollment method '${request.method}' is not allowed`\n );\n }\n\n // Verify signature if secret is configured\n if (enrollment?.deviceSecret) {\n const isValid = verifyEnrollmentSignature(\n request,\n enrollment.deviceSecret\n );\n if (!isValid) {\n throw new EnrollmentError('Invalid enrollment signature');\n }\n }\n\n // Custom validation\n if (enrollment?.validate) {\n const isValid = await enrollment.validate(request);\n if (!isValid) {\n throw new EnrollmentError('Enrollment validation failed');\n }\n }\n\n // Determine enrollment ID\n const enrollmentId =\n request.macAddress ||\n request.serialNumber ||\n request.imei ||\n request.androidId;\n\n if (!enrollmentId) {\n throw new EnrollmentError(\n 'Device must provide at least one identifier (macAddress, serialNumber, imei, or androidId)'\n );\n }\n\n // Check if device already exists\n let device = await database.findDeviceByEnrollmentId(enrollmentId);\n\n if (device) {\n // Device re-enrolling\n device = await database.updateDevice(device.id, {\n status: 'enrolled',\n model: request.model,\n manufacturer: request.manufacturer,\n osVersion: request.osVersion,\n lastSync: new Date(),\n });\n } else if (enrollment?.autoEnroll) {\n // Auto-create device\n device = await database.createDevice({\n enrollmentId,\n model: request.model,\n manufacturer: request.manufacturer,\n osVersion: request.osVersion,\n serialNumber: request.serialNumber,\n imei: request.imei,\n macAddress: request.macAddress,\n androidId: request.androidId,\n policyId: request.policyId || enrollment.defaultPolicyId,\n });\n\n // Add to default group if configured\n if (enrollment.defaultGroupId) {\n await database.addDeviceToGroup(device.id, enrollment.defaultGroupId);\n }\n } else if (enrollment?.requireApproval) {\n // Create pending device\n device = await database.createDevice({\n enrollmentId,\n model: request.model,\n manufacturer: request.manufacturer,\n osVersion: request.osVersion,\n serialNumber: request.serialNumber,\n imei: request.imei,\n macAddress: request.macAddress,\n androidId: request.androidId,\n });\n // Status remains 'pending'\n } else {\n throw new EnrollmentError(\n 'Device not registered and auto-enroll is disabled'\n );\n }\n\n // Get policy\n let policy: Policy | null = null;\n if (device.policyId) {\n policy = await database.findPolicy(device.policyId);\n }\n if (!policy) {\n policy = await database.findDefaultPolicy();\n }\n\n // Generate JWT token for device auth\n const tokenSecret =\n config.auth?.deviceTokenSecret || enrollment?.deviceSecret || '';\n const tokenExpiration = config.auth?.deviceTokenExpiration || 365 * 24 * 60 * 60;\n const token = generateDeviceToken(device.id, tokenSecret, tokenExpiration);\n\n // Emit enrollment event\n await emit('device.enrolled', { device });\n\n // Call config hook if defined\n if (config.onDeviceEnrolled) {\n await config.onDeviceEnrolled(device);\n }\n\n // Call plugin hooks\n for (const plugin of plugins) {\n if (plugin.onEnroll) {\n await plugin.onEnroll(device, request);\n }\n if (plugin.onDeviceEnrolled) {\n await plugin.onDeviceEnrolled(device);\n }\n }\n\n return {\n deviceId: device.id,\n enrollmentId: device.enrollmentId,\n policyId: policy?.id,\n policy: policy || undefined,\n serverUrl: config.serverUrl || '',\n pushConfig: {\n provider: push?.provider || 'polling',\n fcmSenderId: (push?.fcmCredentials as any)?.project_id,\n mqttUrl: push?.mqttUrl,\n mqttTopic: push?.mqttTopicPrefix\n ? `${push.mqttTopicPrefix}/${device.id}`\n : `openmdm/devices/${device.id}`,\n pollingInterval: push?.pollingInterval || 60,\n },\n token,\n tokenExpiresAt: new Date(Date.now() + tokenExpiration * 1000),\n };\n };\n\n // ============================================\n // Heartbeat Processing\n // ============================================\n\n const processHeartbeat = async (\n deviceId: string,\n heartbeat: Heartbeat\n ): Promise<void> => {\n const device = await database.findDevice(deviceId);\n if (!device) {\n throw new DeviceNotFoundError(deviceId);\n }\n\n // Update device with heartbeat data\n const updateData: UpdateDeviceInput = {\n lastHeartbeat: heartbeat.timestamp,\n batteryLevel: heartbeat.batteryLevel,\n storageUsed: heartbeat.storageUsed,\n storageTotal: heartbeat.storageTotal,\n installedApps: heartbeat.installedApps,\n };\n\n if (heartbeat.location) {\n updateData.location = heartbeat.location;\n }\n\n const updatedDevice = await database.updateDevice(deviceId, updateData);\n\n // Emit heartbeat event\n await emit('device.heartbeat', { device: updatedDevice, heartbeat });\n\n // Emit location event if location changed\n if (heartbeat.location) {\n await emit('device.locationUpdated', {\n device: updatedDevice,\n location: heartbeat.location,\n });\n }\n\n // Check for app changes\n if (device.installedApps && heartbeat.installedApps) {\n const oldApps = new Map(\n device.installedApps.map((a) => [a.packageName, a])\n );\n const newApps = new Map(\n heartbeat.installedApps.map((a) => [a.packageName, a])\n );\n\n // Check for new installs\n for (const [pkg, app] of newApps) {\n const oldApp = oldApps.get(pkg);\n if (!oldApp) {\n await emit('app.installed', { device: updatedDevice, app });\n } else if (oldApp.version !== app.version) {\n await emit('app.updated', {\n device: updatedDevice,\n app,\n oldVersion: oldApp.version,\n });\n }\n }\n\n // Check for uninstalls\n for (const [pkg] of oldApps) {\n if (!newApps.has(pkg)) {\n await emit('app.uninstalled', {\n device: updatedDevice,\n packageName: pkg,\n });\n }\n }\n }\n\n // Call config hook if defined\n if (config.onHeartbeat) {\n await config.onHeartbeat(updatedDevice, heartbeat);\n }\n\n // Call plugin hooks\n for (const plugin of plugins) {\n if (plugin.onHeartbeat) {\n await plugin.onHeartbeat(updatedDevice, heartbeat);\n }\n }\n };\n\n // ============================================\n // Token Verification\n // ============================================\n\n const verifyDeviceToken = async (\n token: string\n ): Promise<{ deviceId: string } | null> => {\n try {\n const tokenSecret =\n config.auth?.deviceTokenSecret || enrollment?.deviceSecret || '';\n\n const parts = token.split('.');\n if (parts.length !== 3) {\n return null;\n }\n\n const [header, payload, signature] = parts;\n\n // Verify signature\n const expectedSignature = createHmac('sha256', tokenSecret)\n .update(`${header}.${payload}`)\n .digest('base64url');\n\n if (signature !== expectedSignature) {\n return null;\n }\n\n // Decode payload\n const decoded = JSON.parse(\n Buffer.from(payload, 'base64url').toString('utf-8')\n );\n\n // Check expiration\n if (decoded.exp && decoded.exp < Math.floor(Date.now() / 1000)) {\n return null;\n }\n\n return { deviceId: decoded.sub };\n } catch {\n return null;\n }\n };\n\n // ============================================\n // Plugin Management\n // ============================================\n\n const getPlugins = (): MDMPlugin[] => plugins;\n\n const getPlugin = (name: string): MDMPlugin | undefined => {\n return plugins.find((p) => p.name === name);\n };\n\n // ============================================\n // Create Instance\n // ============================================\n\n const instance: MDMInstance = {\n devices,\n policies,\n apps,\n commands,\n groups,\n push: pushAdapter,\n webhooks: webhookManager,\n db: database,\n logger,\n config,\n on,\n emit,\n enroll,\n processHeartbeat,\n verifyDeviceToken,\n getPlugins,\n getPlugin,\n // Enterprise managers (optional)\n tenants: tenantManager,\n authorization: authorizationManager,\n audit: auditManager,\n schedules: scheduleManager,\n messageQueue: messageQueueManager,\n dashboard: dashboardManager,\n pluginStorage: pluginStorageAdapter,\n };\n\n // Initialize plugins\n (async () => {\n for (const plugin of plugins) {\n if (plugin.onInit) {\n try {\n await plugin.onInit(instance);\n logger.info({ plugin: plugin.name }, 'Plugin initialized');\n } catch (error) {\n logger.error(\n { plugin: plugin.name, err: errorMessage(error) },\n 'Failed to initialize plugin',\n );\n }\n }\n }\n })();\n\n return instance;\n}\n\n// ============================================\n// Push Adapter Factory\n// ============================================\n\nfunction createPushAdapter(\n config: MDMConfig['push'],\n database: MDMConfig['database'],\n logger: Logger,\n): PushAdapter {\n if (!config) {\n return createStubPushAdapter(logger);\n }\n\n const pushLogger = logger.child({ component: 'push' });\n\n // The actual implementations will be provided by separate packages\n // This is a base implementation that logs and stores tokens\n return {\n async send(deviceId: string, message: PushMessage): Promise<PushResult> {\n pushLogger.debug(\n { deviceId, type: message.type, payload: message.payload },\n 'send',\n );\n\n // In production, this would be replaced by FCM/MQTT adapter\n return { success: true, messageId: randomUUID() };\n },\n\n async sendBatch(\n deviceIds: string[],\n message: PushMessage\n ): Promise<PushBatchResult> {\n pushLogger.debug(\n { count: deviceIds.length, type: message.type },\n 'sendBatch',\n );\n\n const results = deviceIds.map((deviceId) => ({\n deviceId,\n result: { success: true, messageId: randomUUID() },\n }));\n\n return {\n successCount: deviceIds.length,\n failureCount: 0,\n results,\n };\n },\n\n async registerToken(deviceId: string, token: string): Promise<void> {\n // Polling doesn't use push tokens\n if (config.provider === 'polling') {\n return;\n }\n await database.upsertPushToken({\n deviceId,\n provider: config.provider,\n token,\n });\n },\n\n async unregisterToken(deviceId: string): Promise<void> {\n // Polling doesn't use push tokens\n if (config.provider === 'polling') {\n return;\n }\n await database.deletePushToken(deviceId, config.provider);\n },\n };\n}\n\nfunction createStubPushAdapter(logger: Logger): PushAdapter {\n const stubLogger = logger.child({ component: 'push-stub' });\n return {\n async send(deviceId: string, message: PushMessage): Promise<PushResult> {\n stubLogger.debug({ deviceId, type: message.type }, 'send (stub)');\n return { success: true, messageId: 'stub' };\n },\n\n async sendBatch(\n deviceIds: string[],\n message: PushMessage\n ): Promise<PushBatchResult> {\n stubLogger.debug(\n { count: deviceIds.length, type: message.type },\n 'sendBatch (stub)',\n );\n return {\n successCount: deviceIds.length,\n failureCount: 0,\n results: deviceIds.map((deviceId) => ({\n deviceId,\n result: { success: true, messageId: 'stub' },\n })),\n };\n },\n };\n}\n\n// ============================================\n// Utility Functions\n// ============================================\n\nexport function verifyEnrollmentSignature(\n request: EnrollmentRequest,\n secret: string\n): boolean {\n const { signature, ...data } = request;\n\n if (!signature) {\n return false;\n }\n\n // Reconstruct the message that was signed. This must stay in lockstep with\n // @openmdm/client's generateEnrollmentSignature — any change here is a wire\n // break and must land in both places. A contract test in core/tests guards\n // the format and will fail on divergence.\n const message = [\n data.model,\n data.manufacturer,\n data.osVersion,\n data.serialNumber || '',\n data.imei || '',\n data.macAddress || '',\n data.androidId || '',\n data.method,\n data.timestamp,\n ].join('|');\n\n const expectedSignature = createHmac('sha256', secret)\n .update(message)\n .digest('hex');\n\n try {\n return timingSafeEqual(\n Buffer.from(signature, 'hex'),\n Buffer.from(expectedSignature, 'hex')\n );\n } catch {\n return false;\n }\n}\n\nfunction generateDeviceToken(\n deviceId: string,\n secret: string,\n expirationSeconds: number\n): string {\n const header = Buffer.from(\n JSON.stringify({ alg: 'HS256', typ: 'JWT' })\n ).toString('base64url');\n\n const now = Math.floor(Date.now() / 1000);\n const payload = Buffer.from(\n JSON.stringify({\n sub: deviceId,\n iat: now,\n exp: now + expirationSeconds,\n iss: 'openmdm',\n })\n ).toString('base64url');\n\n const signature = createHmac('sha256', secret)\n .update(`${header}.${payload}`)\n .digest('base64url');\n\n return `${header}.${payload}.${signature}`;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/logger.ts","../src/webhooks.ts","../src/tenant.ts","../src/authorization.ts","../src/audit.ts","../src/schedule.ts","../src/queue.ts","../src/dashboard.ts","../src/plugin-storage.ts","../src/device-identity.ts","../src/schema.ts","../src/agent-protocol.ts","../src/index.ts"],"names":["cryptoVerify","randomUUID","policy","devices","createHmac"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * OpenMDM Core Types\n *\n * These types define the core data structures for the MDM system.\n * Designed to be database-agnostic and framework-agnostic.\n */\n\n// ============================================\n// Device Types\n// ============================================\n\nexport type DeviceStatus = 'pending' | 'enrolled' | 'unenrolled' | 'blocked';\n\nexport interface Device {\n id: string;\n externalId?: string | null;\n enrollmentId: string;\n status: DeviceStatus;\n\n // Device Info\n model?: string | null;\n manufacturer?: string | null;\n osVersion?: string | null;\n serialNumber?: string | null;\n imei?: string | null;\n macAddress?: string | null;\n androidId?: string | null;\n\n // MDM State\n policyId?: string | null;\n agentVersion?: string | null; // MDM agent version installed on device\n lastHeartbeat?: Date | null;\n lastSync?: Date | null;\n\n // Device identity (Phase 2b — device-pinned ECDSA P-256 key)\n /**\n * Base64-encoded SPKI public key the device registered on first\n * enrollment. Requests from this device can be verified against\n * this key via `verifyDeviceRequest` / `verifyEcdsaSignature` from\n * `@openmdm/core`. `null` on devices that enrolled via the legacy\n * HMAC path and have never been migrated.\n */\n publicKey?: string | null;\n /**\n * How the device originally enrolled. `'hmac'` for the legacy\n * shared-secret path; `'pinned-key'` for the device-pinned ECDSA\n * path. `null` on pre-Phase-2b device rows that predate the\n * column (treated as `'hmac'`).\n */\n enrollmentMethod?: 'hmac' | 'pinned-key' | null;\n\n // Telemetry\n batteryLevel?: number | null;\n storageUsed?: number | null;\n storageTotal?: number | null;\n location?: DeviceLocation | null;\n installedApps?: InstalledApp[] | null;\n\n // Metadata\n tags?: Record<string, string> | null;\n metadata?: Record<string, unknown> | null;\n\n // Timestamps\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface DeviceLocation {\n latitude: number;\n longitude: number;\n accuracy?: number;\n timestamp: Date;\n}\n\nexport interface InstalledApp {\n packageName: string;\n version: string;\n versionCode?: number;\n installedAt?: Date;\n}\n\nexport interface CreateDeviceInput {\n enrollmentId: string;\n externalId?: string;\n model?: string;\n manufacturer?: string;\n osVersion?: string;\n serialNumber?: string;\n imei?: string;\n macAddress?: string;\n androidId?: string;\n policyId?: string;\n tags?: Record<string, string>;\n metadata?: Record<string, unknown>;\n}\n\nexport interface UpdateDeviceInput {\n externalId?: string | null;\n status?: DeviceStatus;\n policyId?: string | null;\n agentVersion?: string | null;\n model?: string;\n manufacturer?: string;\n osVersion?: string;\n batteryLevel?: number | null;\n storageUsed?: number | null;\n storageTotal?: number | null;\n lastHeartbeat?: Date;\n lastSync?: Date;\n installedApps?: InstalledApp[];\n location?: DeviceLocation;\n tags?: Record<string, string>;\n metadata?: Record<string, unknown>;\n /** Phase 2b — pin a new public key on first enroll. */\n publicKey?: string | null;\n /** Phase 2b — record which auth path the device enrolled via. */\n enrollmentMethod?: 'hmac' | 'pinned-key' | null;\n}\n\nexport interface DeviceFilter {\n status?: DeviceStatus | DeviceStatus[];\n policyId?: string;\n groupId?: string;\n search?: string;\n tags?: Record<string, string>;\n limit?: number;\n offset?: number;\n}\n\nexport interface DeviceListResult {\n devices: Device[];\n total: number;\n limit: number;\n offset: number;\n}\n\n// ============================================\n// Policy Types\n// ============================================\n\nexport interface Policy {\n id: string;\n name: string;\n description?: string | null;\n isDefault: boolean;\n settings: PolicySettings;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface PolicySettings {\n // Kiosk Mode\n kioskMode?: boolean;\n mainApp?: string;\n allowedApps?: string[];\n kioskExitPassword?: string;\n\n // Lock Features\n lockStatusBar?: boolean;\n lockNavigationBar?: boolean;\n lockSettings?: boolean;\n lockPowerButton?: boolean;\n blockInstall?: boolean;\n blockUninstall?: boolean;\n\n // Hardware Controls\n bluetooth?: HardwareControl;\n wifi?: HardwareControl;\n gps?: HardwareControl;\n mobileData?: HardwareControl;\n camera?: HardwareControl;\n microphone?: HardwareControl;\n usb?: HardwareControl;\n nfc?: HardwareControl;\n\n // Update Settings\n systemUpdatePolicy?: SystemUpdatePolicy;\n updateWindow?: TimeWindow;\n\n // Security\n passwordPolicy?: PasswordPolicy;\n encryptionRequired?: boolean;\n factoryResetProtection?: boolean;\n safeBootDisabled?: boolean;\n\n // Telemetry\n heartbeatInterval?: number;\n locationReportInterval?: number;\n locationEnabled?: boolean;\n\n // Network\n wifiConfigs?: WifiConfig[];\n vpnConfig?: VpnConfig;\n\n // Applications\n applications?: PolicyApplication[];\n\n // Custom settings (for plugins)\n custom?: Record<string, unknown>;\n}\n\nexport type HardwareControl = 'on' | 'off' | 'user';\nexport type SystemUpdatePolicy = 'auto' | 'windowed' | 'postpone' | 'manual';\n\nexport interface TimeWindow {\n start: string; // \"HH:MM\"\n end: string; // \"HH:MM\"\n}\n\nexport interface PasswordPolicy {\n required: boolean;\n minLength?: number;\n complexity?: 'none' | 'numeric' | 'alphanumeric' | 'complex';\n maxFailedAttempts?: number;\n expirationDays?: number;\n historyLength?: number;\n}\n\nexport interface WifiConfig {\n ssid: string;\n securityType: 'none' | 'wep' | 'wpa' | 'wpa2' | 'wpa3';\n password?: string;\n hidden?: boolean;\n autoConnect?: boolean;\n}\n\nexport interface VpnConfig {\n type: 'pptp' | 'l2tp' | 'ipsec' | 'openvpn' | 'wireguard';\n server: string;\n username?: string;\n password?: string;\n certificate?: string;\n config?: Record<string, unknown>;\n}\n\nexport interface PolicyApplication {\n packageName: string;\n action: 'install' | 'update' | 'uninstall';\n version?: string;\n required?: boolean;\n autoUpdate?: boolean;\n}\n\nexport interface CreatePolicyInput {\n name: string;\n description?: string;\n isDefault?: boolean;\n settings: PolicySettings;\n}\n\nexport interface UpdatePolicyInput {\n name?: string;\n description?: string | null;\n isDefault?: boolean;\n settings?: PolicySettings;\n}\n\n// ============================================\n// Application Types\n// ============================================\n\nexport interface Application {\n id: string;\n name: string;\n packageName: string;\n version: string;\n versionCode: number;\n url: string;\n hash?: string | null;\n size?: number | null;\n minSdkVersion?: number | null;\n\n // Deployment settings\n showIcon: boolean;\n runAfterInstall: boolean;\n runAtBoot: boolean;\n isSystem: boolean;\n\n // State\n isActive: boolean;\n\n // Metadata\n metadata?: Record<string, unknown> | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface CreateApplicationInput {\n name: string;\n packageName: string;\n version: string;\n versionCode: number;\n url: string;\n hash?: string;\n size?: number;\n minSdkVersion?: number;\n showIcon?: boolean;\n runAfterInstall?: boolean;\n runAtBoot?: boolean;\n isSystem?: boolean;\n metadata?: Record<string, unknown>;\n}\n\nexport interface UpdateApplicationInput {\n name?: string;\n version?: string;\n versionCode?: number;\n url?: string;\n hash?: string | null;\n size?: number | null;\n minSdkVersion?: number | null;\n showIcon?: boolean;\n runAfterInstall?: boolean;\n runAtBoot?: boolean;\n isActive?: boolean;\n metadata?: Record<string, unknown> | null;\n}\n\nexport interface DeployTarget {\n devices?: string[];\n policies?: string[];\n groups?: string[];\n}\n\n// ============================================\n// App Version & Rollback Types\n// ============================================\n\nexport interface AppVersion {\n id: string;\n applicationId: string;\n packageName: string;\n version: string;\n versionCode: number;\n url: string;\n hash?: string | null;\n size?: number | null;\n releaseNotes?: string | null;\n isMinimumVersion: boolean;\n createdAt: Date;\n}\n\nexport interface AppRollback {\n id: string;\n deviceId: string;\n packageName: string;\n fromVersion: string;\n fromVersionCode: number;\n toVersion: string;\n toVersionCode: number;\n reason?: string | null;\n status: 'pending' | 'in_progress' | 'completed' | 'failed';\n error?: string | null;\n initiatedBy?: string | null;\n createdAt: Date;\n completedAt?: Date | null;\n}\n\nexport interface CreateAppRollbackInput {\n deviceId: string;\n packageName: string;\n toVersionCode: number;\n reason?: string;\n initiatedBy?: string;\n}\n\n// ============================================\n// Command Types\n// ============================================\n\nexport type CommandType =\n | 'reboot'\n | 'shutdown'\n | 'sync'\n | 'lock'\n | 'unlock'\n | 'wipe'\n | 'factoryReset'\n | 'installApp'\n | 'uninstallApp'\n | 'updateApp'\n | 'runApp'\n | 'clearAppData'\n | 'clearAppCache'\n | 'shell'\n | 'setPolicy'\n | 'grantPermissions'\n | 'exitKiosk'\n | 'enterKiosk'\n | 'setWifi'\n | 'screenshot'\n | 'getLocation'\n | 'setVolume'\n | 'sendNotification'\n | 'whitelistBattery' // Whitelist app from battery optimization (Doze)\n | 'enablePermissiveMode' // Enable permissive mode for debugging\n | 'setTimeZone' // Set device timezone\n | 'enableAdb' // Enable/disable ADB debugging\n | 'rollbackApp' // Rollback to previous app version\n | 'updateAgent' // Update MDM agent to a new version\n | 'custom';\n\nexport type CommandStatus =\n | 'pending'\n | 'sent'\n | 'acknowledged'\n | 'completed'\n | 'failed'\n | 'cancelled';\n\nexport interface Command {\n id: string;\n deviceId: string;\n type: CommandType;\n payload?: Record<string, unknown> | null;\n status: CommandStatus;\n result?: CommandResult | null;\n error?: string | null;\n createdAt: Date;\n sentAt?: Date | null;\n acknowledgedAt?: Date | null;\n completedAt?: Date | null;\n}\n\nexport interface CommandResult {\n success: boolean;\n message?: string;\n data?: unknown;\n}\n\nexport interface SendCommandInput {\n deviceId: string;\n type: CommandType;\n payload?: Record<string, unknown>;\n}\n\nexport interface CommandFilter {\n deviceId?: string;\n status?: CommandStatus | CommandStatus[];\n type?: CommandType | CommandType[];\n limit?: number;\n offset?: number;\n}\n\n// ============================================\n// Event Types\n// ============================================\n\nexport type EventType =\n | 'device.enrolled'\n | 'device.unenrolled'\n | 'device.blocked'\n | 'device.heartbeat'\n | 'device.locationUpdated'\n | 'device.statusChanged'\n | 'device.policyChanged'\n | 'app.installed'\n | 'app.uninstalled'\n | 'app.updated'\n | 'app.crashed'\n | 'app.started'\n | 'app.stopped'\n | 'policy.applied'\n | 'policy.failed'\n | 'command.received'\n | 'command.acknowledged'\n | 'command.completed'\n | 'command.failed'\n | 'security.tamper'\n | 'security.rootDetected'\n | 'security.screenLocked'\n | 'security.screenUnlocked'\n | 'custom';\n\nexport interface MDMEvent<T = unknown> {\n id: string;\n deviceId: string;\n type: EventType;\n payload: T;\n createdAt: Date;\n}\n\nexport interface EventFilter {\n deviceId?: string;\n type?: EventType | EventType[];\n startDate?: Date;\n endDate?: Date;\n limit?: number;\n offset?: number;\n}\n\n// ============================================\n// Group Types\n// ============================================\n\nexport interface Group {\n id: string;\n name: string;\n description?: string | null;\n policyId?: string | null;\n parentId?: string | null;\n metadata?: Record<string, unknown> | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface CreateGroupInput {\n name: string;\n description?: string;\n policyId?: string;\n parentId?: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface UpdateGroupInput {\n name?: string;\n description?: string | null;\n policyId?: string | null;\n parentId?: string | null;\n metadata?: Record<string, unknown> | null;\n}\n\n// ============================================\n// Enrollment Types\n// ============================================\n\nexport type EnrollmentMethod =\n | 'qr'\n | 'nfc'\n | 'zero-touch'\n | 'knox'\n | 'manual'\n | 'app-only'\n | 'adb';\n\nexport interface EnrollmentRequest {\n // Device identifiers (at least one required)\n macAddress?: string;\n serialNumber?: string;\n imei?: string;\n androidId?: string;\n\n // Device info\n model: string;\n manufacturer: string;\n osVersion: string;\n sdkVersion?: number;\n\n // Agent info\n agentVersion?: string;\n agentPackage?: string;\n\n // Enrollment details\n method: EnrollmentMethod;\n timestamp: string;\n\n /**\n * Signature over the canonical enrollment message.\n *\n * Phase 2a (HMAC path, backwards-compatible): hex-encoded\n * HMAC-SHA256 of the nine-field pipe-delimited canonical form\n * (see `concepts/enrollment`).\n *\n * Phase 2b (device-pinned-key path, preferred): base64-encoded\n * DER ECDSA-P256 signature produced by the device's Keystore\n * private key, over `canonicalEnrollmentMessage(...)` including\n * the public key and challenge. The server distinguishes the\n * two paths by whether `publicKey` is present on the request.\n */\n signature: string;\n\n /**\n * Base64-encoded SPKI public key (EC P-256) the device generated\n * in its Keystore. When present, enrollment follows the Phase 2b\n * device-pinned-key path and `signature` must verify as an ECDSA\n * signature against this key. The server pins this key on the\n * device row on first successful enroll; any future enroll\n * attempting a different key for the same `enrollmentId` is\n * rejected with `PublicKeyMismatchError`.\n *\n * Omit for the legacy HMAC path. Callers that want to migrate a\n * fleet gradually can run both paths in parallel.\n */\n publicKey?: string;\n\n /**\n * Opaque challenge issued by `GET /agent/enroll/challenge`. Must\n * be present whenever `publicKey` is present — the server uses\n * it to prevent replay of captured enrollment payloads. The\n * challenge is single-use: the server consumes it on first\n * successful verify.\n */\n attestationChallenge?: string;\n\n // Optional pre-assigned policy/group\n policyId?: string;\n groupId?: string;\n}\n\nexport interface EnrollmentResponse {\n deviceId: string;\n enrollmentId: string;\n policyId?: string;\n policy?: Policy;\n serverUrl: string;\n pushConfig: PushConfig;\n token: string;\n refreshToken?: string;\n tokenExpiresAt?: Date;\n}\n\n// ============================================\n// Device Identity (Phase 2b)\n// ============================================\n\n/**\n * Single-use nonce issued by `GET /agent/enroll/challenge` and\n * consumed on first successful verify of a device-pinned-key\n * enrollment. A persisted record; the `consume*` adapter methods\n * enforce the single-use invariant.\n */\nexport interface EnrollmentChallenge {\n challenge: string;\n expiresAt: Date;\n consumedAt?: Date | null;\n createdAt: Date;\n}\n\n/**\n * Result of calling `verifyDeviceRequest`. Callers pattern-match on\n * `ok` and, when `false`, on `reason` to decide their response\n * shape:\n *\n * - `not-found` — unknown device id. Return 401.\n * - `no-pinned-key` — device exists but never migrated off the\n * legacy HMAC path. Caller should fall back\n * to their HMAC verifier, or fail if\n * they've completed their migration.\n * - `signature-invalid` — signature did not verify against the\n * pinned key. Return 401. Never re-pin\n * in response to this.\n */\nexport type DeviceIdentityVerification =\n | { ok: true; device: Device }\n | { ok: false; reason: 'not-found' }\n | { ok: false; reason: 'no-pinned-key'; device: Device }\n | { ok: false; reason: 'signature-invalid'; device: Device };\n\nexport interface PushConfig {\n provider: 'fcm' | 'mqtt' | 'websocket' | 'polling';\n fcmSenderId?: string;\n mqttUrl?: string;\n mqttTopic?: string;\n mqttUsername?: string;\n mqttPassword?: string;\n wsUrl?: string;\n pollingInterval?: number;\n}\n\n// ============================================\n// Telemetry Types\n// ============================================\n\nexport interface Heartbeat {\n deviceId: string;\n timestamp: Date;\n\n // Battery\n batteryLevel: number;\n isCharging: boolean;\n batteryHealth?: 'good' | 'overheat' | 'dead' | 'cold' | 'unknown';\n\n // Storage\n storageUsed: number;\n storageTotal: number;\n\n // Memory\n memoryUsed: number;\n memoryTotal: number;\n\n // Network\n networkType?: 'wifi' | 'cellular' | 'ethernet' | 'none';\n networkName?: string; // SSID or carrier\n signalStrength?: number;\n ipAddress?: string;\n\n // Location\n location?: DeviceLocation;\n\n // Apps\n installedApps: InstalledApp[];\n runningApps?: string[];\n\n // Security\n isRooted?: boolean;\n isEncrypted?: boolean;\n screenLockEnabled?: boolean;\n\n // Agent status\n agentVersion?: string;\n policyVersion?: string;\n lastPolicySync?: Date;\n}\n\n// ============================================\n// Push Token Types\n// ============================================\n\nexport interface PushToken {\n id: string;\n deviceId: string;\n provider: 'fcm' | 'mqtt' | 'websocket';\n token: string;\n isActive: boolean;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface RegisterPushTokenInput {\n deviceId: string;\n provider: 'fcm' | 'mqtt' | 'websocket';\n token: string;\n}\n\n// ============================================\n// Configuration Types\n// ============================================\n\nexport interface MDMConfig {\n /** Database adapter for persistence */\n database: DatabaseAdapter;\n\n /** Authentication/authorization configuration */\n auth?: AuthConfig;\n\n /** Push notification provider configuration */\n push?: PushProviderConfig;\n\n /** Device enrollment configuration */\n enrollment?: EnrollmentConfig;\n\n /** Server URL (used in enrollment responses) */\n serverUrl?: string;\n\n /** APK/file storage configuration */\n storage?: StorageConfig;\n\n /** Outbound webhook configuration */\n webhooks?: WebhookConfig;\n\n /** Plugins to extend functionality */\n plugins?: MDMPlugin[];\n\n /** Event handlers */\n onDeviceEnrolled?: (device: Device) => Promise<void>;\n onDeviceUnenrolled?: (device: Device) => Promise<void>;\n onDeviceBlocked?: (device: Device) => Promise<void>;\n onHeartbeat?: (device: Device, heartbeat: Heartbeat) => Promise<void>;\n onCommand?: (command: Command) => Promise<void>;\n onEvent?: (event: MDMEvent) => Promise<void>;\n\n // Enterprise features\n /** Multi-tenancy configuration */\n multiTenancy?: {\n enabled: boolean;\n defaultTenantId?: string;\n tenantResolver?: (context: unknown) => Promise<string | null>;\n };\n\n /** Authorization (RBAC) configuration */\n authorization?: {\n enabled: boolean;\n defaultRole?: string;\n };\n\n /** Audit logging configuration */\n audit?: {\n enabled: boolean;\n retentionDays?: number;\n };\n\n /** Scheduling configuration */\n scheduling?: {\n enabled: boolean;\n timezone?: string;\n };\n\n /** Plugin storage configuration */\n pluginStorage?: {\n adapter: 'database' | 'memory';\n };\n\n /**\n * Structured logger. Replaces OpenMDM's internal `console.*` calls\n * so log output lands in the host application's logging pipeline\n * (pino, winston, bunyan, OTEL collector, etc.) instead of raw\n * stderr.\n *\n * The shape is a strict subset of the pino / winston / bunyan\n * interface — any of those can be passed directly. If omitted, a\n * default logger that writes to the console with an `[openmdm]`\n * prefix is used. To silence OpenMDM entirely, pass a no-op\n * implementation (see `createSilentLogger()` in the package\n * exports).\n */\n logger?: Logger;\n}\n\n/**\n * Minimal structured-logger interface OpenMDM calls internally.\n *\n * The shape is deliberately the pino-compatible subset: an optional\n * context object as the first argument followed by a message string.\n * pino, winston, bunyan, and most other structured loggers accept\n * this shape natively.\n *\n * Implementations should be side-effect-free on unconfigured levels\n * (a production logger filtered to `info` should still accept\n * `.debug()` calls cheaply).\n */\nexport interface Logger {\n /** Human-ignorable, high-volume tracing. Off in production by default. */\n debug(context: LogContext, message: string): void;\n debug(message: string): void;\n\n /** Normal operational events. Enrollment, policy changes, command delivery. */\n info(context: LogContext, message: string): void;\n info(message: string): void;\n\n /** Something is wrong but the server is still running. Retries, fallbacks, degraded modes. */\n warn(context: LogContext, message: string): void;\n warn(message: string): void;\n\n /** Something failed and a request/operation did not complete. */\n error(context: LogContext, message: string): void;\n error(message: string): void;\n\n /**\n * Return a new logger with the given fields attached to every\n * subsequent call. Used by managers and plugins to scope logs to\n * a specific subsystem without repeating context.\n */\n child(bindings: LogContext): Logger;\n}\n\n/**\n * Arbitrary structured context attached to a log line. Values must\n * be JSON-serializable so host loggers can ship them to any backend.\n */\nexport type LogContext = Record<string, unknown>;\n\nexport interface StorageConfig {\n /** Storage provider (s3, local, custom) */\n provider: 's3' | 'local' | 'custom';\n\n /** S3 configuration */\n s3?: {\n bucket: string;\n region: string;\n accessKeyId?: string;\n secretAccessKey?: string;\n endpoint?: string; // For S3-compatible services\n presignedUrlExpiry?: number; // Seconds, default 3600\n };\n\n /** Local storage path */\n localPath?: string;\n\n /** Custom storage adapter */\n customAdapter?: {\n upload: (file: Buffer, key: string) => Promise<string>;\n getUrl: (key: string) => Promise<string>;\n delete: (key: string) => Promise<void>;\n };\n}\n\nexport interface WebhookConfig {\n /** Webhook endpoints to notify */\n endpoints?: WebhookEndpoint[];\n\n /** Retry configuration */\n retry?: {\n maxRetries?: number;\n initialDelay?: number;\n maxDelay?: number;\n };\n\n /** Sign webhooks with HMAC secret */\n signingSecret?: string;\n}\n\nexport interface WebhookEndpoint {\n /** Unique identifier */\n id: string;\n /** Webhook URL */\n url: string;\n /** Events to trigger this webhook */\n events: (EventType | '*')[];\n /** Custom headers */\n headers?: Record<string, string>;\n /** Whether endpoint is active */\n enabled: boolean;\n}\n\nexport interface AuthConfig {\n /** Get current user from request context */\n getUser: <T = unknown>(context: unknown) => Promise<T | null>;\n /** Check if user has admin privileges */\n isAdmin?: (user: unknown) => Promise<boolean>;\n /** Check if user can access specific device */\n canAccessDevice?: (user: unknown, deviceId: string) => Promise<boolean>;\n /** Device JWT secret (for device auth tokens) */\n deviceTokenSecret?: string;\n /** Device token expiration in seconds (default: 365 days) */\n deviceTokenExpiration?: number;\n}\n\nexport interface PushProviderConfig {\n provider: 'fcm' | 'mqtt' | 'websocket' | 'polling';\n\n // FCM configuration\n fcmCredentials?: string | Record<string, unknown>;\n fcmProjectId?: string;\n\n // MQTT configuration\n mqttUrl?: string;\n mqttUsername?: string;\n mqttPassword?: string;\n mqttTopicPrefix?: string;\n\n // WebSocket configuration\n wsPath?: string;\n wsPingInterval?: number;\n\n // Polling fallback\n pollingInterval?: number;\n}\n\nexport interface EnrollmentConfig {\n /** Auto-enroll devices with valid signature */\n autoEnroll?: boolean;\n /** HMAC secret for device signature verification (Phase 2a path) */\n deviceSecret: string;\n /** Allowed enrollment methods */\n allowedMethods?: EnrollmentMethod[];\n /** Default policy for new devices */\n defaultPolicyId?: string;\n /** Default group for new devices */\n defaultGroupId?: string;\n /** Require manual approval for enrollment */\n requireApproval?: boolean;\n /** Custom enrollment validation */\n validate?: (request: EnrollmentRequest) => Promise<boolean>;\n\n /**\n * Phase 2b device-pinned-key configuration. Optional — when\n * omitted, enrollment continues to accept the Phase 2a HMAC path\n * exclusively, matching pre-0.9 behaviour.\n */\n pinnedKey?: PinnedKeyConfig;\n}\n\n/**\n * Device-pinned-key enrollment options. See\n * `docs/concepts/enrollment` for the full flow.\n */\nexport interface PinnedKeyConfig {\n /**\n * Require every new enrollment to use the pinned-key path. When\n * `true`, requests without `publicKey` are rejected. When `false`\n * (the default), both paths coexist during rollout — the server\n * pins a public key when one is provided, falls back to HMAC when\n * it isn't.\n */\n required?: boolean;\n\n /**\n * TTL for enrollment challenges, in seconds. Defaults to 300\n * (5 minutes). Challenges are single-use; this only bounds how\n * long an unused challenge stays valid.\n */\n challengeTtlSeconds?: number;\n}\n\n// ============================================\n// Adapter Interfaces\n// ============================================\n\nexport interface DatabaseAdapter {\n // Devices\n findDevice(id: string): Promise<Device | null>;\n findDeviceByEnrollmentId(enrollmentId: string): Promise<Device | null>;\n listDevices(filter?: DeviceFilter): Promise<DeviceListResult>;\n createDevice(data: CreateDeviceInput): Promise<Device>;\n updateDevice(id: string, data: UpdateDeviceInput): Promise<Device>;\n deleteDevice(id: string): Promise<void>;\n countDevices(filter?: DeviceFilter): Promise<number>;\n\n // Policies\n findPolicy(id: string): Promise<Policy | null>;\n findDefaultPolicy(): Promise<Policy | null>;\n listPolicies(): Promise<Policy[]>;\n createPolicy(data: CreatePolicyInput): Promise<Policy>;\n updatePolicy(id: string, data: UpdatePolicyInput): Promise<Policy>;\n deletePolicy(id: string): Promise<void>;\n\n // Applications\n findApplication(id: string): Promise<Application | null>;\n findApplicationByPackage(packageName: string, version?: string): Promise<Application | null>;\n listApplications(activeOnly?: boolean): Promise<Application[]>;\n createApplication(data: CreateApplicationInput): Promise<Application>;\n updateApplication(id: string, data: UpdateApplicationInput): Promise<Application>;\n deleteApplication(id: string): Promise<void>;\n\n // Commands\n findCommand(id: string): Promise<Command | null>;\n listCommands(filter?: CommandFilter): Promise<Command[]>;\n createCommand(data: SendCommandInput): Promise<Command>;\n updateCommand(id: string, data: Partial<Command>): Promise<Command | null>;\n getPendingCommands(deviceId: string): Promise<Command[]>;\n\n // Events\n createEvent(event: Omit<MDMEvent, 'id' | 'createdAt'>): Promise<MDMEvent>;\n listEvents(filter?: EventFilter): Promise<MDMEvent[]>;\n\n // Groups\n findGroup(id: string): Promise<Group | null>;\n listGroups(): Promise<Group[]>;\n createGroup(data: CreateGroupInput): Promise<Group>;\n updateGroup(id: string, data: UpdateGroupInput): Promise<Group>;\n deleteGroup(id: string): Promise<void>;\n listDevicesInGroup(groupId: string): Promise<Device[]>;\n addDeviceToGroup(deviceId: string, groupId: string): Promise<void>;\n removeDeviceFromGroup(deviceId: string, groupId: string): Promise<void>;\n getDeviceGroups(deviceId: string): Promise<Group[]>;\n\n // Push Tokens\n findPushToken(deviceId: string, provider: string): Promise<PushToken | null>;\n upsertPushToken(data: RegisterPushTokenInput): Promise<PushToken>;\n deletePushToken(deviceId: string, provider?: string): Promise<void>;\n\n // App Versions (optional - for version tracking)\n listAppVersions?(packageName: string): Promise<AppVersion[]>;\n createAppVersion?(data: Omit<AppVersion, 'id' | 'createdAt'>): Promise<AppVersion>;\n setMinimumVersion?(packageName: string, versionCode: number): Promise<void>;\n getMinimumVersion?(packageName: string): Promise<AppVersion | null>;\n\n // Rollback History (optional)\n createRollback?(data: CreateAppRollbackInput): Promise<AppRollback>;\n updateRollback?(id: string, data: Partial<AppRollback>): Promise<AppRollback>;\n listRollbacks?(filter?: { deviceId?: string; packageName?: string }): Promise<AppRollback[]>;\n\n // Group Hierarchy (optional)\n getGroupChildren?(parentId: string | null): Promise<Group[]>;\n getGroupAncestors?(groupId: string): Promise<Group[]>;\n getGroupDescendants?(groupId: string): Promise<Group[]>;\n getGroupTree?(rootId?: string): Promise<GroupTreeNode[]>;\n getGroupEffectivePolicy?(groupId: string): Promise<Policy | null>;\n moveGroup?(groupId: string, newParentId: string | null): Promise<Group>;\n getGroupHierarchyStats?(): Promise<GroupHierarchyStats>;\n\n // Enrollment challenges (optional - for Phase 2b device-pinned-key)\n /**\n * Persist a new single-use enrollment challenge. The adapter\n * should store it with `consumed_at = null` and enforce a\n * primary-key constraint on `challenge` so duplicate inserts\n * fail loudly.\n */\n createEnrollmentChallenge?(challenge: EnrollmentChallenge): Promise<void>;\n /**\n * Look up a challenge by its opaque value. Returns `null` if not\n * found. Does NOT filter on expiry — the core layer checks\n * freshness so the adapter stays dumb.\n */\n findEnrollmentChallenge?(challenge: string): Promise<EnrollmentChallenge | null>;\n /**\n * Atomically mark a challenge as consumed. Must set\n * `consumed_at = now()` and return the updated row only when the\n * challenge was previously unused. Adapters should implement\n * this as a conditional UPDATE (e.g. Postgres\n * `UPDATE ... WHERE consumed_at IS NULL RETURNING *`) so two\n * concurrent consume attempts cannot both succeed.\n */\n consumeEnrollmentChallenge?(challenge: string): Promise<EnrollmentChallenge | null>;\n /**\n * Delete expired, unconsumed challenges. Called periodically by\n * the core layer; adapters can no-op if they rely on a TTL index\n * elsewhere.\n */\n pruneExpiredEnrollmentChallenges?(now: Date): Promise<number>;\n\n // Tenants (optional - for multi-tenancy)\n findTenant?(id: string): Promise<Tenant | null>;\n findTenantBySlug?(slug: string): Promise<Tenant | null>;\n listTenants?(filter?: TenantFilter): Promise<TenantListResult>;\n createTenant?(data: CreateTenantInput): Promise<Tenant>;\n updateTenant?(id: string, data: UpdateTenantInput): Promise<Tenant>;\n deleteTenant?(id: string): Promise<void>;\n getTenantStats?(tenantId: string): Promise<TenantStats>;\n\n // Users (optional - for RBAC)\n findUser?(id: string): Promise<User | null>;\n findUserByEmail?(email: string, tenantId?: string): Promise<User | null>;\n listUsers?(filter?: UserFilter): Promise<UserListResult>;\n createUser?(data: CreateUserInput): Promise<User>;\n updateUser?(id: string, data: UpdateUserInput): Promise<User>;\n deleteUser?(id: string): Promise<void>;\n\n // Roles (optional - for RBAC)\n findRole?(id: string): Promise<Role | null>;\n listRoles?(tenantId?: string): Promise<Role[]>;\n createRole?(data: CreateRoleInput): Promise<Role>;\n updateRole?(id: string, data: UpdateRoleInput): Promise<Role>;\n deleteRole?(id: string): Promise<void>;\n assignRoleToUser?(userId: string, roleId: string): Promise<void>;\n removeRoleFromUser?(userId: string, roleId: string): Promise<void>;\n getUserRoles?(userId: string): Promise<Role[]>;\n\n // Audit Logs (optional - for compliance)\n createAuditLog?(data: CreateAuditLogInput): Promise<AuditLog>;\n listAuditLogs?(filter?: AuditLogFilter): Promise<AuditLogListResult>;\n deleteAuditLogs?(filter: { olderThan?: Date; tenantId?: string }): Promise<number>;\n\n // Scheduled Tasks (optional - for scheduling)\n findScheduledTask?(id: string): Promise<ScheduledTask | null>;\n listScheduledTasks?(filter?: ScheduledTaskFilter): Promise<ScheduledTaskListResult>;\n createScheduledTask?(data: CreateScheduledTaskInput): Promise<ScheduledTask>;\n updateScheduledTask?(id: string, data: UpdateScheduledTaskInput): Promise<ScheduledTask>;\n deleteScheduledTask?(id: string): Promise<void>;\n getUpcomingTasks?(hours: number): Promise<ScheduledTask[]>;\n createTaskExecution?(data: { taskId: string }): Promise<TaskExecution>;\n updateTaskExecution?(id: string, data: Partial<TaskExecution>): Promise<TaskExecution>;\n listTaskExecutions?(taskId: string, limit?: number): Promise<TaskExecution[]>;\n\n // Message Queue (optional - for persistent messaging)\n enqueueMessage?(data: EnqueueMessageInput): Promise<QueuedMessage>;\n dequeueMessages?(deviceId: string, limit?: number): Promise<QueuedMessage[]>;\n peekMessages?(deviceId: string, limit?: number): Promise<QueuedMessage[]>;\n acknowledgeMessage?(messageId: string): Promise<void>;\n failMessage?(messageId: string, error: string): Promise<void>;\n retryFailedMessages?(maxAttempts?: number): Promise<number>;\n purgeExpiredMessages?(): Promise<number>;\n getQueueStats?(tenantId?: string): Promise<QueueStats>;\n\n // Plugin Storage (optional)\n getPluginValue?(pluginName: string, key: string): Promise<unknown | null>;\n setPluginValue?(pluginName: string, key: string, value: unknown): Promise<void>;\n deletePluginValue?(pluginName: string, key: string): Promise<void>;\n listPluginKeys?(pluginName: string, prefix?: string): Promise<string[]>;\n clearPluginData?(pluginName: string): Promise<void>;\n\n // Dashboard (optional - for analytics)\n getDashboardStats?(tenantId?: string): Promise<DashboardStats>;\n getDeviceStatusBreakdown?(tenantId?: string): Promise<DeviceStatusBreakdown>;\n getEnrollmentTrend?(days: number, tenantId?: string): Promise<EnrollmentTrendPoint[]>;\n getCommandSuccessRates?(tenantId?: string): Promise<CommandSuccessRates>;\n getAppInstallationSummary?(tenantId?: string): Promise<AppInstallationSummary>;\n\n // Transactions (optional)\n transaction?<T>(fn: () => Promise<T>): Promise<T>;\n}\n\nexport interface PushAdapter {\n /** Send push message to a device */\n send(deviceId: string, message: PushMessage): Promise<PushResult>;\n /** Send push message to multiple devices */\n sendBatch(deviceIds: string[], message: PushMessage): Promise<PushBatchResult>;\n /** Register device push token */\n registerToken?(deviceId: string, token: string): Promise<void>;\n /** Unregister device push token */\n unregisterToken?(deviceId: string): Promise<void>;\n /** Subscribe device to topic */\n subscribe?(deviceId: string, topic: string): Promise<void>;\n /** Unsubscribe device from topic */\n unsubscribe?(deviceId: string, topic: string): Promise<void>;\n}\n\nexport interface PushMessage {\n type: string;\n payload?: Record<string, unknown>;\n priority?: 'high' | 'normal';\n ttl?: number;\n collapseKey?: string;\n}\n\nexport interface PushResult {\n success: boolean;\n messageId?: string;\n error?: string;\n}\n\nexport interface PushBatchResult {\n successCount: number;\n failureCount: number;\n results: Array<{ deviceId: string; result: PushResult }>;\n}\n\n// ============================================\n// Plugin Interface\n// ============================================\n\nexport interface MDMPlugin {\n /** Unique plugin name */\n name: string;\n /** Plugin version */\n version: string;\n\n /** Called when MDM is initialized */\n onInit?(mdm: MDMInstance): Promise<void>;\n\n /** Called when MDM is destroyed */\n onDestroy?(): Promise<void>;\n\n /** Additional routes to mount */\n routes?: PluginRoute[];\n\n /** Middleware to apply to all routes */\n middleware?: PluginMiddleware[];\n\n /** Extend enrollment process */\n onEnroll?(device: Device, request: EnrollmentRequest): Promise<void>;\n\n /** Extend device processing */\n onDeviceEnrolled?(device: Device): Promise<void>;\n onDeviceUnenrolled?(device: Device): Promise<void>;\n onHeartbeat?(device: Device, heartbeat: Heartbeat): Promise<void>;\n\n /** Extend policy processing */\n policySchema?: Record<string, unknown>;\n validatePolicy?(settings: PolicySettings): Promise<{ valid: boolean; errors?: string[] }>;\n applyPolicy?(device: Device, policy: Policy): Promise<void>;\n\n /** Extend command processing */\n commandTypes?: CommandType[];\n executeCommand?(device: Device, command: Command): Promise<CommandResult>;\n}\n\nexport interface PluginRoute {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n path: string;\n handler: (context: unknown) => Promise<unknown>;\n auth?: boolean;\n admin?: boolean;\n}\n\nexport type PluginMiddleware = (\n context: unknown,\n next: () => Promise<unknown>\n) => Promise<unknown>;\n\n// ============================================\n// MDM Instance Interface\n// ============================================\n\nexport interface WebhookManager {\n /** Deliver an event to all matching webhook endpoints */\n deliver<T>(event: MDMEvent<T>): Promise<WebhookDeliveryResult[]>;\n /** Add a webhook endpoint at runtime */\n addEndpoint(endpoint: WebhookEndpoint): void;\n /** Remove a webhook endpoint */\n removeEndpoint(endpointId: string): void;\n /** Update a webhook endpoint */\n updateEndpoint(endpointId: string, updates: Partial<WebhookEndpoint>): void;\n /** Get all configured endpoints */\n getEndpoints(): WebhookEndpoint[];\n /** Test a webhook endpoint with a test payload */\n testEndpoint(endpointId: string): Promise<WebhookDeliveryResult>;\n}\n\nexport interface WebhookDeliveryResult {\n endpointId: string;\n success: boolean;\n statusCode?: number;\n error?: string;\n retryCount: number;\n deliveredAt?: Date;\n}\n\nexport interface MDMInstance {\n /** Device management */\n devices: DeviceManager;\n /** Policy management */\n policies: PolicyManager;\n /** Application management */\n apps: ApplicationManager;\n /** Command management */\n commands: CommandManager;\n /** Group management */\n groups: GroupManager;\n\n /** Tenant management (if multi-tenancy enabled) */\n tenants?: TenantManager;\n /** Authorization management (RBAC) */\n authorization?: AuthorizationManager;\n /** Audit logging */\n audit?: AuditManager;\n /** Scheduled task management */\n schedules?: ScheduleManager;\n /** Persistent message queue */\n messageQueue?: MessageQueueManager;\n /** Dashboard analytics */\n dashboard?: DashboardManager;\n /** Plugin storage */\n pluginStorage?: PluginStorageAdapter;\n\n /** Push notification service */\n push: PushAdapter;\n\n /** Webhook delivery (if configured) */\n webhooks?: WebhookManager;\n\n /** Database adapter */\n db: DatabaseAdapter;\n\n /** Structured logger. Already scoped to the `openmdm` namespace. Plugins should call `.child({...})` to scope further. */\n logger: Logger;\n\n /** Configuration */\n config: MDMConfig;\n\n /** Subscribe to events */\n on<T extends EventType>(event: T, handler: EventHandler<T>): () => void;\n /** Emit an event */\n emit<T extends EventType>(event: T, data: EventPayloadMap[T]): Promise<void>;\n\n /** Process device enrollment */\n enroll(request: EnrollmentRequest): Promise<EnrollmentResponse>;\n /** Process device heartbeat */\n processHeartbeat(deviceId: string, heartbeat: Heartbeat): Promise<void>;\n /** Verify device token */\n verifyDeviceToken(token: string): Promise<{ deviceId: string } | null>;\n\n /** Get loaded plugins */\n getPlugins(): MDMPlugin[];\n /** Get plugin by name */\n getPlugin(name: string): MDMPlugin | undefined;\n}\n\n// ============================================\n// Manager Interfaces\n// ============================================\n\nexport interface DeviceManager {\n get(id: string): Promise<Device | null>;\n getByEnrollmentId(enrollmentId: string): Promise<Device | null>;\n list(filter?: DeviceFilter): Promise<DeviceListResult>;\n create(data: CreateDeviceInput): Promise<Device>;\n update(id: string, data: UpdateDeviceInput): Promise<Device>;\n delete(id: string): Promise<void>;\n assignPolicy(deviceId: string, policyId: string | null): Promise<Device>;\n addToGroup(deviceId: string, groupId: string): Promise<void>;\n removeFromGroup(deviceId: string, groupId: string): Promise<void>;\n getGroups(deviceId: string): Promise<Group[]>;\n sendCommand(deviceId: string, input: Omit<SendCommandInput, 'deviceId'>): Promise<Command>;\n sync(deviceId: string): Promise<Command>;\n reboot(deviceId: string): Promise<Command>;\n lock(deviceId: string, message?: string): Promise<Command>;\n wipe(deviceId: string, preserveData?: boolean): Promise<Command>;\n}\n\nexport interface PolicyManager {\n get(id: string): Promise<Policy | null>;\n getDefault(): Promise<Policy | null>;\n list(): Promise<Policy[]>;\n create(data: CreatePolicyInput): Promise<Policy>;\n update(id: string, data: UpdatePolicyInput): Promise<Policy>;\n delete(id: string): Promise<void>;\n setDefault(id: string): Promise<Policy>;\n getDevices(policyId: string): Promise<Device[]>;\n applyToDevice(policyId: string, deviceId: string): Promise<void>;\n}\n\nexport interface ApplicationManager {\n get(id: string): Promise<Application | null>;\n getByPackage(packageName: string, version?: string): Promise<Application | null>;\n list(activeOnly?: boolean): Promise<Application[]>;\n register(data: CreateApplicationInput): Promise<Application>;\n update(id: string, data: UpdateApplicationInput): Promise<Application>;\n delete(id: string): Promise<void>;\n activate(id: string): Promise<Application>;\n deactivate(id: string): Promise<Application>;\n deploy(packageName: string, target: DeployTarget): Promise<void>;\n installOnDevice(packageName: string, deviceId: string, version?: string): Promise<Command>;\n uninstallFromDevice(packageName: string, deviceId: string): Promise<Command>;\n}\n\nexport interface CommandManager {\n get(id: string): Promise<Command | null>;\n list(filter?: CommandFilter): Promise<Command[]>;\n send(input: SendCommandInput): Promise<Command>;\n cancel(id: string): Promise<Command>;\n acknowledge(id: string): Promise<Command>;\n complete(id: string, result: CommandResult): Promise<Command>;\n fail(id: string, error: string): Promise<Command>;\n getPending(deviceId: string): Promise<Command[]>;\n}\n\nexport interface GroupManager {\n // Basic CRUD operations\n get(id: string): Promise<Group | null>;\n list(): Promise<Group[]>;\n create(data: CreateGroupInput): Promise<Group>;\n update(id: string, data: UpdateGroupInput): Promise<Group>;\n delete(id: string): Promise<void>;\n\n // Device management\n getDevices(groupId: string): Promise<Device[]>;\n addDevice(groupId: string, deviceId: string): Promise<void>;\n removeDevice(groupId: string, deviceId: string): Promise<void>;\n\n // Hierarchy operations\n getChildren(groupId: string): Promise<Group[]>;\n getTree(rootId?: string): Promise<GroupTreeNode[]>;\n getAncestors(groupId: string): Promise<Group[]>;\n getDescendants(groupId: string): Promise<Group[]>;\n move(groupId: string, newParentId: string | null): Promise<Group>;\n getEffectivePolicy(groupId: string): Promise<Policy | null>;\n getHierarchyStats(): Promise<GroupHierarchyStats>;\n}\n\n// ============================================\n// Group Hierarchy Types\n// ============================================\n\nexport interface GroupTreeNode extends Group {\n children: GroupTreeNode[];\n depth: number;\n path: string[];\n effectivePolicyId?: string | null;\n}\n\nexport interface GroupHierarchyStats {\n totalGroups: number;\n maxDepth: number;\n groupsWithDevices: number;\n groupsWithPolicies: number;\n}\n\n// ============================================\n// Tenant Types (Multi-tenancy)\n// ============================================\n\nexport type TenantStatus = 'active' | 'suspended' | 'pending';\n\nexport interface Tenant {\n id: string;\n name: string;\n slug: string;\n status: TenantStatus;\n settings?: TenantSettings | null;\n metadata?: Record<string, unknown> | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface TenantSettings {\n maxDevices?: number;\n maxUsers?: number;\n features?: string[];\n branding?: {\n logo?: string;\n primaryColor?: string;\n };\n}\n\nexport interface CreateTenantInput {\n name: string;\n slug: string;\n settings?: TenantSettings;\n metadata?: Record<string, unknown>;\n}\n\nexport interface UpdateTenantInput {\n name?: string;\n slug?: string;\n status?: TenantStatus;\n settings?: TenantSettings;\n metadata?: Record<string, unknown>;\n}\n\nexport interface TenantFilter {\n status?: TenantStatus;\n search?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface TenantListResult {\n tenants: Tenant[];\n total: number;\n limit: number;\n offset: number;\n}\n\nexport interface TenantStats {\n deviceCount: number;\n userCount: number;\n policyCount: number;\n appCount: number;\n}\n\n// ============================================\n// RBAC Types (Role-Based Access Control)\n// ============================================\n\nexport type PermissionAction = 'create' | 'read' | 'update' | 'delete' | 'manage' | '*';\nexport type PermissionResource = 'devices' | 'policies' | 'apps' | 'groups' | 'commands' | 'users' | 'roles' | 'tenants' | 'audit' | '*';\n\nexport interface Permission {\n action: PermissionAction;\n resource: PermissionResource;\n resourceId?: string;\n}\n\nexport interface Role {\n id: string;\n tenantId?: string | null;\n name: string;\n description?: string | null;\n permissions: Permission[];\n isSystem: boolean;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface CreateRoleInput {\n tenantId?: string;\n name: string;\n description?: string;\n permissions: Permission[];\n}\n\nexport interface UpdateRoleInput {\n name?: string;\n description?: string;\n permissions?: Permission[];\n}\n\nexport interface User {\n id: string;\n tenantId?: string | null;\n email: string;\n name?: string | null;\n status: 'active' | 'inactive' | 'pending';\n metadata?: Record<string, unknown> | null;\n lastLoginAt?: Date | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface UserWithRoles extends User {\n roles: Role[];\n}\n\nexport interface CreateUserInput {\n tenantId?: string;\n email: string;\n name?: string;\n status?: 'active' | 'inactive' | 'pending';\n metadata?: Record<string, unknown>;\n}\n\nexport interface UpdateUserInput {\n email?: string;\n name?: string;\n status?: 'active' | 'inactive' | 'pending';\n metadata?: Record<string, unknown>;\n}\n\nexport interface UserFilter {\n tenantId?: string;\n status?: 'active' | 'inactive' | 'pending';\n search?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface UserListResult {\n users: User[];\n total: number;\n limit: number;\n offset: number;\n}\n\n// ============================================\n// Audit Types\n// ============================================\n\nexport type AuditAction = 'create' | 'read' | 'update' | 'delete' | 'login' | 'logout' | 'enroll' | 'unenroll' | 'command' | 'export' | 'import' | 'custom';\n\nexport interface AuditLog {\n id: string;\n tenantId?: string | null;\n userId?: string | null;\n action: AuditAction;\n resource: string;\n resourceId?: string | null;\n status: 'success' | 'failure';\n error?: string | null;\n details?: Record<string, unknown> | null;\n ipAddress?: string | null;\n userAgent?: string | null;\n createdAt: Date;\n}\n\nexport interface CreateAuditLogInput {\n tenantId?: string;\n userId?: string;\n action: AuditAction;\n resource: string;\n resourceId?: string;\n status?: 'success' | 'failure';\n error?: string;\n details?: Record<string, unknown>;\n ipAddress?: string;\n userAgent?: string;\n}\n\nexport interface AuditConfig {\n enabled: boolean;\n retentionDays?: number;\n skipReadOperations?: boolean;\n logActions?: AuditAction[];\n logResources?: string[];\n}\n\nexport interface AuditSummary {\n totalLogs: number;\n byAction: Record<AuditAction, number>;\n byResource: Record<string, number>;\n byStatus: { success: number; failure: number };\n topUsers: Array<{ userId: string; count: number }>;\n recentFailures: AuditLog[];\n}\n\nexport interface AuditLogFilter {\n tenantId?: string;\n userId?: string;\n action?: string;\n resource?: string;\n resourceId?: string;\n startDate?: Date;\n endDate?: Date;\n limit?: number;\n offset?: number;\n}\n\nexport interface AuditLogListResult {\n logs: AuditLog[];\n total: number;\n limit: number;\n offset: number;\n}\n\n// ============================================\n// Schedule Types\n// ============================================\n\nexport type TaskType = 'command' | 'policy_update' | 'app_install' | 'maintenance' | 'custom';\nexport type ScheduledTaskStatus = 'active' | 'paused' | 'completed' | 'failed';\n\nexport interface MaintenanceWindow {\n daysOfWeek: number[];\n startTime: string;\n endTime: string;\n timezone: string;\n}\n\nexport interface TaskSchedule {\n type: 'once' | 'recurring' | 'window';\n executeAt?: Date;\n cron?: string;\n window?: MaintenanceWindow;\n}\n\nexport interface ScheduledTask {\n id: string;\n tenantId?: string | null;\n name: string;\n description?: string | null;\n taskType: TaskType;\n schedule: TaskSchedule;\n target?: DeployTarget;\n payload?: Record<string, unknown> | null;\n status: ScheduledTaskStatus;\n nextRunAt?: Date | null;\n lastRunAt?: Date | null;\n maxRetries: number;\n retryCount: number;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface CreateScheduledTaskInput {\n tenantId?: string;\n name: string;\n description?: string;\n taskType: TaskType;\n schedule: TaskSchedule;\n target?: DeployTarget;\n payload?: Record<string, unknown>;\n maxRetries?: number;\n}\n\nexport interface UpdateScheduledTaskInput {\n name?: string;\n description?: string;\n schedule?: TaskSchedule;\n target?: DeployTarget;\n payload?: Record<string, unknown>;\n status?: ScheduledTaskStatus;\n maxRetries?: number;\n}\n\nexport interface ScheduledTaskFilter {\n tenantId?: string;\n taskType?: TaskType | TaskType[];\n status?: ScheduledTaskStatus | ScheduledTaskStatus[];\n limit?: number;\n offset?: number;\n}\n\nexport interface ScheduledTaskListResult {\n tasks: ScheduledTask[];\n total: number;\n limit: number;\n offset: number;\n}\n\nexport interface TaskExecution {\n id: string;\n taskId: string;\n status: 'running' | 'completed' | 'failed';\n startedAt: Date;\n completedAt?: Date | null;\n devicesProcessed: number;\n devicesSucceeded: number;\n devicesFailed: number;\n error?: string | null;\n details?: Record<string, unknown> | null;\n}\n\n// ============================================\n// Message Queue Types\n// ============================================\n\nexport type QueueMessageStatus = 'pending' | 'processing' | 'delivered' | 'failed' | 'expired';\n\nexport interface QueuedMessage {\n id: string;\n tenantId?: string | null;\n deviceId: string;\n messageType: string;\n payload: Record<string, unknown>;\n priority: 'high' | 'normal' | 'low';\n status: QueueMessageStatus;\n attempts: number;\n maxAttempts: number;\n lastAttemptAt?: Date | null;\n lastError?: string | null;\n expiresAt?: Date | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface EnqueueMessageInput {\n tenantId?: string;\n deviceId: string;\n messageType: string;\n payload: Record<string, unknown>;\n priority?: 'high' | 'normal' | 'low';\n maxAttempts?: number;\n ttlSeconds?: number;\n}\n\nexport interface QueueStats {\n pending: number;\n processing: number;\n delivered: number;\n failed: number;\n expired: number;\n byDevice: Record<string, number>;\n oldestPending?: Date;\n}\n\n// ============================================\n// Dashboard Types\n// ============================================\n\nexport interface DashboardStats {\n devices: {\n total: number;\n enrolled: number;\n active: number;\n blocked: number;\n pending: number;\n };\n policies: {\n total: number;\n deployed: number;\n };\n applications: {\n total: number;\n deployed: number;\n };\n commands: {\n pendingCount: number;\n last24hTotal: number;\n last24hSuccess: number;\n last24hFailed: number;\n };\n groups: {\n total: number;\n withDevices: number;\n };\n}\n\nexport interface DeviceStatusBreakdown {\n byStatus: Record<DeviceStatus, number>;\n byOs: Record<string, number>;\n byManufacturer: Record<string, number>;\n byModel: Record<string, number>;\n}\n\nexport interface EnrollmentTrendPoint {\n date: Date;\n enrolled: number;\n unenrolled: number;\n netChange: number;\n totalDevices: number;\n}\n\nexport interface CommandSuccessRates {\n overall: {\n total: number;\n completed: number;\n failed: number;\n successRate: number;\n };\n byType: Record<string, {\n total: number;\n completed: number;\n failed: number;\n successRate: number;\n avgExecutionTimeMs?: number;\n }>;\n last24h: {\n total: number;\n completed: number;\n failed: number;\n pending: number;\n };\n}\n\nexport interface AppInstallationSummary {\n total: number;\n byStatus: Record<string, number>;\n recentFailures: Array<{\n packageName: string;\n deviceId: string;\n error: string;\n timestamp: Date;\n }>;\n topInstalled: Array<{\n packageName: string;\n name: string;\n installedCount: number;\n }>;\n}\n\n// ============================================\n// Plugin Storage Types\n// ============================================\n\nexport interface PluginStorageAdapter {\n get<T>(pluginName: string, key: string): Promise<T | null>;\n set<T>(pluginName: string, key: string, value: T): Promise<void>;\n delete(pluginName: string, key: string): Promise<void>;\n list(pluginName: string, prefix?: string): Promise<string[]>;\n clear(pluginName: string): Promise<void>;\n}\n\nexport interface PluginStorageEntry {\n pluginName: string;\n key: string;\n value: unknown;\n createdAt: Date;\n updatedAt: Date;\n}\n\n// ============================================\n// Enterprise Manager Interfaces\n// ============================================\n\nexport interface TenantManager {\n get(id: string): Promise<Tenant | null>;\n getBySlug(slug: string): Promise<Tenant | null>;\n list(filter?: TenantFilter): Promise<TenantListResult>;\n create(data: CreateTenantInput): Promise<Tenant>;\n update(id: string, data: UpdateTenantInput): Promise<Tenant>;\n delete(id: string, cascade?: boolean): Promise<void>;\n getStats(tenantId: string): Promise<TenantStats>;\n activate(id: string): Promise<Tenant>;\n deactivate(id: string): Promise<Tenant>;\n}\n\nexport interface AuthorizationManager {\n createRole(data: CreateRoleInput): Promise<Role>;\n getRole(id: string): Promise<Role | null>;\n listRoles(tenantId?: string): Promise<Role[]>;\n updateRole(id: string, data: UpdateRoleInput): Promise<Role>;\n deleteRole(id: string): Promise<void>;\n createUser(data: CreateUserInput): Promise<User>;\n getUser(id: string): Promise<UserWithRoles | null>;\n getUserByEmail(email: string, tenantId?: string): Promise<UserWithRoles | null>;\n listUsers(filter?: UserFilter): Promise<UserListResult>;\n updateUser(id: string, data: UpdateUserInput): Promise<User>;\n deleteUser(id: string): Promise<void>;\n assignRole(userId: string, roleId: string): Promise<void>;\n removeRole(userId: string, roleId: string): Promise<void>;\n getUserRoles(userId: string): Promise<Role[]>;\n can(userId: string, action: PermissionAction, resource: PermissionResource, resourceId?: string): Promise<boolean>;\n canAny(userId: string, permissions: Array<{ action: PermissionAction; resource: PermissionResource }>): Promise<boolean>;\n requirePermission(userId: string, action: PermissionAction, resource: PermissionResource, resourceId?: string): Promise<void>;\n isAdmin(userId: string): Promise<boolean>;\n}\n\nexport interface AuditManager {\n log(entry: CreateAuditLogInput): Promise<AuditLog>;\n list(filter?: AuditLogFilter): Promise<AuditLogListResult>;\n getByResource(resource: string, resourceId: string): Promise<AuditLog[]>;\n getByUser(userId: string, filter?: AuditLogFilter): Promise<AuditLogListResult>;\n export(filter: AuditLogFilter, format: 'json' | 'csv'): Promise<string>;\n purge(olderThanDays?: number): Promise<number>;\n getSummary(tenantId?: string, days?: number): Promise<AuditSummary>;\n}\n\nexport interface ScheduleManager {\n get(id: string): Promise<ScheduledTask | null>;\n list(filter?: ScheduledTaskFilter): Promise<ScheduledTaskListResult>;\n create(data: CreateScheduledTaskInput): Promise<ScheduledTask>;\n update(id: string, data: UpdateScheduledTaskInput): Promise<ScheduledTask>;\n delete(id: string): Promise<void>;\n pause(id: string): Promise<ScheduledTask>;\n resume(id: string): Promise<ScheduledTask>;\n runNow(id: string): Promise<TaskExecution>;\n getUpcoming(hours: number): Promise<ScheduledTask[]>;\n getExecutions(taskId: string, limit?: number): Promise<TaskExecution[]>;\n calculateNextRun(schedule: TaskSchedule): Date | null;\n}\n\nexport interface MessageQueueManager {\n enqueue(message: EnqueueMessageInput): Promise<QueuedMessage>;\n enqueueBatch(messages: EnqueueMessageInput[]): Promise<QueuedMessage[]>;\n dequeue(deviceId: string, limit?: number): Promise<QueuedMessage[]>;\n acknowledge(messageId: string): Promise<void>;\n fail(messageId: string, error: string): Promise<void>;\n retryFailed(maxAttempts?: number): Promise<number>;\n purgeExpired(): Promise<number>;\n getStats(tenantId?: string): Promise<QueueStats>;\n peek(deviceId: string, limit?: number): Promise<QueuedMessage[]>;\n}\n\nexport interface DashboardManager {\n getStats(tenantId?: string): Promise<DashboardStats>;\n getDeviceStatusBreakdown(tenantId?: string): Promise<DeviceStatusBreakdown>;\n getEnrollmentTrend(days: number, tenantId?: string): Promise<EnrollmentTrendPoint[]>;\n getCommandSuccessRates(tenantId?: string): Promise<CommandSuccessRates>;\n getAppInstallationSummary(tenantId?: string): Promise<AppInstallationSummary>;\n}\n\n// ============================================\n// Event Handler Types\n// ============================================\n\nexport type EventHandler<T extends EventType> = (\n event: MDMEvent<EventPayloadMap[T]>\n) => Promise<void> | void;\n\nexport interface EventPayloadMap {\n 'device.enrolled': { device: Device };\n 'device.unenrolled': { device: Device; reason?: string };\n 'device.blocked': { device: Device; reason: string };\n 'device.heartbeat': { device: Device; heartbeat: Heartbeat };\n 'device.locationUpdated': { device: Device; location: DeviceLocation };\n 'device.statusChanged': { device: Device; oldStatus: DeviceStatus; newStatus: DeviceStatus };\n 'device.policyChanged': { device: Device; oldPolicyId?: string; newPolicyId?: string };\n 'app.installed': { device: Device; app: InstalledApp };\n 'app.uninstalled': { device: Device; packageName: string };\n 'app.updated': { device: Device; app: InstalledApp; oldVersion: string };\n 'app.crashed': { device: Device; packageName: string; error?: string };\n 'app.started': { device: Device; packageName: string };\n 'app.stopped': { device: Device; packageName: string };\n 'policy.applied': { device: Device; policy: Policy };\n 'policy.failed': { device: Device; policy: Policy; error: string };\n 'command.received': { device: Device; command: Command };\n 'command.acknowledged': { device: Device; command: Command };\n 'command.completed': { device: Device; command: Command; result: CommandResult };\n 'command.failed': { device: Device; command: Command; error: string };\n 'security.tamper': { device: Device; type: string; details?: unknown };\n 'security.rootDetected': { device: Device };\n 'security.screenLocked': { device: Device };\n 'security.screenUnlocked': { device: Device };\n custom: Record<string, unknown>;\n}\n\n// ============================================\n// Error Types\n// ============================================\n\nexport class MDMError extends Error {\n constructor(\n message: string,\n public code: string,\n public statusCode: number = 500,\n public details?: unknown\n ) {\n super(message);\n this.name = 'MDMError';\n }\n}\n\nexport class DeviceNotFoundError extends MDMError {\n constructor(deviceId: string) {\n super(`Device not found: ${deviceId}`, 'DEVICE_NOT_FOUND', 404);\n }\n}\n\nexport class PolicyNotFoundError extends MDMError {\n constructor(policyId: string) {\n super(`Policy not found: ${policyId}`, 'POLICY_NOT_FOUND', 404);\n }\n}\n\nexport class ApplicationNotFoundError extends MDMError {\n constructor(identifier: string) {\n super(`Application not found: ${identifier}`, 'APPLICATION_NOT_FOUND', 404);\n }\n}\n\nexport class CommandNotFoundError extends MDMError {\n constructor(commandId: string) {\n super(`Command not found: ${commandId}`, 'COMMAND_NOT_FOUND', 404);\n }\n}\n\nexport class TenantNotFoundError extends MDMError {\n constructor(identifier: string) {\n super(`Tenant not found: ${identifier}`, 'TENANT_NOT_FOUND', 404);\n }\n}\n\nexport class RoleNotFoundError extends MDMError {\n constructor(identifier: string) {\n super(`Role not found: ${identifier}`, 'ROLE_NOT_FOUND', 404);\n }\n}\n\nexport class GroupNotFoundError extends MDMError {\n constructor(identifier: string) {\n super(`Group not found: ${identifier}`, 'GROUP_NOT_FOUND', 404);\n }\n}\n\nexport class UserNotFoundError extends MDMError {\n constructor(identifier: string) {\n super(`User not found: ${identifier}`, 'USER_NOT_FOUND', 404);\n }\n}\n\nexport class EnrollmentError extends MDMError {\n constructor(message: string, details?: unknown) {\n super(message, 'ENROLLMENT_ERROR', 400, details);\n }\n}\n\nexport class AuthenticationError extends MDMError {\n constructor(message: string = 'Authentication required') {\n super(message, 'AUTHENTICATION_ERROR', 401);\n }\n}\n\nexport class AuthorizationError extends MDMError {\n constructor(message: string = 'Access denied') {\n super(message, 'AUTHORIZATION_ERROR', 403);\n }\n}\n\nexport class ValidationError extends MDMError {\n constructor(message: string, details?: unknown) {\n super(message, 'VALIDATION_ERROR', 400, details);\n }\n}\n","/**\n * OpenMDM Logger\n *\n * Default logger implementations and helpers. Production users are\n * expected to pass their own pino/winston/bunyan instance via\n * `createMDM({ logger })`; these defaults are for development and\n * for the zero-config path.\n */\n\nimport type { Logger, LogContext } from './types';\n\n/**\n * Resolve (context, message) or (message) argument forms into a\n * single shape. Matches the pino call convention used by the Logger\n * interface.\n */\nfunction normalize(\n ...args: [LogContext, string] | [string]\n): { context: LogContext | undefined; message: string } {\n if (args.length === 1) {\n return { context: undefined, message: args[0] };\n }\n return { context: args[0], message: args[1] };\n}\n\n/**\n * Console-backed logger. Writes JSON-ish lines to stdout/stderr with\n * an `[openmdm]` prefix so they stand out in a mixed-log stream.\n *\n * This is the zero-config default — it intentionally does the\n * minimum viable thing. Hosts running in production should replace\n * it with a real structured logger.\n */\nexport function createConsoleLogger(scope: string[] = []): Logger {\n const prefix = scope.length > 0 ? `[openmdm:${scope.join(':')}]` : '[openmdm]';\n\n const render = (context: LogContext | undefined): string => {\n if (!context || Object.keys(context).length === 0) return '';\n // Keep single-line to remain friendly to `grep`. JSON.stringify is\n // the cheapest structured-output format that every production\n // logger can consume as-is.\n try {\n return ' ' + JSON.stringify(context);\n } catch {\n // Fall back to a string cast when the context has a circular\n // reference — losing structure is better than crashing the call\n // site.\n return ' ' + String(context);\n }\n };\n\n return {\n debug: (...args: [LogContext, string] | [string]) => {\n const { context, message } = normalize(...args);\n // Debug is off by default when no DEBUG env var is set — keeps\n // the dev experience quiet unless someone opts in.\n if (!process.env.DEBUG) return;\n console.debug(`${prefix} ${message}${render(context)}`);\n },\n info: (...args: [LogContext, string] | [string]) => {\n const { context, message } = normalize(...args);\n console.log(`${prefix} ${message}${render(context)}`);\n },\n warn: (...args: [LogContext, string] | [string]) => {\n const { context, message } = normalize(...args);\n console.warn(`${prefix} ${message}${render(context)}`);\n },\n error: (...args: [LogContext, string] | [string]) => {\n const { context, message } = normalize(...args);\n console.error(`${prefix} ${message}${render(context)}`);\n },\n child: (bindings: LogContext): Logger => {\n // Console logger's `child` extends the scope with any\n // `component` field if provided, otherwise appends nothing\n // meaningful and just returns a new logger with the same\n // scope. Real loggers (pino) properly attach bindings to every\n // subsequent call — we do the simplest thing that won't lie.\n const componentPart =\n typeof bindings.component === 'string' ? [bindings.component] : [];\n return createConsoleLogger([...scope, ...componentPart]);\n },\n };\n}\n\n/**\n * No-op logger. Use to silence OpenMDM entirely — e.g. in tests or in\n * environments where log noise is inappropriate.\n */\nexport function createSilentLogger(): Logger {\n const silent: Logger = {\n debug: () => undefined,\n info: () => undefined,\n warn: () => undefined,\n error: () => undefined,\n child: () => silent,\n };\n return silent;\n}\n","/**\n * OpenMDM Webhook Delivery System\n *\n * Handles outbound webhook delivery with HMAC signing and retry logic.\n */\n\nimport { createHmac, randomUUID } from 'crypto';\nimport type {\n WebhookConfig,\n WebhookEndpoint,\n EventType,\n MDMEvent,\n Logger,\n} from './types';\nimport { createSilentLogger } from './logger';\n\n// ============================================\n// Types\n// ============================================\n\nexport interface WebhookDeliveryResult {\n endpointId: string;\n success: boolean;\n statusCode?: number;\n error?: string;\n retryCount: number;\n deliveredAt?: Date;\n}\n\nexport interface WebhookPayload<T = unknown> {\n id: string;\n event: EventType;\n timestamp: string;\n data: T;\n}\n\nexport interface WebhookManager {\n /**\n * Deliver an event to all matching webhook endpoints\n */\n deliver<T>(event: MDMEvent<T>): Promise<WebhookDeliveryResult[]>;\n\n /**\n * Add a webhook endpoint at runtime\n */\n addEndpoint(endpoint: WebhookEndpoint): void;\n\n /**\n * Remove a webhook endpoint\n */\n removeEndpoint(endpointId: string): void;\n\n /**\n * Update a webhook endpoint\n */\n updateEndpoint(endpointId: string, updates: Partial<WebhookEndpoint>): void;\n\n /**\n * Get all configured endpoints\n */\n getEndpoints(): WebhookEndpoint[];\n\n /**\n * Test a webhook endpoint with a test payload\n */\n testEndpoint(endpointId: string): Promise<WebhookDeliveryResult>;\n}\n\n// ============================================\n// Implementation\n// ============================================\n\nconst DEFAULT_RETRY_CONFIG = {\n maxRetries: 3,\n initialDelay: 1000,\n maxDelay: 30000,\n};\n\n/**\n * Create a webhook manager instance\n */\nexport function createWebhookManager(\n config: WebhookConfig,\n logger: Logger = createSilentLogger(),\n): WebhookManager {\n const endpoints = new Map<string, WebhookEndpoint>();\n const retryConfig = { ...DEFAULT_RETRY_CONFIG, ...config.retry };\n const log = logger.child({ component: 'webhooks' });\n\n // Initialize with configured endpoints\n if (config.endpoints) {\n for (const endpoint of config.endpoints) {\n endpoints.set(endpoint.id, endpoint);\n }\n }\n\n /**\n * Sign a webhook payload with HMAC-SHA256\n */\n function signPayload(payload: string, secret: string): string {\n return createHmac('sha256', secret).update(payload).digest('hex');\n }\n\n /**\n * Calculate exponential backoff delay\n */\n function getBackoffDelay(retryCount: number): number {\n const delay = retryConfig.initialDelay * Math.pow(2, retryCount);\n return Math.min(delay, retryConfig.maxDelay);\n }\n\n /**\n * Check if an endpoint should receive this event\n */\n function shouldDeliverToEndpoint(\n endpoint: WebhookEndpoint,\n eventType: EventType\n ): boolean {\n if (!endpoint.enabled) {\n return false;\n }\n\n // Wildcard matches all events\n if (endpoint.events.includes('*')) {\n return true;\n }\n\n return endpoint.events.includes(eventType);\n }\n\n /**\n * Deliver payload to a single endpoint with retry logic\n */\n async function deliverToEndpoint(\n endpoint: WebhookEndpoint,\n payload: WebhookPayload\n ): Promise<WebhookDeliveryResult> {\n const payloadString = JSON.stringify(payload);\n let lastError: string | undefined;\n let lastStatusCode: number | undefined;\n\n for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {\n try {\n // Prepare headers\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-OpenMDM-Event': payload.event,\n 'X-OpenMDM-Delivery': payload.id,\n 'X-OpenMDM-Timestamp': payload.timestamp,\n ...endpoint.headers,\n };\n\n // Add signature if signing secret is configured\n if (config.signingSecret) {\n const signature = signPayload(payloadString, config.signingSecret);\n headers['X-OpenMDM-Signature'] = `sha256=${signature}`;\n }\n\n // Make the request\n const response = await fetch(endpoint.url, {\n method: 'POST',\n headers,\n body: payloadString,\n signal: AbortSignal.timeout(30000), // 30 second timeout\n });\n\n lastStatusCode = response.status;\n\n // 2xx is success\n if (response.ok) {\n return {\n endpointId: endpoint.id,\n success: true,\n statusCode: response.status,\n retryCount: attempt,\n deliveredAt: new Date(),\n };\n }\n\n // 4xx errors (except 429) should not be retried\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n return {\n endpointId: endpoint.id,\n success: false,\n statusCode: response.status,\n error: `HTTP ${response.status}: ${response.statusText}`,\n retryCount: attempt,\n };\n }\n\n // 5xx and 429 should be retried\n lastError = `HTTP ${response.status}: ${response.statusText}`;\n } catch (error) {\n lastError = error instanceof Error ? error.message : String(error);\n }\n\n // Wait before retry (unless this was the last attempt)\n if (attempt < retryConfig.maxRetries) {\n const delay = getBackoffDelay(attempt);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n return {\n endpointId: endpoint.id,\n success: false,\n statusCode: lastStatusCode,\n error: lastError || 'Max retries exceeded',\n retryCount: retryConfig.maxRetries,\n };\n }\n\n return {\n async deliver<T>(event: MDMEvent<T>): Promise<WebhookDeliveryResult[]> {\n const matchingEndpoints = Array.from(endpoints.values()).filter((ep) =>\n shouldDeliverToEndpoint(ep, event.type)\n );\n\n if (matchingEndpoints.length === 0) {\n return [];\n }\n\n // Prepare webhook payload\n const payload: WebhookPayload<T> = {\n id: randomUUID(),\n event: event.type,\n timestamp: new Date().toISOString(),\n data: event.payload,\n };\n\n // Deliver to all matching endpoints in parallel\n const deliveryPromises = matchingEndpoints.map((endpoint) =>\n deliverToEndpoint(endpoint, payload as WebhookPayload)\n );\n\n const results = await Promise.all(deliveryPromises);\n\n // Log failures\n for (const result of results) {\n if (!result.success) {\n log.error(\n {\n endpointId: result.endpointId,\n statusCode: result.statusCode,\n retryCount: result.retryCount,\n err: result.error,\n },\n 'Webhook delivery failed',\n );\n }\n }\n\n return results;\n },\n\n addEndpoint(endpoint: WebhookEndpoint): void {\n endpoints.set(endpoint.id, endpoint);\n },\n\n removeEndpoint(endpointId: string): void {\n endpoints.delete(endpointId);\n },\n\n updateEndpoint(endpointId: string, updates: Partial<WebhookEndpoint>): void {\n const existing = endpoints.get(endpointId);\n if (existing) {\n endpoints.set(endpointId, { ...existing, ...updates });\n }\n },\n\n getEndpoints(): WebhookEndpoint[] {\n return Array.from(endpoints.values());\n },\n\n async testEndpoint(endpointId: string): Promise<WebhookDeliveryResult> {\n const endpoint = endpoints.get(endpointId);\n if (!endpoint) {\n return {\n endpointId,\n success: false,\n error: 'Endpoint not found',\n retryCount: 0,\n };\n }\n\n const testPayload: WebhookPayload = {\n id: randomUUID(),\n event: 'device.heartbeat',\n timestamp: new Date().toISOString(),\n data: {\n test: true,\n message: 'OpenMDM webhook test',\n },\n };\n\n return deliverToEndpoint(endpoint, testPayload);\n },\n };\n}\n\n/**\n * Verify a webhook signature from incoming requests\n * (Utility for consumers to verify our webhooks)\n */\nexport function verifyWebhookSignature(\n payload: string,\n signature: string,\n secret: string\n): boolean {\n const expectedSignature = `sha256=${createHmac('sha256', secret)\n .update(payload)\n .digest('hex')}`;\n\n // Constant-time comparison\n if (signature.length !== expectedSignature.length) {\n return false;\n }\n\n let result = 0;\n for (let i = 0; i < signature.length; i++) {\n result |= signature.charCodeAt(i) ^ expectedSignature.charCodeAt(i);\n }\n\n return result === 0;\n}\n","/**\n * OpenMDM Tenant Manager\n *\n * Provides multi-tenancy support for the MDM system.\n * Enables organization isolation, tenant management, and resource quotas.\n */\n\nimport type {\n Tenant,\n TenantManager,\n TenantFilter,\n TenantListResult,\n TenantStats,\n CreateTenantInput,\n UpdateTenantInput,\n DatabaseAdapter,\n} from './types';\nimport { TenantNotFoundError, ValidationError } from './types';\n\n/**\n * Generate a unique ID for entities\n */\nfunction generateId(): string {\n return crypto.randomUUID();\n}\n\n/**\n * Validate tenant slug format\n */\nfunction validateSlug(slug: string): boolean {\n // Slug must be lowercase alphanumeric with hyphens, 3-50 chars\n const slugRegex = /^[a-z0-9][a-z0-9-]{1,48}[a-z0-9]$/;\n return slugRegex.test(slug);\n}\n\n/**\n * Create a TenantManager instance\n */\nexport function createTenantManager(db: DatabaseAdapter): TenantManager {\n return {\n async get(id: string): Promise<Tenant | null> {\n if (!db.findTenant) {\n throw new Error('Database adapter does not support tenant operations');\n }\n return db.findTenant(id);\n },\n\n async getBySlug(slug: string): Promise<Tenant | null> {\n if (!db.findTenantBySlug) {\n throw new Error('Database adapter does not support tenant operations');\n }\n return db.findTenantBySlug(slug);\n },\n\n async list(filter?: TenantFilter): Promise<TenantListResult> {\n if (!db.listTenants) {\n throw new Error('Database adapter does not support tenant operations');\n }\n return db.listTenants(filter);\n },\n\n async create(data: CreateTenantInput): Promise<Tenant> {\n if (!db.createTenant || !db.findTenantBySlug) {\n throw new Error('Database adapter does not support tenant operations');\n }\n\n // Validate slug format\n if (!validateSlug(data.slug)) {\n throw new ValidationError(\n 'Invalid slug format. Must be 3-50 lowercase alphanumeric characters with hyphens.',\n { slug: data.slug }\n );\n }\n\n // Check for duplicate slug\n const existing = await db.findTenantBySlug(data.slug);\n if (existing) {\n throw new ValidationError(`Tenant with slug '${data.slug}' already exists`, {\n slug: data.slug,\n });\n }\n\n return db.createTenant({\n ...data,\n slug: data.slug.toLowerCase(),\n });\n },\n\n async update(id: string, data: UpdateTenantInput): Promise<Tenant> {\n if (!db.updateTenant || !db.findTenant || !db.findTenantBySlug) {\n throw new Error('Database adapter does not support tenant operations');\n }\n\n const tenant = await db.findTenant(id);\n if (!tenant) {\n throw new TenantNotFoundError(id);\n }\n\n // Validate new slug if provided\n if (data.slug) {\n if (!validateSlug(data.slug)) {\n throw new ValidationError(\n 'Invalid slug format. Must be 3-50 lowercase alphanumeric characters with hyphens.',\n { slug: data.slug }\n );\n }\n\n // Check for duplicate slug\n const existing = await db.findTenantBySlug(data.slug);\n if (existing && existing.id !== id) {\n throw new ValidationError(`Tenant with slug '${data.slug}' already exists`, {\n slug: data.slug,\n });\n }\n\n data.slug = data.slug.toLowerCase();\n }\n\n return db.updateTenant(id, data);\n },\n\n async delete(id: string, cascade: boolean = false): Promise<void> {\n if (!db.deleteTenant || !db.findTenant) {\n throw new Error('Database adapter does not support tenant operations');\n }\n\n const tenant = await db.findTenant(id);\n if (!tenant) {\n throw new TenantNotFoundError(id);\n }\n\n // If cascade is true, the database adapter should handle\n // deletion of all related resources (devices, policies, etc.)\n // This is typically done via ON DELETE CASCADE in the schema\n\n await db.deleteTenant(id);\n },\n\n async getStats(tenantId: string): Promise<TenantStats> {\n if (!db.getTenantStats || !db.findTenant) {\n throw new Error('Database adapter does not support tenant operations');\n }\n\n const tenant = await db.findTenant(tenantId);\n if (!tenant) {\n throw new TenantNotFoundError(tenantId);\n }\n\n return db.getTenantStats(tenantId);\n },\n\n async activate(id: string): Promise<Tenant> {\n if (!db.updateTenant || !db.findTenant) {\n throw new Error('Database adapter does not support tenant operations');\n }\n\n const tenant = await db.findTenant(id);\n if (!tenant) {\n throw new TenantNotFoundError(id);\n }\n\n if (tenant.status === 'active') {\n return tenant;\n }\n\n return db.updateTenant(id, { status: 'active' });\n },\n\n async deactivate(id: string): Promise<Tenant> {\n if (!db.updateTenant || !db.findTenant) {\n throw new Error('Database adapter does not support tenant operations');\n }\n\n const tenant = await db.findTenant(id);\n if (!tenant) {\n throw new TenantNotFoundError(id);\n }\n\n if (tenant.status === 'suspended') {\n return tenant;\n }\n\n return db.updateTenant(id, { status: 'suspended' });\n },\n };\n}\n\n/**\n * Default system roles that can be used across tenants\n */\nexport const DEFAULT_SYSTEM_ROLES = {\n SUPER_ADMIN: {\n name: 'Super Admin',\n description: 'Full system access across all tenants',\n permissions: [{ action: '*' as const, resource: '*' as const }],\n isSystem: true,\n },\n TENANT_ADMIN: {\n name: 'Tenant Admin',\n description: 'Full access within the tenant',\n permissions: [\n { action: 'manage' as const, resource: 'devices' as const },\n { action: 'manage' as const, resource: 'policies' as const },\n { action: 'manage' as const, resource: 'applications' as const },\n { action: 'manage' as const, resource: 'commands' as const },\n { action: 'manage' as const, resource: 'groups' as const },\n { action: 'manage' as const, resource: 'users' as const },\n { action: 'read' as const, resource: 'audit' as const },\n ],\n isSystem: true,\n },\n DEVICE_MANAGER: {\n name: 'Device Manager',\n description: 'Manage devices and send commands',\n permissions: [\n { action: 'manage' as const, resource: 'devices' as const },\n { action: 'manage' as const, resource: 'commands' as const },\n { action: 'read' as const, resource: 'policies' as const },\n { action: 'read' as const, resource: 'groups' as const },\n ],\n isSystem: true,\n },\n VIEWER: {\n name: 'Viewer',\n description: 'Read-only access to all resources',\n permissions: [\n { action: 'read' as const, resource: 'devices' as const },\n { action: 'read' as const, resource: 'policies' as const },\n { action: 'read' as const, resource: 'applications' as const },\n { action: 'read' as const, resource: 'commands' as const },\n { action: 'read' as const, resource: 'groups' as const },\n ],\n isSystem: true,\n },\n};\n\nexport type SystemRoleName = keyof typeof DEFAULT_SYSTEM_ROLES;\n","/**\n * OpenMDM Authorization Manager\n *\n * Provides Role-Based Access Control (RBAC) for the MDM system.\n * Enables fine-grained permission management for users and resources.\n */\n\nimport type {\n Role,\n User,\n UserWithRoles,\n Permission,\n PermissionAction,\n PermissionResource,\n AuthorizationManager,\n CreateRoleInput,\n UpdateRoleInput,\n CreateUserInput,\n UpdateUserInput,\n UserFilter,\n UserListResult,\n DatabaseAdapter,\n} from './types';\nimport {\n UserNotFoundError,\n RoleNotFoundError,\n AuthorizationError,\n ValidationError,\n} from './types';\n\n/**\n * Check if an action matches the required action\n */\nfunction actionMatches(required: PermissionAction, granted: PermissionAction): boolean {\n if (granted === '*') return true;\n if (granted === 'manage') {\n // 'manage' implies all CRUD operations\n return ['create', 'read', 'update', 'delete', 'manage'].includes(required);\n }\n return required === granted;\n}\n\n/**\n * Check if a resource matches the required resource\n */\nfunction resourceMatches(required: PermissionResource, granted: PermissionResource): boolean {\n if (granted === '*') return true;\n return required === granted;\n}\n\n/**\n * Check if a permission matches the required permission\n */\nfunction permissionMatches(\n required: { action: PermissionAction; resource: PermissionResource },\n granted: Permission\n): boolean {\n return (\n actionMatches(required.action, granted.action) &&\n resourceMatches(required.resource, granted.resource)\n );\n}\n\n/**\n * Check if any permission in the list grants the required access\n */\nfunction hasPermission(\n permissions: Permission[],\n action: PermissionAction,\n resource: PermissionResource\n): boolean {\n return permissions.some((p) => permissionMatches({ action, resource }, p));\n}\n\n/**\n * Check if user has admin permissions (full access)\n */\nfunction isAdminPermission(permissions: Permission[]): boolean {\n return permissions.some(\n (p) => p.action === '*' && p.resource === '*'\n );\n}\n\n/**\n * Validate email format\n */\nfunction validateEmail(email: string): boolean {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailRegex.test(email);\n}\n\n/**\n * Create an AuthorizationManager instance\n */\nexport function createAuthorizationManager(db: DatabaseAdapter): AuthorizationManager {\n /**\n * Get all permissions for a user from all their roles\n */\n async function getAllUserPermissions(userId: string): Promise<Permission[]> {\n if (!db.getUserRoles) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const roles = await db.getUserRoles(userId);\n const permissions: Permission[] = [];\n\n for (const role of roles) {\n permissions.push(...role.permissions);\n }\n\n return permissions;\n }\n\n return {\n // ========================================\n // Role Management\n // ========================================\n\n async createRole(data: CreateRoleInput): Promise<Role> {\n if (!db.createRole) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n // Validate permissions array\n if (!data.permissions || !Array.isArray(data.permissions)) {\n throw new ValidationError('Permissions must be an array');\n }\n\n for (const permission of data.permissions) {\n if (!permission.action || !permission.resource) {\n throw new ValidationError('Each permission must have action and resource');\n }\n }\n\n return db.createRole(data);\n },\n\n async getRole(id: string): Promise<Role | null> {\n if (!db.findRole) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n return db.findRole(id);\n },\n\n async listRoles(tenantId?: string): Promise<Role[]> {\n if (!db.listRoles) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n return db.listRoles(tenantId);\n },\n\n async updateRole(id: string, data: UpdateRoleInput): Promise<Role> {\n if (!db.updateRole || !db.findRole) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const role = await db.findRole(id);\n if (!role) {\n throw new RoleNotFoundError(id);\n }\n\n // Cannot update system roles\n if (role.isSystem) {\n throw new AuthorizationError('Cannot modify system roles');\n }\n\n // Validate permissions if provided\n if (data.permissions) {\n if (!Array.isArray(data.permissions)) {\n throw new ValidationError('Permissions must be an array');\n }\n\n for (const permission of data.permissions) {\n if (!permission.action || !permission.resource) {\n throw new ValidationError('Each permission must have action and resource');\n }\n }\n }\n\n return db.updateRole(id, data);\n },\n\n async deleteRole(id: string): Promise<void> {\n if (!db.deleteRole || !db.findRole) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const role = await db.findRole(id);\n if (!role) {\n throw new RoleNotFoundError(id);\n }\n\n // Cannot delete system roles\n if (role.isSystem) {\n throw new AuthorizationError('Cannot delete system roles');\n }\n\n await db.deleteRole(id);\n },\n\n // ========================================\n // User Management\n // ========================================\n\n async createUser(data: CreateUserInput): Promise<User> {\n if (!db.createUser || !db.findUserByEmail) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n // Validate email\n if (!validateEmail(data.email)) {\n throw new ValidationError('Invalid email format', { email: data.email });\n }\n\n // Check for duplicate email within tenant\n const existing = await db.findUserByEmail(data.email, data.tenantId);\n if (existing) {\n throw new ValidationError(`User with email '${data.email}' already exists`, {\n email: data.email,\n });\n }\n\n return db.createUser({\n ...data,\n email: data.email.toLowerCase(),\n });\n },\n\n async getUser(id: string): Promise<UserWithRoles | null> {\n if (!db.findUser || !db.getUserRoles) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(id);\n if (!user) return null;\n\n const roles = await db.getUserRoles(id);\n return { ...user, roles };\n },\n\n async getUserByEmail(email: string, tenantId?: string): Promise<UserWithRoles | null> {\n if (!db.findUserByEmail || !db.getUserRoles) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUserByEmail(email.toLowerCase(), tenantId);\n if (!user) return null;\n\n const roles = await db.getUserRoles(user.id);\n return { ...user, roles };\n },\n\n async listUsers(filter?: UserFilter): Promise<UserListResult> {\n if (!db.listUsers) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n return db.listUsers(filter);\n },\n\n async updateUser(id: string, data: UpdateUserInput): Promise<User> {\n if (!db.updateUser || !db.findUser) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(id);\n if (!user) {\n throw new UserNotFoundError(id);\n }\n\n // Validate email if provided\n if (data.email) {\n if (!validateEmail(data.email)) {\n throw new ValidationError('Invalid email format', { email: data.email });\n }\n data.email = data.email.toLowerCase();\n }\n\n return db.updateUser(id, data);\n },\n\n async deleteUser(id: string): Promise<void> {\n if (!db.deleteUser || !db.findUser) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(id);\n if (!user) {\n throw new UserNotFoundError(id);\n }\n\n await db.deleteUser(id);\n },\n\n // ========================================\n // Role Assignment\n // ========================================\n\n async assignRole(userId: string, roleId: string): Promise<void> {\n if (!db.assignRoleToUser || !db.findUser || !db.findRole) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(userId);\n if (!user) {\n throw new UserNotFoundError(userId);\n }\n\n const role = await db.findRole(roleId);\n if (!role) {\n throw new RoleNotFoundError(roleId);\n }\n\n // Verify tenant compatibility\n if (role.tenantId && user.tenantId && role.tenantId !== user.tenantId) {\n throw new AuthorizationError('Role belongs to a different tenant');\n }\n\n await db.assignRoleToUser(userId, roleId);\n },\n\n async removeRole(userId: string, roleId: string): Promise<void> {\n if (!db.removeRoleFromUser || !db.findUser) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(userId);\n if (!user) {\n throw new UserNotFoundError(userId);\n }\n\n await db.removeRoleFromUser(userId, roleId);\n },\n\n async getUserRoles(userId: string): Promise<Role[]> {\n if (!db.getUserRoles || !db.findUser) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(userId);\n if (!user) {\n throw new UserNotFoundError(userId);\n }\n\n return db.getUserRoles(userId);\n },\n\n // ========================================\n // Permission Checking\n // ========================================\n\n async can(\n userId: string,\n action: PermissionAction,\n resource: PermissionResource,\n _resourceId?: string\n ): Promise<boolean> {\n if (!db.findUser) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(userId);\n if (!user) return false;\n\n // Inactive users have no permissions\n if (user.status !== 'active') return false;\n\n const permissions = await getAllUserPermissions(userId);\n return hasPermission(permissions, action, resource);\n },\n\n async requirePermission(\n userId: string,\n action: PermissionAction,\n resource: PermissionResource,\n resourceId?: string\n ): Promise<void> {\n const allowed = await this.can(userId, action, resource, resourceId);\n if (!allowed) {\n throw new AuthorizationError(\n `Permission denied: ${action} on ${resource}${resourceId ? ` (${resourceId})` : ''}`\n );\n }\n },\n\n async canAny(\n userId: string,\n permissions: Array<{ action: PermissionAction; resource: PermissionResource }>\n ): Promise<boolean> {\n if (!db.findUser) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(userId);\n if (!user) return false;\n\n // Inactive users have no permissions\n if (user.status !== 'active') return false;\n\n const userPermissions = await getAllUserPermissions(userId);\n\n return permissions.some((required) =>\n hasPermission(userPermissions, required.action, required.resource)\n );\n },\n\n async isAdmin(userId: string): Promise<boolean> {\n if (!db.findUser) {\n throw new Error('Database adapter does not support RBAC operations');\n }\n\n const user = await db.findUser(userId);\n if (!user || user.status !== 'active') return false;\n\n const permissions = await getAllUserPermissions(userId);\n return isAdminPermission(permissions);\n },\n };\n}\n","/**\n * OpenMDM Audit Manager\n *\n * Provides audit logging for compliance and tracking.\n * Records all significant operations for security auditing.\n */\n\nimport type {\n AuditLog,\n AuditAction,\n AuditManager,\n AuditSummary,\n CreateAuditLogInput,\n AuditLogFilter,\n AuditLogListResult,\n DatabaseAdapter,\n AuditConfig,\n} from './types';\n\n/**\n * Default audit retention in days\n */\nconst DEFAULT_RETENTION_DAYS = 90;\n\n/**\n * Convert audit log to CSV row\n */\nfunction auditLogToCsvRow(log: AuditLog): string {\n const fields = [\n log.id,\n log.tenantId || '',\n log.userId || '',\n log.action,\n log.resource,\n log.resourceId || '',\n log.status,\n log.ipAddress || '',\n log.userAgent || '',\n log.error || '',\n log.createdAt.toISOString(),\n JSON.stringify(log.details || {}),\n ];\n return fields.map((f) => `\"${String(f).replace(/\"/g, '\"\"')}\"`).join(',');\n}\n\n/**\n * CSV header for audit log export\n */\nconst CSV_HEADER =\n 'id,tenant_id,user_id,action,resource,resource_id,status,ip_address,user_agent,error,created_at,details';\n\n/**\n * Create an AuditManager instance\n */\nexport function createAuditManager(\n db: DatabaseAdapter,\n config?: AuditConfig\n): AuditManager {\n const retentionDays = config?.retentionDays ?? DEFAULT_RETENTION_DAYS;\n\n /**\n * Check if an action should be logged based on configuration\n */\n function shouldLog(action: AuditAction, resource: string): boolean {\n if (!config?.enabled) return false;\n\n // Skip read operations if configured\n if (config.skipReadOperations && action === 'read') {\n return false;\n }\n\n // Check action filter\n if (config.logActions && config.logActions.length > 0) {\n if (!config.logActions.includes(action)) {\n return false;\n }\n }\n\n // Check resource filter\n if (config.logResources && config.logResources.length > 0) {\n if (!config.logResources.includes(resource)) {\n return false;\n }\n }\n\n return true;\n }\n\n return {\n async log(entry: CreateAuditLogInput): Promise<AuditLog> {\n if (!db.createAuditLog) {\n throw new Error('Database adapter does not support audit operations');\n }\n\n // Check if we should log this action\n if (config && !shouldLog(entry.action, entry.resource)) {\n // Return a stub audit log without persisting\n return {\n id: 'skipped',\n ...entry,\n createdAt: new Date(),\n } as AuditLog;\n }\n\n return db.createAuditLog(entry);\n },\n\n async list(filter?: AuditLogFilter): Promise<AuditLogListResult> {\n if (!db.listAuditLogs) {\n throw new Error('Database adapter does not support audit operations');\n }\n return db.listAuditLogs(filter);\n },\n\n async getByResource(resource: string, resourceId: string): Promise<AuditLog[]> {\n if (!db.listAuditLogs) {\n throw new Error('Database adapter does not support audit operations');\n }\n\n const result = await db.listAuditLogs({\n resource,\n resourceId,\n limit: 1000, // Reasonable limit for resource-specific queries\n });\n\n return result.logs;\n },\n\n async getByUser(\n userId: string,\n filter?: Omit<AuditLogFilter, 'userId'>\n ): Promise<AuditLogListResult> {\n if (!db.listAuditLogs) {\n throw new Error('Database adapter does not support audit operations');\n }\n\n return db.listAuditLogs({\n ...filter,\n userId,\n });\n },\n\n async export(filter: AuditLogFilter, format: 'csv' | 'json'): Promise<string> {\n if (!db.listAuditLogs) {\n throw new Error('Database adapter does not support audit operations');\n }\n\n // Fetch all matching logs (with a reasonable limit)\n const allLogs: AuditLog[] = [];\n let offset = 0;\n const batchSize = 1000;\n\n while (true) {\n const result = await db.listAuditLogs({\n ...filter,\n limit: batchSize,\n offset,\n });\n\n allLogs.push(...result.logs);\n\n if (result.logs.length < batchSize || allLogs.length >= 100000) {\n break;\n }\n\n offset += batchSize;\n }\n\n if (format === 'json') {\n return JSON.stringify(allLogs, null, 2);\n }\n\n // CSV format\n const rows = allLogs.map(auditLogToCsvRow);\n return [CSV_HEADER, ...rows].join('\\n');\n },\n\n async purge(olderThanDays?: number): Promise<number> {\n if (!db.deleteAuditLogs) {\n throw new Error('Database adapter does not support audit operations');\n }\n\n const days = olderThanDays ?? retentionDays;\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - days);\n\n return db.deleteAuditLogs({ olderThan: cutoffDate });\n },\n\n async getSummary(tenantId?: string, days: number = 30): Promise<AuditSummary> {\n if (!db.listAuditLogs) {\n throw new Error('Database adapter does not support audit operations');\n }\n\n const startDate = new Date();\n startDate.setDate(startDate.getDate() - days);\n\n // Fetch logs for the period\n const result = await db.listAuditLogs({\n tenantId,\n startDate,\n limit: 10000, // Reasonable limit for summary\n });\n\n const logs = result.logs;\n\n // Calculate summary statistics\n const byAction: Record<AuditAction, number> = {} as Record<AuditAction, number>;\n const byResource: Record<string, number> = {};\n const byStatus = { success: 0, failure: 0 };\n const userCounts: Record<string, number> = {};\n const recentFailures: AuditLog[] = [];\n\n for (const log of logs) {\n // By action\n byAction[log.action] = (byAction[log.action] || 0) + 1;\n\n // By resource\n byResource[log.resource] = (byResource[log.resource] || 0) + 1;\n\n // By status\n byStatus[log.status]++;\n\n // By user\n if (log.userId) {\n userCounts[log.userId] = (userCounts[log.userId] || 0) + 1;\n }\n\n // Collect failures\n if (log.status === 'failure' && recentFailures.length < 10) {\n recentFailures.push(log);\n }\n }\n\n // Get top users\n const topUsers = Object.entries(userCounts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n .map(([userId, count]) => ({ userId, count }));\n\n return {\n totalLogs: result.total,\n byAction,\n byResource,\n byStatus,\n topUsers,\n recentFailures,\n };\n },\n };\n}\n\n/**\n * Helper function to create audit log entries with common fields\n */\nexport function createAuditEntry(\n action: AuditAction,\n resource: string,\n options: {\n resourceId?: string;\n tenantId?: string;\n userId?: string;\n details?: Record<string, unknown>;\n ipAddress?: string;\n userAgent?: string;\n status?: 'success' | 'failure';\n error?: string;\n } = {}\n): CreateAuditLogInput {\n return {\n action,\n resource,\n resourceId: options.resourceId,\n tenantId: options.tenantId,\n userId: options.userId,\n details: options.details,\n ipAddress: options.ipAddress,\n userAgent: options.userAgent,\n status: options.status ?? 'success',\n error: options.error,\n };\n}\n\n/**\n * Audit decorator for wrapping async functions with audit logging\n */\nexport function withAudit<T extends (...args: unknown[]) => Promise<unknown>>(\n manager: AuditManager,\n action: AuditAction,\n resource: string,\n getContext: (...args: Parameters<T>) => Partial<CreateAuditLogInput>\n) {\n return function decorator(target: T): T {\n return (async (...args: Parameters<T>) => {\n const context = getContext(...args);\n try {\n const result = await target(...args);\n await manager.log({\n action,\n resource,\n status: 'success',\n ...context,\n });\n return result;\n } catch (error) {\n await manager.log({\n action,\n resource,\n status: 'failure',\n error: error instanceof Error ? error.message : String(error),\n ...context,\n });\n throw error;\n }\n }) as T;\n };\n}\n","/**\n * OpenMDM Schedule Manager\n *\n * Provides scheduled task management for the MDM system.\n * Enables scheduling of recurring operations, maintenance windows, and one-time tasks.\n */\n\nimport type {\n ScheduleManager,\n ScheduledTask,\n ScheduledTaskFilter,\n ScheduledTaskListResult,\n CreateScheduledTaskInput,\n UpdateScheduledTaskInput,\n TaskSchedule,\n TaskExecution,\n DatabaseAdapter,\n} from './types';\n\n/**\n * Parse cron expression and calculate next run time\n * Supports: minute hour dayOfMonth month dayOfWeek\n */\nfunction parseCronNextRun(cron: string, from: Date = new Date()): Date | null {\n try {\n const parts = cron.trim().split(/\\s+/);\n if (parts.length !== 5) return null;\n\n const [minute, hour, dayOfMonth, month, dayOfWeek] = parts;\n\n // Simple cron parsing - handles basic patterns\n const now = new Date(from);\n const next = new Date(now);\n\n // Start from the next minute\n next.setSeconds(0);\n next.setMilliseconds(0);\n next.setMinutes(next.getMinutes() + 1);\n\n // Try to find next valid time (up to 1 year)\n const maxIterations = 365 * 24 * 60; // 1 year in minutes\n for (let i = 0; i < maxIterations; i++) {\n const matches =\n matchesCronField(minute, next.getMinutes()) &&\n matchesCronField(hour, next.getHours()) &&\n matchesCronField(dayOfMonth, next.getDate()) &&\n matchesCronField(month, next.getMonth() + 1) &&\n matchesCronField(dayOfWeek, next.getDay());\n\n if (matches) {\n return next;\n }\n\n next.setMinutes(next.getMinutes() + 1);\n }\n\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Check if a value matches a cron field pattern\n */\nfunction matchesCronField(pattern: string, value: number): boolean {\n if (pattern === '*') return true;\n\n // Handle step values: */5, */15, etc.\n if (pattern.startsWith('*/')) {\n const step = parseInt(pattern.slice(2), 10);\n return value % step === 0;\n }\n\n // Handle ranges: 1-5\n if (pattern.includes('-')) {\n const [start, end] = pattern.split('-').map((n) => parseInt(n, 10));\n return value >= start && value <= end;\n }\n\n // Handle lists: 1,3,5\n if (pattern.includes(',')) {\n const values = pattern.split(',').map((n) => parseInt(n, 10));\n return values.includes(value);\n }\n\n // Simple number\n return parseInt(pattern, 10) === value;\n}\n\n/**\n * Check if current time is within a maintenance window\n */\nfunction isInMaintenanceWindow(\n window: TaskSchedule['window'],\n now: Date = new Date()\n): boolean {\n if (!window) return false;\n\n const dayOfWeek = now.getDay();\n if (!window.daysOfWeek.includes(dayOfWeek)) return false;\n\n // Parse times\n const [startHour, startMin] = window.startTime.split(':').map(Number);\n const [endHour, endMin] = window.endTime.split(':').map(Number);\n\n const currentMinutes = now.getHours() * 60 + now.getMinutes();\n const startMinutes = startHour * 60 + startMin;\n const endMinutes = endHour * 60 + endMin;\n\n // Handle overnight windows\n if (endMinutes < startMinutes) {\n return currentMinutes >= startMinutes || currentMinutes < endMinutes;\n }\n\n return currentMinutes >= startMinutes && currentMinutes < endMinutes;\n}\n\n/**\n * Calculate next run time for a maintenance window\n */\nfunction calculateNextWindowRun(\n window: TaskSchedule['window'],\n from: Date = new Date()\n): Date | null {\n if (!window) return null;\n\n const [startHour, startMin] = window.startTime.split(':').map(Number);\n\n // Try each day for the next 7 days\n for (let dayOffset = 0; dayOffset <= 7; dayOffset++) {\n const candidate = new Date(from);\n candidate.setDate(candidate.getDate() + dayOffset);\n candidate.setHours(startHour, startMin, 0, 0);\n\n // Skip if in the past\n if (candidate <= from) continue;\n\n // Check if day matches\n if (window.daysOfWeek.includes(candidate.getDay())) {\n return candidate;\n }\n }\n\n return null;\n}\n\n/**\n * Create a ScheduleManager instance\n */\nexport function createScheduleManager(db: DatabaseAdapter): ScheduleManager {\n /**\n * Calculate the next run time for a schedule\n */\n function calculateNextRun(schedule: TaskSchedule): Date | null {\n const now = new Date();\n\n switch (schedule.type) {\n case 'once':\n // For one-time tasks, return the scheduled time if it's in the future\n if (schedule.executeAt && new Date(schedule.executeAt) > now) {\n return new Date(schedule.executeAt);\n }\n return null;\n\n case 'recurring':\n // Parse cron expression\n if (schedule.cron) {\n return parseCronNextRun(schedule.cron, now);\n }\n return null;\n\n case 'window':\n // Calculate next maintenance window start\n if (schedule.window) {\n return calculateNextWindowRun(schedule.window, now);\n }\n return null;\n\n default:\n return null;\n }\n }\n\n return {\n async get(id: string): Promise<ScheduledTask | null> {\n if (!db.findScheduledTask) {\n throw new Error('Database adapter does not support task scheduling');\n }\n return db.findScheduledTask(id);\n },\n\n async list(filter?: ScheduledTaskFilter): Promise<ScheduledTaskListResult> {\n if (!db.listScheduledTasks) {\n throw new Error('Database adapter does not support task scheduling');\n }\n return db.listScheduledTasks(filter);\n },\n\n async create(data: CreateScheduledTaskInput): Promise<ScheduledTask> {\n if (!db.createScheduledTask) {\n throw new Error('Database adapter does not support task scheduling');\n }\n\n // Calculate initial next run time\n const nextRunAt = calculateNextRun(data.schedule);\n\n // Create task with calculated next run\n const task = await db.createScheduledTask({\n ...data,\n // Note: nextRunAt is set by the database adapter based on schedule\n });\n\n // Update next run time if needed\n if (nextRunAt && db.updateScheduledTask) {\n return db.updateScheduledTask(task.id, {\n ...data,\n });\n }\n\n return task;\n },\n\n async update(id: string, data: UpdateScheduledTaskInput): Promise<ScheduledTask> {\n if (!db.updateScheduledTask || !db.findScheduledTask) {\n throw new Error('Database adapter does not support task scheduling');\n }\n\n const existing = await db.findScheduledTask(id);\n if (!existing) {\n throw new Error(`Scheduled task not found: ${id}`);\n }\n\n return db.updateScheduledTask(id, data);\n },\n\n async delete(id: string): Promise<void> {\n if (!db.deleteScheduledTask) {\n throw new Error('Database adapter does not support task scheduling');\n }\n await db.deleteScheduledTask(id);\n },\n\n async pause(id: string): Promise<ScheduledTask> {\n if (!db.updateScheduledTask || !db.findScheduledTask) {\n throw new Error('Database adapter does not support task scheduling');\n }\n\n const task = await db.findScheduledTask(id);\n if (!task) {\n throw new Error(`Scheduled task not found: ${id}`);\n }\n\n if (task.status === 'paused') {\n return task;\n }\n\n return db.updateScheduledTask(id, { status: 'paused' });\n },\n\n async resume(id: string): Promise<ScheduledTask> {\n if (!db.updateScheduledTask || !db.findScheduledTask) {\n throw new Error('Database adapter does not support task scheduling');\n }\n\n const task = await db.findScheduledTask(id);\n if (!task) {\n throw new Error(`Scheduled task not found: ${id}`);\n }\n\n if (task.status !== 'paused') {\n return task;\n }\n\n // Recalculate next run time\n const nextRunAt = calculateNextRun(task.schedule);\n\n return db.updateScheduledTask(id, { status: 'active' });\n },\n\n async runNow(id: string): Promise<TaskExecution> {\n if (\n !db.findScheduledTask ||\n !db.createTaskExecution ||\n !db.updateScheduledTask\n ) {\n throw new Error('Database adapter does not support task scheduling');\n }\n\n const task = await db.findScheduledTask(id);\n if (!task) {\n throw new Error(`Scheduled task not found: ${id}`);\n }\n\n // Create execution record\n const execution = await db.createTaskExecution({ taskId: id });\n\n // Update task last run time\n await db.updateScheduledTask(id, {});\n\n return execution;\n },\n\n async getUpcoming(hours: number): Promise<ScheduledTask[]> {\n if (!db.getUpcomingTasks) {\n throw new Error('Database adapter does not support task scheduling');\n }\n return db.getUpcomingTasks(hours);\n },\n\n async getExecutions(taskId: string, limit: number = 10): Promise<TaskExecution[]> {\n if (!db.listTaskExecutions) {\n throw new Error('Database adapter does not support task scheduling');\n }\n return db.listTaskExecutions(taskId, limit);\n },\n\n calculateNextRun,\n };\n}\n\n/**\n * Export utility functions\n */\nexport { parseCronNextRun, isInMaintenanceWindow, calculateNextWindowRun };\n","/**\n * OpenMDM Message Queue Manager\n *\n * Provides persistent message queue management for the MDM system.\n * Ensures reliable message delivery with retry and expiration handling.\n */\n\nimport type {\n MessageQueueManager,\n QueuedMessage,\n EnqueueMessageInput,\n QueueStats,\n DatabaseAdapter,\n} from './types';\n\n/**\n * Default maximum attempts for message delivery\n */\nconst DEFAULT_MAX_ATTEMPTS = 3;\n\n/**\n * Default TTL in seconds (24 hours)\n */\nconst DEFAULT_TTL_SECONDS = 86400;\n\n/**\n * Create a MessageQueueManager instance\n */\nexport function createMessageQueueManager(db: DatabaseAdapter): MessageQueueManager {\n return {\n async enqueue(message: EnqueueMessageInput): Promise<QueuedMessage> {\n if (!db.enqueueMessage) {\n throw new Error('Database adapter does not support message queue');\n }\n\n // Set defaults\n const enrichedMessage: EnqueueMessageInput = {\n ...message,\n priority: message.priority ?? 'normal',\n maxAttempts: message.maxAttempts ?? DEFAULT_MAX_ATTEMPTS,\n ttlSeconds: message.ttlSeconds ?? DEFAULT_TTL_SECONDS,\n };\n\n return db.enqueueMessage(enrichedMessage);\n },\n\n async enqueueBatch(messages: EnqueueMessageInput[]): Promise<QueuedMessage[]> {\n if (!db.enqueueMessage) {\n throw new Error('Database adapter does not support message queue');\n }\n\n const results: QueuedMessage[] = [];\n\n for (const message of messages) {\n const enrichedMessage: EnqueueMessageInput = {\n ...message,\n priority: message.priority ?? 'normal',\n maxAttempts: message.maxAttempts ?? DEFAULT_MAX_ATTEMPTS,\n ttlSeconds: message.ttlSeconds ?? DEFAULT_TTL_SECONDS,\n };\n\n const queued = await db.enqueueMessage(enrichedMessage);\n results.push(queued);\n }\n\n return results;\n },\n\n async dequeue(deviceId: string, limit: number = 10): Promise<QueuedMessage[]> {\n if (!db.dequeueMessages) {\n throw new Error('Database adapter does not support message queue');\n }\n return db.dequeueMessages(deviceId, limit);\n },\n\n async acknowledge(messageId: string): Promise<void> {\n if (!db.acknowledgeMessage) {\n throw new Error('Database adapter does not support message queue');\n }\n await db.acknowledgeMessage(messageId);\n },\n\n async fail(messageId: string, error: string): Promise<void> {\n if (!db.failMessage) {\n throw new Error('Database adapter does not support message queue');\n }\n await db.failMessage(messageId, error);\n },\n\n async retryFailed(maxAttempts: number = DEFAULT_MAX_ATTEMPTS): Promise<number> {\n if (!db.retryFailedMessages) {\n throw new Error('Database adapter does not support message queue');\n }\n return db.retryFailedMessages(maxAttempts);\n },\n\n async purgeExpired(): Promise<number> {\n if (!db.purgeExpiredMessages) {\n throw new Error('Database adapter does not support message queue');\n }\n return db.purgeExpiredMessages();\n },\n\n async getStats(tenantId?: string): Promise<QueueStats> {\n if (!db.getQueueStats) {\n throw new Error('Database adapter does not support message queue');\n }\n return db.getQueueStats(tenantId);\n },\n\n async peek(deviceId: string, limit: number = 10): Promise<QueuedMessage[]> {\n if (!db.peekMessages) {\n throw new Error('Database adapter does not support message queue');\n }\n return db.peekMessages(deviceId, limit);\n },\n };\n}\n\n/**\n * Message priority weights for sorting\n */\nexport const PRIORITY_WEIGHTS = {\n high: 3,\n normal: 2,\n low: 1,\n} as const;\n\n/**\n * Compare messages by priority (higher priority first)\n */\nexport function compareByPriority(a: QueuedMessage, b: QueuedMessage): number {\n return PRIORITY_WEIGHTS[b.priority] - PRIORITY_WEIGHTS[a.priority];\n}\n\n/**\n * Check if a message has expired\n */\nexport function isMessageExpired(message: QueuedMessage): boolean {\n if (!message.expiresAt) return false;\n return new Date(message.expiresAt) < new Date();\n}\n\n/**\n * Check if a message can be retried\n */\nexport function canRetryMessage(message: QueuedMessage): boolean {\n return message.status === 'failed' && message.attempts < message.maxAttempts;\n}\n\n/**\n * Calculate exponential backoff delay for retries\n */\nexport function calculateBackoffDelay(\n attempts: number,\n baseDelayMs: number = 1000,\n maxDelayMs: number = 300000 // 5 minutes\n): number {\n const delay = baseDelayMs * Math.pow(2, attempts - 1);\n return Math.min(delay, maxDelayMs);\n}\n","/**\n * OpenMDM Dashboard Manager\n *\n * Provides analytics and statistics for the MDM dashboard.\n * Aggregates data from devices, commands, and applications.\n */\n\nimport type {\n DashboardManager,\n DashboardStats,\n DeviceStatusBreakdown,\n EnrollmentTrendPoint,\n CommandSuccessRates,\n AppInstallationSummary,\n DatabaseAdapter,\n DeviceStatus,\n} from './types';\n\n/**\n * Throws if a tenantId is supplied to a dashboard method whose\n * database adapter does not implement the tenant-scoped version.\n *\n * The old behavior — silently ignoring the tenantId and returning\n * global stats — was a data-leak footgun in multi-tenant deployments.\n * We would rather fail loudly than return fleet-wide numbers to a\n * caller who thought they were asking about one tenant.\n *\n * The audit recommended this as a backstop until core resources gain\n * a real `tenantId` column. Once that lands, this guard becomes\n * redundant — the fallback paths will be able to filter themselves.\n */\nfunction assertNoTenantScopeRequested(\n tenantId: string | undefined,\n method: string,\n): void {\n if (tenantId) {\n throw new Error(\n `DashboardManager.${method} was called with a tenantId but the ` +\n 'database adapter does not implement tenant-scoped dashboard ' +\n 'queries. Implement the matching DatabaseAdapter method, or omit ' +\n 'tenantId to accept global stats. See ' +\n 'docs/proposals/tenant-rbac-audit.md for context.',\n );\n }\n}\n\n/**\n * Create a DashboardManager instance\n */\nexport function createDashboardManager(db: DatabaseAdapter): DashboardManager {\n return {\n async getStats(_tenantId?: string): Promise<DashboardStats> {\n // Use database method if available\n if (db.getDashboardStats) {\n return db.getDashboardStats(_tenantId);\n }\n\n // No tenant-scoped path available in the fallback. Refuse\n // rather than silently returning global stats.\n assertNoTenantScopeRequested(_tenantId, 'getStats');\n\n // Fallback: compute from individual queries\n const devices = await db.listDevices({\n limit: 10000, // Get all for counting\n });\n\n const deviceStats = {\n total: devices.total,\n enrolled: devices.devices.filter((d) => d.status === 'enrolled').length,\n active: devices.devices.filter((d) => d.status === 'enrolled').length, // 'active' = 'enrolled' for dashboard\n blocked: devices.devices.filter((d) => d.status === 'blocked').length,\n pending: devices.devices.filter((d) => d.status === 'pending').length,\n };\n\n const allPolicies = await db.listPolicies();\n const policyStats = {\n total: allPolicies.length,\n deployed: allPolicies.filter((p) => p.isDefault).length,\n };\n\n const allApps = await db.listApplications();\n const appStats = {\n total: allApps.length,\n deployed: allApps.length, // All apps in db are considered deployed\n };\n\n // Command stats - get recent commands\n const now = new Date();\n const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);\n const allCommands = await db.listCommands({ limit: 10000 });\n\n const pendingCommands = allCommands.filter((c) => c.status === 'pending');\n const last24hCommands = allCommands.filter(\n (c) => new Date(c.createdAt) >= yesterday\n );\n\n const commandStats = {\n pendingCount: pendingCommands.length,\n last24hTotal: last24hCommands.length,\n last24hSuccess: last24hCommands.filter((c) => c.status === 'completed').length,\n last24hFailed: last24hCommands.filter((c) => c.status === 'failed').length,\n };\n\n // Group stats\n const allGroups = await db.listGroups();\n let groupsWithDevices = 0;\n for (const group of allGroups) {\n const groupDevices = await db.listDevicesInGroup(group.id);\n if (groupDevices.length > 0) groupsWithDevices++;\n }\n\n return {\n devices: deviceStats,\n policies: policyStats,\n applications: appStats,\n commands: commandStats,\n groups: {\n total: allGroups.length,\n withDevices: groupsWithDevices,\n },\n };\n },\n\n async getDeviceStatusBreakdown(_tenantId?: string): Promise<DeviceStatusBreakdown> {\n if (db.getDeviceStatusBreakdown) {\n return db.getDeviceStatusBreakdown(_tenantId);\n }\n\n assertNoTenantScopeRequested(_tenantId, 'getDeviceStatusBreakdown');\n\n const devices = await db.listDevices({\n limit: 10000,\n });\n\n const byStatus: Record<DeviceStatus, number> = {\n pending: 0,\n enrolled: 0,\n blocked: 0,\n unenrolled: 0,\n };\n\n const byOs: Record<string, number> = {};\n const byManufacturer: Record<string, number> = {};\n const byModel: Record<string, number> = {};\n\n for (const device of devices.devices) {\n // By status\n byStatus[device.status]++;\n\n // By OS version\n const osKey = device.osVersion || 'Unknown';\n byOs[osKey] = (byOs[osKey] || 0) + 1;\n\n // By manufacturer\n const mfr = device.manufacturer || 'Unknown';\n byManufacturer[mfr] = (byManufacturer[mfr] || 0) + 1;\n\n // By model\n const model = device.model || 'Unknown';\n byModel[model] = (byModel[model] || 0) + 1;\n }\n\n return {\n byStatus,\n byOs,\n byManufacturer,\n byModel,\n };\n },\n\n async getEnrollmentTrend(days: number, _tenantId?: string): Promise<EnrollmentTrendPoint[]> {\n if (db.getEnrollmentTrend) {\n return db.getEnrollmentTrend(days, _tenantId);\n }\n\n assertNoTenantScopeRequested(_tenantId, 'getEnrollmentTrend');\n\n // Generate trend data from event history\n const now = new Date();\n const startDate = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);\n\n // Get enrollment events\n const events = await db.listEvents({\n type: 'device.enrolled',\n startDate,\n limit: 10000,\n });\n\n const unenrollEvents = await db.listEvents({\n type: 'device.unenrolled',\n startDate,\n limit: 10000,\n });\n\n // Group by date\n const trendByDate = new Map<string, { enrolled: number; unenrolled: number }>();\n\n // Initialize all dates\n for (let i = 0; i < days; i++) {\n const date = new Date(startDate.getTime() + i * 24 * 60 * 60 * 1000);\n const dateKey = date.toISOString().split('T')[0];\n trendByDate.set(dateKey, { enrolled: 0, unenrolled: 0 });\n }\n\n // Count events\n for (const event of events) {\n const dateKey = new Date(event.createdAt).toISOString().split('T')[0];\n const entry = trendByDate.get(dateKey);\n if (entry) {\n entry.enrolled++;\n }\n }\n\n for (const event of unenrollEvents) {\n const dateKey = new Date(event.createdAt).toISOString().split('T')[0];\n const entry = trendByDate.get(dateKey);\n if (entry) {\n entry.unenrolled++;\n }\n }\n\n // Get initial device count\n const initialDevices = await db.listDevices({\n limit: 10000,\n });\n let runningTotal = initialDevices.total;\n\n // Build trend points\n const result: EnrollmentTrendPoint[] = [];\n const sortedDates = Array.from(trendByDate.keys()).sort();\n\n for (const dateKey of sortedDates) {\n const entry = trendByDate.get(dateKey)!;\n const netChange = entry.enrolled - entry.unenrolled;\n runningTotal += netChange;\n\n result.push({\n date: new Date(dateKey),\n enrolled: entry.enrolled,\n unenrolled: entry.unenrolled,\n netChange,\n totalDevices: runningTotal,\n });\n }\n\n return result;\n },\n\n async getCommandSuccessRates(_tenantId?: string): Promise<CommandSuccessRates> {\n if (db.getCommandSuccessRates) {\n return db.getCommandSuccessRates(_tenantId);\n }\n\n assertNoTenantScopeRequested(_tenantId, 'getCommandSuccessRates');\n\n const now = new Date();\n const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);\n\n const commands = await db.listCommands({ limit: 10000 });\n\n // Overall stats\n const completed = commands.filter((c) => c.status === 'completed').length;\n const failed = commands.filter((c) => c.status === 'failed').length;\n const total = commands.length;\n\n // By type\n const byType: CommandSuccessRates['byType'] = {};\n for (const cmd of commands) {\n if (!byType[cmd.type]) {\n byType[cmd.type] = {\n total: 0,\n completed: 0,\n failed: 0,\n successRate: 0,\n };\n }\n byType[cmd.type].total++;\n if (cmd.status === 'completed') byType[cmd.type].completed++;\n if (cmd.status === 'failed') byType[cmd.type].failed++;\n }\n\n // Calculate success rates\n for (const type of Object.keys(byType)) {\n const stats = byType[type];\n const finishedCount = stats.completed + stats.failed;\n stats.successRate = finishedCount > 0 ? (stats.completed / finishedCount) * 100 : 0;\n }\n\n // Last 24h\n const last24hCommands = commands.filter(\n (c) => new Date(c.createdAt) >= yesterday\n );\n\n return {\n overall: {\n total,\n completed,\n failed,\n successRate:\n completed + failed > 0 ? (completed / (completed + failed)) * 100 : 0,\n },\n byType,\n last24h: {\n total: last24hCommands.length,\n completed: last24hCommands.filter((c) => c.status === 'completed').length,\n failed: last24hCommands.filter((c) => c.status === 'failed').length,\n pending: last24hCommands.filter((c) => c.status === 'pending').length,\n },\n };\n },\n\n async getAppInstallationSummary(_tenantId?: string): Promise<AppInstallationSummary> {\n if (db.getAppInstallationSummary) {\n return db.getAppInstallationSummary(_tenantId);\n }\n\n assertNoTenantScopeRequested(_tenantId, 'getAppInstallationSummary');\n\n // Get all apps\n const apps = await db.listApplications();\n const appMap = new Map(apps.map((a) => [a.packageName, a]));\n\n // Get installation statuses if available\n const byStatus: Record<string, number> = {\n installed: 0,\n installing: 0,\n failed: 0,\n pending: 0,\n };\n\n // Count installed apps per device\n const installCounts: Record<string, number> = {};\n\n // Get devices to count installations\n const devices = await db.listDevices({\n limit: 10000,\n });\n\n for (const device of devices.devices) {\n if (device.installedApps) {\n for (const app of device.installedApps) {\n const key = app.packageName;\n installCounts[key] = (installCounts[key] || 0) + 1;\n byStatus['installed']++;\n }\n }\n }\n\n // Top installed apps\n const topInstalled = Object.entries(installCounts)\n .sort(([, a], [, b]) => b - a)\n .slice(0, 10)\n .map(([packageName, count]) => ({\n packageName,\n name: appMap.get(packageName)?.name || packageName,\n installedCount: count,\n }));\n\n return {\n total: Object.values(byStatus).reduce((a, b) => a + b, 0),\n byStatus,\n recentFailures: [], // Would need installation status tracking\n topInstalled,\n };\n },\n };\n}\n","/**\n * OpenMDM Plugin Storage Manager\n *\n * Provides persistent storage for plugin state.\n * Supports both database-backed and in-memory storage.\n */\n\nimport type { PluginStorageAdapter, DatabaseAdapter } from './types';\n\n/**\n * Create a PluginStorageAdapter backed by the database\n */\nexport function createPluginStorageAdapter(db: DatabaseAdapter): PluginStorageAdapter {\n return {\n async get<T>(pluginName: string, key: string): Promise<T | null> {\n if (db.getPluginValue) {\n const value = await db.getPluginValue(pluginName, key);\n return value as T | null;\n }\n\n // Fallback: not supported\n // Silently no-op: the plugin-storage contract treats missing\n // adapter methods as \"not configured\", which is the same\n // branch plugins handle via their in-memory fallback. A warn\n // log here would flood production with one line per hit.\n //\n return null;\n },\n\n async set<T>(pluginName: string, key: string, value: T): Promise<void> {\n if (db.setPluginValue) {\n await db.setPluginValue(pluginName, key, value);\n return;\n }\n\n // Silently no-op: the plugin-storage contract treats missing\n // adapter methods as \"not configured\", which is the same\n // branch plugins handle via their in-memory fallback. A warn\n // log here would flood production with one line per hit.\n //\n },\n\n async delete(pluginName: string, key: string): Promise<void> {\n if (db.deletePluginValue) {\n await db.deletePluginValue(pluginName, key);\n return;\n }\n\n // Silently no-op: the plugin-storage contract treats missing\n // adapter methods as \"not configured\", which is the same\n // branch plugins handle via their in-memory fallback. A warn\n // log here would flood production with one line per hit.\n //\n },\n\n async list(pluginName: string, prefix?: string): Promise<string[]> {\n if (db.listPluginKeys) {\n return db.listPluginKeys(pluginName, prefix);\n }\n\n // Silently no-op: the plugin-storage contract treats missing\n // adapter methods as \"not configured\", which is the same\n // branch plugins handle via their in-memory fallback. A warn\n // log here would flood production with one line per hit.\n //\n return [];\n },\n\n async clear(pluginName: string): Promise<void> {\n if (db.clearPluginData) {\n await db.clearPluginData(pluginName);\n return;\n }\n\n // Silently no-op: the plugin-storage contract treats missing\n // adapter methods as \"not configured\", which is the same\n // branch plugins handle via their in-memory fallback. A warn\n // log here would flood production with one line per hit.\n //\n },\n };\n}\n\n/**\n * Create an in-memory PluginStorageAdapter for testing\n */\nexport function createMemoryPluginStorageAdapter(): PluginStorageAdapter {\n const store = new Map<string, Map<string, unknown>>();\n\n function getPluginStore(pluginName: string): Map<string, unknown> {\n if (!store.has(pluginName)) {\n store.set(pluginName, new Map());\n }\n return store.get(pluginName)!;\n }\n\n return {\n async get<T>(pluginName: string, key: string): Promise<T | null> {\n const pluginStore = getPluginStore(pluginName);\n const value = pluginStore.get(key);\n return value === undefined ? null : (value as T);\n },\n\n async set<T>(pluginName: string, key: string, value: T): Promise<void> {\n const pluginStore = getPluginStore(pluginName);\n pluginStore.set(key, value);\n },\n\n async delete(pluginName: string, key: string): Promise<void> {\n const pluginStore = getPluginStore(pluginName);\n pluginStore.delete(key);\n },\n\n async list(pluginName: string, prefix?: string): Promise<string[]> {\n const pluginStore = getPluginStore(pluginName);\n const keys = Array.from(pluginStore.keys());\n\n if (prefix) {\n return keys.filter((k) => k.startsWith(prefix));\n }\n\n return keys;\n },\n\n async clear(pluginName: string): Promise<void> {\n store.delete(pluginName);\n },\n };\n}\n\n/**\n * Plugin storage utilities\n */\n\n/**\n * Create a namespaced key for plugin storage\n */\nexport function createPluginKey(namespace: string, ...parts: string[]): string {\n return [namespace, ...parts].join(':');\n}\n\n/**\n * Parse a namespaced key\n */\nexport function parsePluginKey(key: string): { namespace: string; parts: string[] } {\n const [namespace, ...parts] = key.split(':');\n return { namespace, parts };\n}\n","/**\n * OpenMDM Device Identity\n *\n * Device-pinned asymmetric identity, using an ECDSA P-256 keypair the\n * device generates in its own Keystore and registers with the server on\n * first enrollment. After pinning, every consumer can verify a signed\n * request against the same pinned public key — no shared HMAC secret,\n * no APK extraction footgun, no dependence on Google hardware\n * attestation (which most non-GMS fleet hardware cannot produce).\n *\n * This module is the reusable primitive. `@openmdm/core` uses it to\n * gate `/agent/enroll` and will use it for `/agent/*` in Phase 2c.\n * External consumers (midiamob's `deviceValidation.ts`, other custom\n * servers) import the same functions to verify requests against the\n * same pinned key — one device identity, many consumers.\n *\n * Why zero dependencies: Node's built-in `node:crypto` supports EC\n * P-256 SPKI import and `crypto.verify('sha256', ...)` over DER-encoded\n * signatures, which is the default format the Android Keystore\n * produces. We deliberately do not pull in `@peculiar/*` or `node-forge`\n * for this primitive — the surface area we need is small enough that\n * the built-in is the right call.\n *\n * @see docs/concepts/enrollment for the full flow\n * @see docs/proposals/phase-2b-rollout for the Android + rollout story\n */\n\nimport { createPublicKey, verify as cryptoVerify, KeyObject } from 'crypto';\nimport type { Device, DeviceIdentityVerification, MDMInstance } from './types';\n\n// ============================================\n// Low-level: imports and signature verification\n// ============================================\n\n/**\n * Import an EC P-256 public key from base64-encoded SubjectPublicKeyInfo\n * (SPKI) bytes — the standard on-wire format the Android Keystore\n * produces when you call `certificate.publicKey.encoded` on a\n * `KeyStore.getCertificate(alias)` result.\n *\n * Throws `InvalidPublicKeyError` on any parse failure. This is a\n * security boundary — we do NOT return `null` on malformed input,\n * because a caller that forgot to handle the null case would silently\n * treat bad keys as \"no key configured\" and fall through to an\n * insecure path.\n */\nexport function importPublicKeyFromSpki(spkiBase64: string): KeyObject {\n let buffer: Buffer;\n try {\n buffer = Buffer.from(spkiBase64, 'base64');\n } catch (err) {\n throw new InvalidPublicKeyError(\n 'Public key is not valid base64',\n err instanceof Error ? err : undefined,\n );\n }\n if (buffer.length === 0) {\n throw new InvalidPublicKeyError('Public key is empty');\n }\n try {\n const key = createPublicKey({\n key: buffer,\n format: 'der',\n type: 'spki',\n });\n const asymmetricKeyType = key.asymmetricKeyType;\n if (asymmetricKeyType !== 'ec') {\n throw new InvalidPublicKeyError(\n `Expected EC key, got ${asymmetricKeyType ?? 'unknown'}`,\n );\n }\n const curve = (key.asymmetricKeyDetails as { namedCurve?: string } | undefined)\n ?.namedCurve;\n if (curve && curve !== 'prime256v1' && curve !== 'P-256') {\n // Node exposes the curve name as `prime256v1` (the OpenSSL spelling)\n // for EC P-256. Accept both for forward-compat but reject anything\n // else loudly — weaker curves should not silently verify.\n throw new InvalidPublicKeyError(\n `Unsupported EC curve: ${curve}. Only P-256 is accepted.`,\n );\n }\n return key;\n } catch (err) {\n if (err instanceof InvalidPublicKeyError) throw err;\n throw new InvalidPublicKeyError(\n 'Failed to parse SPKI public key',\n err instanceof Error ? err : undefined,\n );\n }\n}\n\n/**\n * Verify an ECDSA-P256 signature over a message using a previously-\n * imported or raw SPKI public key.\n *\n * Signature must be DER-encoded — the default Android Keystore\n * produces DER, and `Signature.sign()` on JVM/Kotlin returns DER, so\n * this matches what every reasonable agent sends on the wire.\n *\n * Returns `true` iff the signature is valid. Never throws on a bad\n * signature (that is the whole point of a verify call). Throws only\n * on an invalid public-key encoding, because that indicates a caller\n * bug rather than a forged request.\n */\nexport function verifyEcdsaSignature(\n publicKey: KeyObject | string,\n message: string,\n signatureBase64: string,\n): boolean {\n const key =\n typeof publicKey === 'string' ? importPublicKeyFromSpki(publicKey) : publicKey;\n let signatureBuffer: Buffer;\n try {\n signatureBuffer = Buffer.from(signatureBase64, 'base64');\n } catch {\n return false;\n }\n if (signatureBuffer.length === 0) return false;\n\n try {\n return cryptoVerify('sha256', Buffer.from(message, 'utf8'), key, signatureBuffer);\n } catch {\n // `crypto.verify` throws only on malformed DER, not on wrong\n // signatures. Treat both as \"not verified\" — the caller can tell\n // them apart by checking the public key import path separately.\n return false;\n }\n}\n\n// ============================================\n// Canonical message\n// ============================================\n\n/**\n * Build the canonical message that an enrollment signature covers.\n *\n * Staying in lockstep with `@openmdm/client` and with the Android\n * agent is load-bearing — any change here is a wire break across\n * every enrolled device. The contract test in\n * `packages/core/tests/device-identity.test.ts` guards against drift.\n *\n * Shape (order matters):\n *\n * publicKey |\n * model | manufacturer | osVersion |\n * serialNumber | imei | macAddress | androidId |\n * method | timestamp | challenge\n *\n * The public key is prepended (rather than appended) because it's the\n * field most likely to be the whole point of the message — putting it\n * first makes the signature's intent visible at a glance in logs.\n */\nexport function canonicalEnrollmentMessage(parts: {\n publicKey: string;\n model: string;\n manufacturer: string;\n osVersion: string;\n serialNumber?: string;\n imei?: string;\n macAddress?: string;\n androidId?: string;\n method: string;\n timestamp: string;\n challenge: string;\n}): string {\n return [\n parts.publicKey,\n parts.model,\n parts.manufacturer,\n parts.osVersion,\n parts.serialNumber ?? '',\n parts.imei ?? '',\n parts.macAddress ?? '',\n parts.androidId ?? '',\n parts.method,\n parts.timestamp,\n parts.challenge,\n ].join('|');\n}\n\n/**\n * Build the canonical message that a *post-enrollment* request\n * signature covers. Consumers (openmdm's `/agent/*` routes,\n * midiamob's `deviceValidation.ts`, any custom server) call this\n * with the fields they want committed to the signature.\n *\n * The shape is deliberately narrower than the enrollment form — only\n * the parts every request has in common.\n *\n * deviceId | timestamp | body | nonce\n *\n * `nonce` is optional; pass an empty string when the request does not\n * carry a challenge. Replay protection on non-enrollment traffic is\n * the caller's job — if your server already has a timestamp window\n * check, you don't need a nonce per request.\n */\nexport function canonicalDeviceRequestMessage(parts: {\n deviceId: string;\n timestamp: string;\n body: string;\n nonce?: string;\n}): string {\n return [parts.deviceId, parts.timestamp, parts.body, parts.nonce ?? ''].join('|');\n}\n\n// ============================================\n// High-level: verifyDeviceRequest primitive\n// ============================================\n\n/**\n * Verify a signed request from an enrolled device against the\n * public key pinned on that device's row.\n *\n * This is the primitive every consumer of device-pinned-key identity\n * calls. It performs exactly the checks required to know the request\n * came from the device that originally enrolled, in constant-ish\n * time:\n *\n * 1. Look up the device by id.\n * 2. Confirm the device has a pinned public key (refusing silently\n * if not — a device without a pinned key is still on the legacy\n * HMAC path and cannot be verified here).\n * 3. Verify the ECDSA signature over the provided canonical message.\n *\n * Returns a tagged union so callers can react to the specific failure\n * mode:\n *\n * - `not-found` — the device id doesn't exist. Almost always a bug\n * in the caller, or a stolen/revoked device id.\n * Return 401 to the client.\n * - `no-pinned-key` — the device is still on the HMAC path. Callers\n * should fall through to their legacy verifier\n * (or fail, if the caller has already migrated).\n * - `signature-invalid` — the signature did not verify against the\n * pinned key. Return 401. **Do NOT** re-pin the\n * submitted public key in response to a failure\n * here — that's how re-pinning becomes a hijack.\n */\nexport async function verifyDeviceRequest(opts: {\n mdm: MDMInstance;\n deviceId: string;\n canonicalMessage: string;\n signatureBase64: string;\n}): Promise<DeviceIdentityVerification> {\n const device = await opts.mdm.devices.get(opts.deviceId);\n if (!device) {\n return { ok: false, reason: 'not-found' };\n }\n\n if (!device.publicKey) {\n return { ok: false, reason: 'no-pinned-key', device };\n }\n\n let verified: boolean;\n try {\n verified = verifyEcdsaSignature(\n device.publicKey,\n opts.canonicalMessage,\n opts.signatureBase64,\n );\n } catch (err) {\n // A pinned key that fails to parse is a data-integrity problem,\n // not a forged request. We log it through the mdm logger so\n // operators can see it, then treat the request as unverified.\n opts.mdm.logger\n .child({ component: 'device-identity' })\n .error(\n {\n deviceId: opts.deviceId,\n err: err instanceof Error ? err.message : String(err),\n },\n 'Pinned public key failed to parse',\n );\n return { ok: false, reason: 'signature-invalid', device };\n }\n\n if (!verified) {\n return { ok: false, reason: 'signature-invalid', device };\n }\n\n return { ok: true, device };\n}\n\n// ============================================\n// Errors\n// ============================================\n\n/**\n * Thrown when a submitted public key cannot be parsed. This is a\n * caller-facing error — the device sent something that is not a\n * well-formed SPKI EC P-256 public key.\n */\nexport class InvalidPublicKeyError extends Error {\n readonly code = 'INVALID_PUBLIC_KEY';\n\n constructor(\n message: string,\n public readonly cause?: Error,\n ) {\n super(message);\n this.name = 'InvalidPublicKeyError';\n }\n}\n\n/**\n * Thrown when a device attempts to re-enroll with a public key that\n * does not match the one originally pinned for its enrollment id.\n *\n * This is the core \"device identity continuity\" check. The server\n * will NEVER automatically re-pin on mismatch — rebinding a device\n * identity requires an explicit admin action (future work).\n */\nexport class PublicKeyMismatchError extends Error {\n readonly code = 'PUBLIC_KEY_MISMATCH';\n\n constructor(public readonly deviceId: string) {\n super(\n `Device ${deviceId} is already enrolled with a different pinned public key`,\n );\n this.name = 'PublicKeyMismatchError';\n }\n}\n\n/**\n * Thrown when an enrollment attempts to use a challenge that is\n * missing, expired, or already consumed.\n */\nexport class ChallengeInvalidError extends Error {\n readonly code = 'CHALLENGE_INVALID';\n\n constructor(\n message: string,\n public readonly challenge?: string,\n ) {\n super(message);\n this.name = 'ChallengeInvalidError';\n }\n}\n","/**\n * OpenMDM Database Schema Definition\n *\n * This schema defines the structure for MDM data storage.\n * Database adapters implement this schema for their specific ORM/database.\n *\n * Tables:\n * - mdm_devices: Enrolled devices and their state\n * - mdm_policies: Device policies and configurations\n * - mdm_applications: Registered applications for deployment\n * - mdm_commands: Command queue for device operations\n * - mdm_events: Event log for device activities\n * - mdm_groups: Device grouping for bulk operations\n * - mdm_device_groups: Many-to-many device-group relationships\n * - mdm_push_tokens: FCM/MQTT push notification tokens\n * - mdm_app_deployments: App-to-policy/group deployment mappings\n * - mdm_app_versions: App version history for rollback support\n * - mdm_rollbacks: Rollback operation history and status\n * - mdm_webhook_endpoints: Outbound webhook configuration\n * - mdm_webhook_deliveries: Webhook delivery history\n * - mdm_tenants: Multi-tenant organization isolation\n * - mdm_roles: RBAC role definitions\n * - mdm_users: User accounts for authorization\n * - mdm_user_roles: User-role mapping\n * - mdm_audit_logs: Compliance and audit trail\n * - mdm_scheduled_tasks: Scheduled task definitions\n * - mdm_task_executions: Task execution history\n * - mdm_message_queue: Persistent push message queue\n * - mdm_plugin_storage: Plugin state persistence\n */\n\n// ============================================\n// Schema Column Types\n// ============================================\n\nexport type ColumnType =\n | 'string'\n | 'text'\n | 'integer'\n | 'bigint'\n | 'boolean'\n | 'datetime'\n | 'json'\n | 'enum';\n\nexport interface ColumnDefinition {\n type: ColumnType;\n nullable?: boolean;\n primaryKey?: boolean;\n unique?: boolean;\n default?: unknown;\n enumValues?: string[];\n references?: {\n table: string;\n column: string;\n onDelete?: 'cascade' | 'set null' | 'restrict';\n };\n}\n\nexport interface IndexDefinition {\n columns: string[];\n unique?: boolean;\n name?: string;\n}\n\nexport interface TableDefinition {\n columns: Record<string, ColumnDefinition>;\n indexes?: IndexDefinition[];\n}\n\nexport interface SchemaDefinition {\n tables: Record<string, TableDefinition>;\n}\n\n// ============================================\n// OpenMDM Schema\n// ============================================\n\nexport const mdmSchema: SchemaDefinition = {\n tables: {\n // ----------------------------------------\n // Devices Table\n // ----------------------------------------\n mdm_devices: {\n columns: {\n id: { type: 'string', primaryKey: true },\n external_id: { type: 'string', nullable: true },\n enrollment_id: { type: 'string', unique: true },\n status: {\n type: 'enum',\n enumValues: ['pending', 'enrolled', 'unenrolled', 'blocked'],\n default: 'pending',\n },\n\n // Device Info\n model: { type: 'string', nullable: true },\n manufacturer: { type: 'string', nullable: true },\n os_version: { type: 'string', nullable: true },\n serial_number: { type: 'string', nullable: true },\n imei: { type: 'string', nullable: true },\n mac_address: { type: 'string', nullable: true },\n android_id: { type: 'string', nullable: true },\n\n // MDM State\n policy_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_policies', column: 'id', onDelete: 'set null' },\n },\n agent_version: { type: 'string', nullable: true }, // MDM agent version installed on device\n last_heartbeat: { type: 'datetime', nullable: true },\n last_sync: { type: 'datetime', nullable: true },\n\n // Telemetry (denormalized for quick access)\n battery_level: { type: 'integer', nullable: true },\n storage_used: { type: 'bigint', nullable: true },\n storage_total: { type: 'bigint', nullable: true },\n latitude: { type: 'string', nullable: true }, // Stored as string for precision\n longitude: { type: 'string', nullable: true },\n location_timestamp: { type: 'datetime', nullable: true },\n\n // JSON fields\n installed_apps: { type: 'json', nullable: true },\n tags: { type: 'json', nullable: true },\n metadata: { type: 'json', nullable: true },\n\n // Timestamps\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['enrollment_id'], unique: true },\n { columns: ['status'] },\n { columns: ['policy_id'] },\n { columns: ['last_heartbeat'] },\n { columns: ['mac_address'] },\n { columns: ['serial_number'] },\n ],\n },\n\n // ----------------------------------------\n // Policies Table\n // ----------------------------------------\n mdm_policies: {\n columns: {\n id: { type: 'string', primaryKey: true },\n name: { type: 'string' },\n description: { type: 'text', nullable: true },\n is_default: { type: 'boolean', default: false },\n settings: { type: 'json' },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['name'] },\n { columns: ['is_default'] },\n ],\n },\n\n // ----------------------------------------\n // Applications Table\n // ----------------------------------------\n mdm_applications: {\n columns: {\n id: { type: 'string', primaryKey: true },\n name: { type: 'string' },\n package_name: { type: 'string' },\n version: { type: 'string' },\n version_code: { type: 'integer' },\n url: { type: 'string' },\n hash: { type: 'string', nullable: true }, // SHA-256\n size: { type: 'bigint', nullable: true },\n min_sdk_version: { type: 'integer', nullable: true },\n\n // Deployment settings\n show_icon: { type: 'boolean', default: true },\n run_after_install: { type: 'boolean', default: false },\n run_at_boot: { type: 'boolean', default: false },\n is_system: { type: 'boolean', default: false },\n\n // State\n is_active: { type: 'boolean', default: true },\n\n // Metadata\n metadata: { type: 'json', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['package_name'] },\n { columns: ['package_name', 'version'], unique: true },\n { columns: ['is_active'] },\n ],\n },\n\n // ----------------------------------------\n // Commands Table\n // ----------------------------------------\n mdm_commands: {\n columns: {\n id: { type: 'string', primaryKey: true },\n device_id: {\n type: 'string',\n references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },\n },\n type: { type: 'string' },\n payload: { type: 'json', nullable: true },\n status: {\n type: 'enum',\n enumValues: ['pending', 'sent', 'acknowledged', 'completed', 'failed', 'cancelled'],\n default: 'pending',\n },\n result: { type: 'json', nullable: true },\n error: { type: 'text', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n sent_at: { type: 'datetime', nullable: true },\n acknowledged_at: { type: 'datetime', nullable: true },\n completed_at: { type: 'datetime', nullable: true },\n },\n indexes: [\n { columns: ['device_id'] },\n { columns: ['status'] },\n { columns: ['device_id', 'status'] },\n { columns: ['created_at'] },\n ],\n },\n\n // ----------------------------------------\n // Events Table\n // ----------------------------------------\n mdm_events: {\n columns: {\n id: { type: 'string', primaryKey: true },\n device_id: {\n type: 'string',\n references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },\n },\n type: { type: 'string' },\n payload: { type: 'json' },\n created_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['device_id'] },\n { columns: ['type'] },\n { columns: ['device_id', 'type'] },\n { columns: ['created_at'] },\n ],\n },\n\n // ----------------------------------------\n // Groups Table\n // ----------------------------------------\n mdm_groups: {\n columns: {\n id: { type: 'string', primaryKey: true },\n name: { type: 'string' },\n description: { type: 'text', nullable: true },\n policy_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_policies', column: 'id', onDelete: 'set null' },\n },\n parent_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_groups', column: 'id', onDelete: 'set null' },\n },\n metadata: { type: 'json', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['name'] },\n { columns: ['policy_id'] },\n { columns: ['parent_id'] },\n ],\n },\n\n // ----------------------------------------\n // Device Groups (Many-to-Many)\n // ----------------------------------------\n mdm_device_groups: {\n columns: {\n device_id: {\n type: 'string',\n references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },\n },\n group_id: {\n type: 'string',\n references: { table: 'mdm_groups', column: 'id', onDelete: 'cascade' },\n },\n created_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['device_id', 'group_id'], unique: true },\n { columns: ['group_id'] },\n ],\n },\n\n // ----------------------------------------\n // Push Tokens (for FCM/MQTT registration)\n // ----------------------------------------\n mdm_push_tokens: {\n columns: {\n id: { type: 'string', primaryKey: true },\n device_id: {\n type: 'string',\n references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },\n },\n provider: {\n type: 'enum',\n enumValues: ['fcm', 'mqtt', 'websocket'],\n },\n token: { type: 'string' },\n is_active: { type: 'boolean', default: true },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['device_id'] },\n { columns: ['provider', 'token'], unique: true },\n { columns: ['is_active'] },\n ],\n },\n\n // ----------------------------------------\n // Application Deployments (Which apps go to which policies/groups)\n // ----------------------------------------\n mdm_app_deployments: {\n columns: {\n id: { type: 'string', primaryKey: true },\n application_id: {\n type: 'string',\n references: { table: 'mdm_applications', column: 'id', onDelete: 'cascade' },\n },\n // Target can be policy or group\n target_type: {\n type: 'enum',\n enumValues: ['policy', 'group'],\n },\n target_id: { type: 'string' },\n action: {\n type: 'enum',\n enumValues: ['install', 'update', 'uninstall'],\n default: 'install',\n },\n is_required: { type: 'boolean', default: false },\n created_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['application_id'] },\n { columns: ['target_type', 'target_id'] },\n ],\n },\n\n // ----------------------------------------\n // App Versions (Version history for rollback support)\n // ----------------------------------------\n mdm_app_versions: {\n columns: {\n id: { type: 'string', primaryKey: true },\n application_id: {\n type: 'string',\n references: { table: 'mdm_applications', column: 'id', onDelete: 'cascade' },\n },\n package_name: { type: 'string' },\n version: { type: 'string' },\n version_code: { type: 'integer' },\n url: { type: 'string' },\n hash: { type: 'string', nullable: true },\n size: { type: 'bigint', nullable: true },\n release_notes: { type: 'text', nullable: true },\n is_minimum_version: { type: 'boolean', default: false },\n created_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['application_id'] },\n { columns: ['package_name'] },\n { columns: ['package_name', 'version_code'], unique: true },\n { columns: ['is_minimum_version'] },\n ],\n },\n\n // ----------------------------------------\n // App Rollbacks (Rollback history and status)\n // ----------------------------------------\n mdm_rollbacks: {\n columns: {\n id: { type: 'string', primaryKey: true },\n device_id: {\n type: 'string',\n references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },\n },\n package_name: { type: 'string' },\n from_version: { type: 'string' },\n from_version_code: { type: 'integer' },\n to_version: { type: 'string' },\n to_version_code: { type: 'integer' },\n reason: { type: 'text', nullable: true },\n status: {\n type: 'enum',\n enumValues: ['pending', 'in_progress', 'completed', 'failed'],\n default: 'pending',\n },\n error: { type: 'text', nullable: true },\n initiated_by: { type: 'string', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n completed_at: { type: 'datetime', nullable: true },\n },\n indexes: [\n { columns: ['device_id'] },\n { columns: ['package_name'] },\n { columns: ['device_id', 'package_name'] },\n { columns: ['status'] },\n { columns: ['created_at'] },\n ],\n },\n\n // ----------------------------------------\n // Webhook Endpoints (For outbound webhook configuration storage)\n // ----------------------------------------\n mdm_webhook_endpoints: {\n columns: {\n id: { type: 'string', primaryKey: true },\n url: { type: 'string' },\n events: { type: 'json' }, // Array of event types or ['*']\n headers: { type: 'json', nullable: true },\n enabled: { type: 'boolean', default: true },\n description: { type: 'text', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['enabled'] },\n ],\n },\n\n // ----------------------------------------\n // Webhook Deliveries (Delivery history and status)\n // ----------------------------------------\n mdm_webhook_deliveries: {\n columns: {\n id: { type: 'string', primaryKey: true },\n endpoint_id: {\n type: 'string',\n references: { table: 'mdm_webhook_endpoints', column: 'id', onDelete: 'cascade' },\n },\n event_id: { type: 'string' },\n event_type: { type: 'string' },\n payload: { type: 'json' },\n status: {\n type: 'enum',\n enumValues: ['pending', 'success', 'failed'],\n default: 'pending',\n },\n status_code: { type: 'integer', nullable: true },\n error: { type: 'text', nullable: true },\n retry_count: { type: 'integer', default: 0 },\n created_at: { type: 'datetime', default: 'now' },\n delivered_at: { type: 'datetime', nullable: true },\n },\n indexes: [\n { columns: ['endpoint_id'] },\n { columns: ['event_type'] },\n { columns: ['status'] },\n { columns: ['created_at'] },\n ],\n },\n\n // ----------------------------------------\n // Tenants Table (Multi-tenancy)\n // ----------------------------------------\n mdm_tenants: {\n columns: {\n id: { type: 'string', primaryKey: true },\n name: { type: 'string' },\n slug: { type: 'string', unique: true },\n status: {\n type: 'enum',\n enumValues: ['active', 'suspended', 'pending'],\n default: 'pending',\n },\n settings: { type: 'json', nullable: true },\n metadata: { type: 'json', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['slug'], unique: true },\n { columns: ['status'] },\n ],\n },\n\n // ----------------------------------------\n // Roles Table (RBAC)\n // ----------------------------------------\n mdm_roles: {\n columns: {\n id: { type: 'string', primaryKey: true },\n tenant_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_tenants', column: 'id', onDelete: 'cascade' },\n },\n name: { type: 'string' },\n description: { type: 'text', nullable: true },\n permissions: { type: 'json' },\n is_system: { type: 'boolean', default: false },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['tenant_id'] },\n { columns: ['name'] },\n { columns: ['tenant_id', 'name'], unique: true },\n ],\n },\n\n // ----------------------------------------\n // Users Table (RBAC)\n // ----------------------------------------\n mdm_users: {\n columns: {\n id: { type: 'string', primaryKey: true },\n tenant_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_tenants', column: 'id', onDelete: 'cascade' },\n },\n email: { type: 'string' },\n name: { type: 'string', nullable: true },\n status: {\n type: 'enum',\n enumValues: ['active', 'inactive', 'pending'],\n default: 'pending',\n },\n metadata: { type: 'json', nullable: true },\n last_login_at: { type: 'datetime', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['tenant_id'] },\n { columns: ['email'] },\n { columns: ['tenant_id', 'email'], unique: true },\n { columns: ['status'] },\n ],\n },\n\n // ----------------------------------------\n // User Roles (Many-to-Many)\n // ----------------------------------------\n mdm_user_roles: {\n columns: {\n user_id: {\n type: 'string',\n references: { table: 'mdm_users', column: 'id', onDelete: 'cascade' },\n },\n role_id: {\n type: 'string',\n references: { table: 'mdm_roles', column: 'id', onDelete: 'cascade' },\n },\n created_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['user_id', 'role_id'], unique: true },\n { columns: ['user_id'] },\n { columns: ['role_id'] },\n ],\n },\n\n // ----------------------------------------\n // Audit Logs Table\n // ----------------------------------------\n mdm_audit_logs: {\n columns: {\n id: { type: 'string', primaryKey: true },\n tenant_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_tenants', column: 'id', onDelete: 'cascade' },\n },\n user_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_users', column: 'id', onDelete: 'set null' },\n },\n action: { type: 'string' },\n resource: { type: 'string' },\n resource_id: { type: 'string', nullable: true },\n details: { type: 'json', nullable: true },\n ip_address: { type: 'string', nullable: true },\n user_agent: { type: 'text', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['tenant_id'] },\n { columns: ['user_id'] },\n { columns: ['action'] },\n { columns: ['resource'] },\n { columns: ['resource', 'resource_id'] },\n { columns: ['created_at'] },\n ],\n },\n\n // ----------------------------------------\n // Scheduled Tasks Table\n // ----------------------------------------\n mdm_scheduled_tasks: {\n columns: {\n id: { type: 'string', primaryKey: true },\n tenant_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_tenants', column: 'id', onDelete: 'cascade' },\n },\n name: { type: 'string' },\n description: { type: 'text', nullable: true },\n task_type: {\n type: 'enum',\n enumValues: ['command', 'policy_update', 'app_install', 'maintenance', 'custom'],\n },\n schedule: { type: 'json' },\n target: { type: 'json', nullable: true },\n payload: { type: 'json', nullable: true },\n status: {\n type: 'enum',\n enumValues: ['active', 'paused', 'completed', 'failed'],\n default: 'active',\n },\n next_run_at: { type: 'datetime', nullable: true },\n last_run_at: { type: 'datetime', nullable: true },\n max_retries: { type: 'integer', default: 3 },\n retry_count: { type: 'integer', default: 0 },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['tenant_id'] },\n { columns: ['task_type'] },\n { columns: ['status'] },\n { columns: ['next_run_at'] },\n ],\n },\n\n // ----------------------------------------\n // Task Executions Table\n // ----------------------------------------\n mdm_task_executions: {\n columns: {\n id: { type: 'string', primaryKey: true },\n task_id: {\n type: 'string',\n references: { table: 'mdm_scheduled_tasks', column: 'id', onDelete: 'cascade' },\n },\n status: {\n type: 'enum',\n enumValues: ['running', 'completed', 'failed'],\n default: 'running',\n },\n started_at: { type: 'datetime', default: 'now' },\n completed_at: { type: 'datetime', nullable: true },\n devices_processed: { type: 'integer', default: 0 },\n devices_succeeded: { type: 'integer', default: 0 },\n devices_failed: { type: 'integer', default: 0 },\n error: { type: 'text', nullable: true },\n details: { type: 'json', nullable: true },\n },\n indexes: [\n { columns: ['task_id'] },\n { columns: ['status'] },\n { columns: ['started_at'] },\n ],\n },\n\n // ----------------------------------------\n // Message Queue Table\n // ----------------------------------------\n mdm_message_queue: {\n columns: {\n id: { type: 'string', primaryKey: true },\n tenant_id: {\n type: 'string',\n nullable: true,\n references: { table: 'mdm_tenants', column: 'id', onDelete: 'cascade' },\n },\n device_id: {\n type: 'string',\n references: { table: 'mdm_devices', column: 'id', onDelete: 'cascade' },\n },\n message_type: { type: 'string' },\n payload: { type: 'json' },\n priority: {\n type: 'enum',\n enumValues: ['high', 'normal', 'low'],\n default: 'normal',\n },\n status: {\n type: 'enum',\n enumValues: ['pending', 'processing', 'delivered', 'failed', 'expired'],\n default: 'pending',\n },\n attempts: { type: 'integer', default: 0 },\n max_attempts: { type: 'integer', default: 3 },\n last_attempt_at: { type: 'datetime', nullable: true },\n last_error: { type: 'text', nullable: true },\n expires_at: { type: 'datetime', nullable: true },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['tenant_id'] },\n { columns: ['device_id'] },\n { columns: ['status'] },\n { columns: ['priority'] },\n { columns: ['expires_at'] },\n { columns: ['device_id', 'status', 'priority'] },\n ],\n },\n\n // ----------------------------------------\n // Plugin Storage Table\n // ----------------------------------------\n mdm_plugin_storage: {\n columns: {\n plugin_name: { type: 'string' },\n key: { type: 'string' },\n value: { type: 'json' },\n created_at: { type: 'datetime', default: 'now' },\n updated_at: { type: 'datetime', default: 'now' },\n },\n indexes: [\n { columns: ['plugin_name', 'key'], unique: true },\n { columns: ['plugin_name'] },\n ],\n },\n },\n};\n\n// ============================================\n// Schema Helper Functions\n// ============================================\n\n/**\n * Get all table names from the schema\n */\nexport function getTableNames(): string[] {\n return Object.keys(mdmSchema.tables);\n}\n\n/**\n * Get column names for a table\n */\nexport function getColumnNames(tableName: string): string[] {\n const table = mdmSchema.tables[tableName];\n if (!table) throw new Error(`Table ${tableName} not found in schema`);\n return Object.keys(table.columns);\n}\n\n/**\n * Get the primary key column for a table\n */\nexport function getPrimaryKey(tableName: string): string | null {\n const table = mdmSchema.tables[tableName];\n if (!table) throw new Error(`Table ${tableName} not found in schema`);\n\n for (const [name, def] of Object.entries(table.columns)) {\n if (def.primaryKey) return name;\n }\n return null;\n}\n\n/**\n * Convert snake_case column name to camelCase\n */\nexport function snakeToCamel(str: string): string {\n return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());\n}\n\n/**\n * Convert camelCase to snake_case\n */\nexport function camelToSnake(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/**\n * Transform object keys from snake_case to camelCase\n */\nexport function transformToCamelCase<T extends Record<string, unknown>>(\n obj: T\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[snakeToCamel(key)] = value;\n }\n return result;\n}\n\n/**\n * Transform object keys from camelCase to snake_case\n */\nexport function transformToSnakeCase<T extends Record<string, unknown>>(\n obj: T\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[camelToSnake(key)] = value;\n }\n return result;\n}\n","/**\n * OpenMDM Agent Wire Protocol v2.\n *\n * A unified response envelope for every `/agent/*` endpoint, plus the\n * version-selection rules that let the server serve v1 and v2 clients\n * simultaneously during a fleet rollout.\n *\n * ## Background\n *\n * Until now, agent-facing handlers returned either a bare JSON body\n * on success or raised an `HTTPException(401|404|5xx)` on failure.\n * The agent had to interpret five different HTTP status codes and\n * infer what to do about each — which in practice meant \"on auth\n * error, wipe local enrollment state and re-enroll\". That single\n * ambiguity produced the auto-unenroll behavior we saw in production:\n * a transient 401 or 404 was indistinguishable from \"you are really\n * unenrolled\", so the agent self-destructed.\n *\n * ## Protocol v2\n *\n * Every agent-facing endpoint replies with HTTP 200 and a body of\n * shape {@link AgentResponse}:\n *\n * ```json\n * { \"ok\": true, \"action\": \"none\", \"data\": { ... } }\n * { \"ok\": false, \"action\": \"retry\", \"message\": \"...\" }\n * { \"ok\": false, \"action\": \"reauth\", \"message\": \"...\" }\n * { \"ok\": false, \"action\": \"unenroll\", \"message\": \"...\" }\n * ```\n *\n * - `ok` is the boolean the agent checks first.\n * - `action` is the *only* field the agent reads to decide what to do\n * next. There is exactly one handler per action on the client, so\n * adding a new server response path is a matter of picking an\n * existing action.\n * - `data` carries the handler-specific payload (heartbeat response,\n * policy update, etc.) on success.\n * - `message` is a human-readable hint, for logs.\n *\n * HTTP 5xx is still used for real infrastructure failures (the Lambda\n * timed out, the database connection dropped, etc.). v2 envelopes are\n * reserved for *application-level* failures the agent can reason about.\n *\n * ## Versioning and rollout\n *\n * The agent opts into v2 by sending the header\n * `X-Openmdm-Protocol: 2` on every request. When absent, the server\n * falls back to the legacy v1 behavior — bare JSON on success,\n * `HTTPException(401|404|…)` on failure — so a fleet still running\n * older APKs keeps working during rollout.\n *\n * After the fleet has been upgraded, v1 can be dropped in a future\n * major release by ignoring the header and always emitting v2.\n */\n\n/**\n * Instruction the server gives the agent on how to react to this\n * response. This is the entire client-side decision space.\n *\n * - `none`: happy path. The agent consumes `data` and continues.\n * - `retry`: transient problem. The agent re-tries later without\n * touching local state.\n * - `reauth`: the agent's access token is no longer valid. It should\n * call the refresh flow. It must NOT wipe enrollment state.\n * - `unenroll`: the server-side record for this device is gone or\n * blocked and the agent's credentials will never work again. The\n * agent should stop making requests and surface this to the user.\n * In Phase 2b this will be further softened: the agent will attempt\n * a hardware-identity-based rebind before treating this as terminal.\n */\nexport type AgentAction = 'none' | 'retry' | 'reauth' | 'unenroll';\n\n/**\n * Unified response envelope for every `/agent/*` endpoint under\n * protocol v2.\n *\n * Successful responses carry `data`; failure responses carry\n * `message`. The envelope never carries both the happy-path payload\n * and an error hint at the same time.\n */\nexport type AgentResponse<T = unknown> =\n | {\n ok: true;\n action: 'none';\n data: T;\n }\n | {\n ok: false;\n action: Exclude<AgentAction, 'none'>;\n message?: string;\n };\n\n/**\n * HTTP header an agent sends to opt into protocol v2. Case-insensitive\n * on the wire; use the constant to avoid typos.\n */\nexport const AGENT_PROTOCOL_HEADER = 'X-Openmdm-Protocol';\n\n/**\n * Current wire-protocol version. Agents that send\n * `X-Openmdm-Protocol: 2` get envelope responses. Absent or older\n * values are served with the legacy flat shape.\n */\nexport const AGENT_PROTOCOL_V2 = '2';\n\n/**\n * Helper: build a success envelope.\n */\nexport function agentOk<T>(data: T): AgentResponse<T> {\n return { ok: true, action: 'none', data };\n}\n\n/**\n * Helper: build a failure envelope.\n */\nexport function agentFail(\n action: Exclude<AgentAction, 'none'>,\n message?: string,\n): AgentResponse<never> {\n return { ok: false, action, message };\n}\n\n/**\n * Returns `true` iff the caller should be served protocol v2. The\n * input is the value of the {@link AGENT_PROTOCOL_HEADER} header,\n * which may be undefined.\n */\nexport function wantsAgentProtocolV2(headerValue: string | undefined | null): boolean {\n return headerValue === AGENT_PROTOCOL_V2;\n}\n","/**\n * OpenMDM Core\n *\n * A flexible, embeddable MDM (Mobile Device Management) SDK.\n * Inspired by better-auth's design philosophy.\n *\n * @example\n * ```typescript\n * import { createMDM } from '@openmdm/core';\n * import { drizzleAdapter } from '@openmdm/drizzle-adapter';\n *\n * const mdm = createMDM({\n * database: drizzleAdapter(db),\n * enrollment: {\n * deviceSecret: process.env.DEVICE_HMAC_SECRET!,\n * autoEnroll: true,\n * },\n * });\n *\n * // Use in your routes\n * const devices = await mdm.devices.list();\n * ```\n */\n\nimport { createHmac, timingSafeEqual, randomUUID } from 'crypto';\nimport type {\n MDMConfig,\n MDMInstance,\n Device,\n Policy,\n Application,\n Command,\n Group,\n Heartbeat,\n EnrollmentRequest,\n EnrollmentResponse,\n DeviceFilter,\n DeviceListResult,\n CreateDeviceInput,\n UpdateDeviceInput,\n CreatePolicyInput,\n UpdatePolicyInput,\n CreateApplicationInput,\n UpdateApplicationInput,\n SendCommandInput,\n CommandFilter,\n CreateGroupInput,\n UpdateGroupInput,\n DeployTarget,\n DeviceManager,\n PolicyManager,\n ApplicationManager,\n CommandManager,\n GroupManager,\n PushAdapter,\n PushResult,\n PushBatchResult,\n PushMessage,\n EventType,\n EventHandler,\n EventPayloadMap,\n MDMEvent,\n MDMPlugin,\n CommandResult,\n InstalledApp,\n WebhookManager,\n TenantManager,\n AuthorizationManager,\n AuditManager,\n ScheduleManager,\n MessageQueueManager,\n DashboardManager,\n PluginStorageAdapter,\n GroupTreeNode,\n GroupHierarchyStats,\n Logger,\n EnrollmentChallenge,\n} from './types';\nimport {\n DeviceNotFoundError,\n ApplicationNotFoundError,\n CommandNotFoundError,\n EnrollmentError,\n} from './types';\nimport { createWebhookManager } from './webhooks';\nimport { createTenantManager } from './tenant';\nimport { createAuthorizationManager } from './authorization';\nimport { createAuditManager } from './audit';\nimport { createScheduleManager } from './schedule';\nimport { createMessageQueueManager } from './queue';\nimport { createDashboardManager } from './dashboard';\nimport { createPluginStorageAdapter, createMemoryPluginStorageAdapter } from './plugin-storage';\nimport { createConsoleLogger, createSilentLogger } from './logger';\nimport {\n importPublicKeyFromSpki,\n verifyEcdsaSignature,\n canonicalEnrollmentMessage,\n canonicalDeviceRequestMessage,\n verifyDeviceRequest,\n InvalidPublicKeyError,\n PublicKeyMismatchError,\n ChallengeInvalidError,\n} from './device-identity';\n\n// Re-export all types\nexport * from './types';\nexport * from './schema';\nexport * from './agent-protocol';\nexport { createWebhookManager, verifyWebhookSignature } from './webhooks';\nexport type { WebhookPayload } from './webhooks';\nexport { createConsoleLogger, createSilentLogger } from './logger';\n\n// Device identity (Phase 2b)\nexport {\n importPublicKeyFromSpki,\n verifyEcdsaSignature,\n canonicalEnrollmentMessage,\n canonicalDeviceRequestMessage,\n verifyDeviceRequest,\n InvalidPublicKeyError,\n PublicKeyMismatchError,\n ChallengeInvalidError,\n} from './device-identity';\n\n// Re-export enterprise manager factories\nexport { createTenantManager } from './tenant';\nexport { createAuthorizationManager } from './authorization';\nexport { createAuditManager } from './audit';\nexport { createScheduleManager } from './schedule';\nexport { createMessageQueueManager } from './queue';\nexport { createDashboardManager } from './dashboard';\nexport { createPluginStorageAdapter, createMemoryPluginStorageAdapter, createPluginKey, parsePluginKey } from './plugin-storage';\n\n/**\n * Create an MDM instance with the given configuration.\n */\nexport function createMDM(config: MDMConfig): MDMInstance {\n const { database, push, enrollment, webhooks: webhooksConfig, plugins = [] } = config;\n\n // Structured logger. Falls back to the console-backed default if\n // the host doesn't pass one. Host code is expected to pass a real\n // pino/winston instance in production.\n const logger = config.logger ?? createConsoleLogger();\n\n // Extract a stable message from an unknown thrown value so it\n // survives JSON serialization into the log context. Error objects\n // stringify to `{}` otherwise, which is the #1 cause of \"we can't\n // tell why this failed\" in production logs.\n const errorMessage = (err: unknown): string => {\n if (err instanceof Error) return err.message;\n if (typeof err === 'string') return err;\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n };\n\n // Event handlers registry\n const eventHandlers = new Map<EventType, Set<EventHandler<EventType>>>();\n\n // Create push adapter\n const pushAdapter: PushAdapter = push\n ? createPushAdapter(push, database, logger)\n : createStubPushAdapter(logger);\n\n // Create webhook manager if configured\n const webhookManager: WebhookManager | undefined = webhooksConfig\n ? createWebhookManager(webhooksConfig, logger)\n : undefined;\n\n // ============================================\n // Enterprise Managers (optional)\n // ============================================\n\n // Create tenant manager if multi-tenancy is enabled\n const tenantManager: TenantManager | undefined = config.multiTenancy?.enabled\n ? createTenantManager(database)\n : undefined;\n\n // Create authorization manager if authorization is enabled\n const authorizationManager: AuthorizationManager | undefined = config.authorization?.enabled\n ? createAuthorizationManager(database)\n : undefined;\n\n // Create audit manager if audit logging is enabled\n const auditManager: AuditManager | undefined = config.audit?.enabled\n ? createAuditManager(database)\n : undefined;\n\n // Create schedule manager if scheduling is enabled\n const scheduleManager: ScheduleManager | undefined = config.scheduling?.enabled\n ? createScheduleManager(database)\n : undefined;\n\n // Create message queue manager if the database supports it\n const messageQueueManager: MessageQueueManager | undefined = database.enqueueMessage\n ? createMessageQueueManager(database)\n : undefined;\n\n // Create dashboard manager (always available, uses database fallbacks)\n const dashboardManager: DashboardManager = createDashboardManager(database);\n\n // Create plugin storage adapter\n const pluginStorageAdapter: PluginStorageAdapter | undefined =\n config.pluginStorage?.adapter === 'database'\n ? createPluginStorageAdapter(database)\n : config.pluginStorage?.adapter === 'memory'\n ? createMemoryPluginStorageAdapter()\n : undefined;\n\n // Event subscription\n const on = <T extends EventType>(\n event: T,\n handler: EventHandler<T>\n ): (() => void) => {\n if (!eventHandlers.has(event)) {\n eventHandlers.set(event, new Set());\n }\n const handlers = eventHandlers.get(event)!;\n handlers.add(handler as EventHandler<EventType>);\n\n // Return unsubscribe function\n return () => {\n handlers.delete(handler as EventHandler<EventType>);\n };\n };\n\n // Event emission\n const emit = async <T extends EventType>(\n event: T,\n data: EventPayloadMap[T]\n ): Promise<void> => {\n const handlers = eventHandlers.get(event);\n\n // Create event record\n const eventRecord: MDMEvent<EventPayloadMap[T]> = {\n id: randomUUID(),\n deviceId: (data as any).device?.id || (data as any).deviceId || '',\n type: event,\n payload: data,\n createdAt: new Date(),\n };\n\n // Persist event\n try {\n await database.createEvent({\n deviceId: eventRecord.deviceId,\n type: eventRecord.type,\n payload: eventRecord.payload as Record<string, unknown>,\n });\n } catch (error) {\n logger.error({ err: errorMessage(error), event }, 'Failed to persist event');\n }\n\n // Deliver webhooks (async, don't wait)\n if (webhookManager) {\n webhookManager.deliver(eventRecord).catch((error) => {\n logger.error(\n { err: errorMessage(error), event },\n 'Webhook delivery error',\n );\n });\n }\n\n // Call handlers\n if (handlers) {\n for (const handler of handlers) {\n try {\n await handler(eventRecord);\n } catch (error) {\n logger.error(\n { err: errorMessage(error), event },\n 'Event handler threw',\n );\n }\n }\n }\n\n // Call config hook if defined\n if (config.onEvent) {\n try {\n await config.onEvent(eventRecord);\n } catch (error) {\n logger.error({ err: errorMessage(error) }, 'onEvent hook threw');\n }\n }\n };\n\n // ============================================\n // Device Manager\n // ============================================\n\n const devices: DeviceManager = {\n async get(id: string): Promise<Device | null> {\n return database.findDevice(id);\n },\n\n async getByEnrollmentId(enrollmentId: string): Promise<Device | null> {\n return database.findDeviceByEnrollmentId(enrollmentId);\n },\n\n async list(filter?: DeviceFilter): Promise<DeviceListResult> {\n return database.listDevices(filter);\n },\n\n async create(data: CreateDeviceInput): Promise<Device> {\n const device = await database.createDevice(data);\n\n await emit('device.enrolled', { device });\n\n if (config.onDeviceEnrolled) {\n await config.onDeviceEnrolled(device);\n }\n\n return device;\n },\n\n async update(id: string, data: UpdateDeviceInput): Promise<Device> {\n const oldDevice = await database.findDevice(id);\n if (!oldDevice) {\n throw new DeviceNotFoundError(id);\n }\n\n const device = await database.updateDevice(id, data);\n\n // Emit status change event if status changed\n if (data.status && data.status !== oldDevice.status) {\n await emit('device.statusChanged', {\n device,\n oldStatus: oldDevice.status,\n newStatus: data.status,\n });\n }\n\n // Emit policy change event if policy changed\n if (data.policyId !== undefined && data.policyId !== oldDevice.policyId) {\n await emit('device.policyChanged', {\n device,\n oldPolicyId: oldDevice.policyId || undefined,\n newPolicyId: data.policyId || undefined,\n });\n }\n\n return device;\n },\n\n async delete(id: string): Promise<void> {\n const device = await database.findDevice(id);\n if (device) {\n await database.deleteDevice(id);\n await emit('device.unenrolled', { device });\n\n if (config.onDeviceUnenrolled) {\n await config.onDeviceUnenrolled(device);\n }\n }\n },\n\n async assignPolicy(\n deviceId: string,\n policyId: string | null\n ): Promise<Device> {\n const device = await this.update(deviceId, { policyId });\n\n // Notify device of policy change\n await pushAdapter.send(deviceId, {\n type: 'policy.updated',\n payload: { policyId },\n priority: 'high',\n });\n\n return device;\n },\n\n async addToGroup(deviceId: string, groupId: string): Promise<void> {\n await database.addDeviceToGroup(deviceId, groupId);\n },\n\n async removeFromGroup(deviceId: string, groupId: string): Promise<void> {\n await database.removeDeviceFromGroup(deviceId, groupId);\n },\n\n async getGroups(deviceId: string): Promise<Group[]> {\n return database.getDeviceGroups(deviceId);\n },\n\n async sendCommand(\n deviceId: string,\n input: Omit<SendCommandInput, 'deviceId'>\n ): Promise<Command> {\n const command = await database.createCommand({\n ...input,\n deviceId,\n });\n\n // Send via push\n const pushResult = await pushAdapter.send(deviceId, {\n type: `command.${input.type}`,\n payload: {\n commandId: command.id,\n type: input.type,\n ...input.payload,\n },\n priority: 'high',\n });\n\n // Update command status\n if (pushResult.success) {\n await database.updateCommand(command.id, {\n status: 'sent',\n sentAt: new Date(),\n });\n }\n\n if (config.onCommand) {\n await config.onCommand(command);\n }\n\n return database.findCommand(command.id) as Promise<Command>;\n },\n\n async sync(deviceId: string): Promise<Command> {\n return this.sendCommand(deviceId, { type: 'sync' });\n },\n\n async reboot(deviceId: string): Promise<Command> {\n return this.sendCommand(deviceId, { type: 'reboot' });\n },\n\n async lock(deviceId: string, message?: string): Promise<Command> {\n return this.sendCommand(deviceId, {\n type: 'lock',\n payload: message ? { message } : undefined,\n });\n },\n\n async wipe(deviceId: string, preserveData?: boolean): Promise<Command> {\n return this.sendCommand(deviceId, {\n type: preserveData ? 'wipe' : 'factoryReset',\n payload: { preserveData },\n });\n },\n };\n\n // ============================================\n // Policy Manager\n // ============================================\n\n const policies: PolicyManager = {\n async get(id: string): Promise<Policy | null> {\n return database.findPolicy(id);\n },\n\n async getDefault(): Promise<Policy | null> {\n return database.findDefaultPolicy();\n },\n\n async list(): Promise<Policy[]> {\n return database.listPolicies();\n },\n\n async create(data: CreatePolicyInput): Promise<Policy> {\n // If this is being set as default, clear other defaults first\n if (data.isDefault) {\n const existingPolicies = await database.listPolicies();\n for (const policy of existingPolicies) {\n if (policy.isDefault) {\n await database.updatePolicy(policy.id, { isDefault: false });\n }\n }\n }\n\n return database.createPolicy(data);\n },\n\n async update(id: string, data: UpdatePolicyInput): Promise<Policy> {\n // If setting as default, clear other defaults first\n if (data.isDefault) {\n const existingPolicies = await database.listPolicies();\n for (const policy of existingPolicies) {\n if (policy.isDefault && policy.id !== id) {\n await database.updatePolicy(policy.id, { isDefault: false });\n }\n }\n }\n\n const policy = await database.updatePolicy(id, data);\n\n // Notify all devices with this policy\n const devicesResult = await database.listDevices({ policyId: id });\n if (devicesResult.devices.length > 0) {\n const deviceIds = devicesResult.devices.map((d) => d.id);\n await pushAdapter.sendBatch(deviceIds, {\n type: 'policy.updated',\n payload: { policyId: id },\n priority: 'high',\n });\n }\n\n return policy;\n },\n\n async delete(id: string): Promise<void> {\n // Check if any devices use this policy\n const devicesResult = await database.listDevices({ policyId: id });\n if (devicesResult.devices.length > 0) {\n // Remove policy from devices first\n for (const device of devicesResult.devices) {\n await database.updateDevice(device.id, { policyId: null });\n }\n }\n\n await database.deletePolicy(id);\n },\n\n async setDefault(id: string): Promise<Policy> {\n return this.update(id, { isDefault: true });\n },\n\n async getDevices(policyId: string): Promise<Device[]> {\n const result = await database.listDevices({ policyId });\n return result.devices;\n },\n\n async applyToDevice(policyId: string, deviceId: string): Promise<void> {\n await devices.assignPolicy(deviceId, policyId);\n },\n };\n\n // ============================================\n // Application Manager\n // ============================================\n\n const apps: ApplicationManager = {\n async get(id: string): Promise<Application | null> {\n return database.findApplication(id);\n },\n\n async getByPackage(\n packageName: string,\n version?: string\n ): Promise<Application | null> {\n return database.findApplicationByPackage(packageName, version);\n },\n\n async list(activeOnly?: boolean): Promise<Application[]> {\n return database.listApplications(activeOnly);\n },\n\n async register(data: CreateApplicationInput): Promise<Application> {\n return database.createApplication(data);\n },\n\n async update(id: string, data: UpdateApplicationInput): Promise<Application> {\n return database.updateApplication(id, data);\n },\n\n async delete(id: string): Promise<void> {\n await database.deleteApplication(id);\n },\n\n async activate(id: string): Promise<Application> {\n return database.updateApplication(id, { isActive: true });\n },\n\n async deactivate(id: string): Promise<Application> {\n return database.updateApplication(id, { isActive: false });\n },\n\n async deploy(packageName: string, target: DeployTarget): Promise<void> {\n const app = await database.findApplicationByPackage(packageName);\n if (!app) {\n throw new ApplicationNotFoundError(packageName);\n }\n\n const deviceIds: string[] = [];\n\n // Collect target devices\n if (target.devices) {\n deviceIds.push(...target.devices);\n }\n\n if (target.groups) {\n for (const groupId of target.groups) {\n const groupDevices = await database.listDevicesInGroup(groupId);\n deviceIds.push(...groupDevices.map((d) => d.id));\n }\n }\n\n if (target.policies) {\n for (const policyId of target.policies) {\n const result = await database.listDevices({ policyId });\n deviceIds.push(...result.devices.map((d) => d.id));\n }\n }\n\n // Deduplicate\n const uniqueDeviceIds = [...new Set(deviceIds)];\n\n // Send install command to all devices\n if (uniqueDeviceIds.length > 0) {\n await pushAdapter.sendBatch(uniqueDeviceIds, {\n type: 'command.installApp',\n payload: {\n packageName: app.packageName,\n version: app.version,\n versionCode: app.versionCode,\n url: app.url,\n hash: app.hash,\n },\n priority: 'high',\n });\n\n // Create command records for each device\n for (const deviceId of uniqueDeviceIds) {\n await database.createCommand({\n deviceId,\n type: 'installApp',\n payload: {\n packageName: app.packageName,\n version: app.version,\n url: app.url,\n },\n });\n }\n }\n },\n\n async installOnDevice(\n packageName: string,\n deviceId: string,\n version?: string\n ): Promise<Command> {\n const app = await database.findApplicationByPackage(packageName, version);\n if (!app) {\n throw new ApplicationNotFoundError(packageName);\n }\n\n return devices.sendCommand(deviceId, {\n type: 'installApp',\n payload: {\n packageName: app.packageName,\n version: app.version,\n versionCode: app.versionCode,\n url: app.url,\n hash: app.hash,\n },\n });\n },\n\n async uninstallFromDevice(\n packageName: string,\n deviceId: string\n ): Promise<Command> {\n return devices.sendCommand(deviceId, {\n type: 'uninstallApp',\n payload: { packageName },\n });\n },\n };\n\n // ============================================\n // Command Manager\n // ============================================\n\n const commands: CommandManager = {\n async get(id: string): Promise<Command | null> {\n return database.findCommand(id);\n },\n\n async list(filter?: CommandFilter): Promise<Command[]> {\n return database.listCommands(filter);\n },\n\n async send(input: SendCommandInput): Promise<Command> {\n return devices.sendCommand(input.deviceId, {\n type: input.type,\n payload: input.payload,\n });\n },\n\n async cancel(id: string): Promise<Command> {\n const command = await database.updateCommand(id, { status: 'cancelled' });\n if (!command) {\n throw new CommandNotFoundError(id);\n }\n return command;\n },\n\n async acknowledge(id: string): Promise<Command> {\n const command = await database.updateCommand(id, {\n status: 'acknowledged',\n acknowledgedAt: new Date(),\n });\n\n if (!command) {\n throw new CommandNotFoundError(id);\n }\n\n const device = await database.findDevice(command.deviceId);\n if (device) {\n await emit('command.acknowledged', { device, command });\n }\n\n return command;\n },\n\n async complete(id: string, result: CommandResult): Promise<Command> {\n const command = await database.updateCommand(id, {\n status: 'completed',\n result,\n completedAt: new Date(),\n });\n\n if (!command) {\n throw new CommandNotFoundError(id);\n }\n\n const device = await database.findDevice(command.deviceId);\n if (device) {\n await emit('command.completed', { device, command, result });\n }\n\n return command;\n },\n\n async fail(id: string, error: string): Promise<Command> {\n const command = await database.updateCommand(id, {\n status: 'failed',\n error,\n completedAt: new Date(),\n });\n\n if (!command) {\n throw new CommandNotFoundError(id);\n }\n\n const device = await database.findDevice(command.deviceId);\n if (device) {\n await emit('command.failed', { device, command, error });\n }\n\n return command;\n },\n\n async getPending(deviceId: string): Promise<Command[]> {\n return database.getPendingCommands(deviceId);\n },\n };\n\n // ============================================\n // Group Manager\n // ============================================\n\n const groups: GroupManager = {\n async get(id: string): Promise<Group | null> {\n return database.findGroup(id);\n },\n\n async list(): Promise<Group[]> {\n return database.listGroups();\n },\n\n async create(data: CreateGroupInput): Promise<Group> {\n return database.createGroup(data);\n },\n\n async update(id: string, data: UpdateGroupInput): Promise<Group> {\n return database.updateGroup(id, data);\n },\n\n async delete(id: string): Promise<void> {\n await database.deleteGroup(id);\n },\n\n async getDevices(groupId: string): Promise<Device[]> {\n return database.listDevicesInGroup(groupId);\n },\n\n async addDevice(groupId: string, deviceId: string): Promise<void> {\n await database.addDeviceToGroup(deviceId, groupId);\n },\n\n async removeDevice(groupId: string, deviceId: string): Promise<void> {\n await database.removeDeviceFromGroup(deviceId, groupId);\n },\n\n async getChildren(groupId: string): Promise<Group[]> {\n const allGroups = await database.listGroups();\n return allGroups.filter((g) => g.parentId === groupId);\n },\n\n async getTree(rootId?: string): Promise<GroupTreeNode[]> {\n // Use database implementation if available\n if (database.getGroupTree) {\n return database.getGroupTree(rootId);\n }\n\n // Fallback: Build tree from flat list\n const allGroups = await database.listGroups();\n const groupMap = new Map(allGroups.map((g) => [g.id, g]));\n\n const buildNode = (group: Group, depth: number, path: string[]): GroupTreeNode => {\n const children = allGroups\n .filter((g) => g.parentId === group.id)\n .map((child) => buildNode(child, depth + 1, [...path, group.id]));\n\n return {\n ...group,\n children,\n depth,\n path,\n effectivePolicyId: group.policyId,\n };\n };\n\n // Find root groups (those with no parent or matching rootId)\n const roots = allGroups.filter((g) =>\n rootId ? g.id === rootId : !g.parentId\n );\n\n return roots.map((root) => buildNode(root, 0, []));\n },\n\n async getAncestors(groupId: string): Promise<Group[]> {\n // Use database implementation if available\n if (database.getGroupAncestors) {\n return database.getGroupAncestors(groupId);\n }\n\n // Fallback: Traverse up the tree\n const ancestors: Group[] = [];\n const allGroups = await database.listGroups();\n const groupMap = new Map(allGroups.map((g) => [g.id, g]));\n\n let current = groupMap.get(groupId);\n while (current?.parentId) {\n const parent = groupMap.get(current.parentId);\n if (parent) {\n ancestors.push(parent);\n current = parent;\n } else {\n break;\n }\n }\n\n return ancestors;\n },\n\n async getDescendants(groupId: string): Promise<Group[]> {\n // Use database implementation if available\n if (database.getGroupDescendants) {\n return database.getGroupDescendants(groupId);\n }\n\n // Fallback: Find all descendants recursively\n const allGroups = await database.listGroups();\n const descendants: Group[] = [];\n\n const findDescendants = (parentId: string) => {\n const children = allGroups.filter((g) => g.parentId === parentId);\n for (const child of children) {\n descendants.push(child);\n findDescendants(child.id);\n }\n };\n\n findDescendants(groupId);\n return descendants;\n },\n\n async move(groupId: string, newParentId: string | null): Promise<Group> {\n // Validate that we're not creating a cycle\n if (newParentId) {\n const ancestors = await this.getAncestors(newParentId);\n if (ancestors.some((a) => a.id === groupId)) {\n throw new Error('Cannot move group: would create circular reference');\n }\n }\n\n return database.updateGroup(groupId, { parentId: newParentId });\n },\n\n async getEffectivePolicy(groupId: string): Promise<Policy | null> {\n // Use database implementation if available\n if (database.getGroupEffectivePolicy) {\n return database.getGroupEffectivePolicy(groupId);\n }\n\n // Fallback: Walk up the tree to find first policy\n const group = await database.findGroup(groupId);\n if (!group) return null;\n\n if (group.policyId) {\n return database.findPolicy(group.policyId);\n }\n\n // Check ancestors\n const ancestors = await this.getAncestors(groupId);\n for (const ancestor of ancestors) {\n if (ancestor.policyId) {\n return database.findPolicy(ancestor.policyId);\n }\n }\n\n return null;\n },\n\n async getHierarchyStats(): Promise<GroupHierarchyStats> {\n // Use database implementation if available\n if (database.getGroupHierarchyStats) {\n return database.getGroupHierarchyStats();\n }\n\n // Fallback: Compute from flat list\n const allGroups = await database.listGroups();\n let maxDepth = 0;\n let groupsWithDevices = 0;\n let groupsWithPolicies = 0;\n\n for (const group of allGroups) {\n // Calculate depth\n const ancestors = await this.getAncestors(group.id);\n maxDepth = Math.max(maxDepth, ancestors.length);\n\n // Check for devices\n const devices = await database.listDevicesInGroup(group.id);\n if (devices.length > 0) groupsWithDevices++;\n\n // Check for policies\n if (group.policyId) groupsWithPolicies++;\n }\n\n return {\n totalGroups: allGroups.length,\n maxDepth,\n groupsWithDevices,\n groupsWithPolicies,\n };\n },\n };\n\n // ============================================\n // Enrollment\n // ============================================\n\n const enroll = async (\n request: EnrollmentRequest\n ): Promise<EnrollmentResponse> => {\n // Validate method if restricted\n if (\n enrollment?.allowedMethods &&\n !enrollment.allowedMethods.includes(request.method)\n ) {\n throw new EnrollmentError(\n `Enrollment method '${request.method}' is not allowed`\n );\n }\n\n // Determine which enrollment path the request is asking for.\n // The presence of `publicKey` is the signal: if the device\n // supplies a public key, it is attempting the Phase 2b\n // device-pinned-key path and must also supply a valid\n // attestation challenge. Otherwise we fall through to the\n // legacy HMAC path.\n const isPinnedKeyPath = Boolean(request.publicKey);\n\n if (!isPinnedKeyPath && enrollment?.pinnedKey?.required) {\n throw new EnrollmentError(\n 'Pinned-key enrollment is required but the request carried no publicKey. ' +\n 'The agent must generate a Keystore keypair and submit the SPKI public key ' +\n 'alongside an ECDSA signature over the canonical enrollment message.',\n );\n }\n\n // HMAC path (Phase 2a): unchanged behavior.\n if (!isPinnedKeyPath && enrollment?.deviceSecret) {\n const isValid = verifyEnrollmentSignature(\n request,\n enrollment.deviceSecret\n );\n if (!isValid) {\n throw new EnrollmentError('Invalid enrollment signature');\n }\n }\n\n // Pinned-key path (Phase 2b).\n let challengeRecord: EnrollmentChallenge | null = null;\n let importedPublicKey: ReturnType<typeof importPublicKeyFromSpki> | null = null;\n if (isPinnedKeyPath) {\n if (!request.attestationChallenge) {\n throw new EnrollmentError(\n 'Pinned-key enrollment requires attestationChallenge. ' +\n 'Fetch a fresh challenge from /agent/enroll/challenge first.',\n );\n }\n if (!database.consumeEnrollmentChallenge) {\n throw new EnrollmentError(\n 'Pinned-key enrollment requires an adapter that implements enrollment ' +\n 'challenge storage. Upgrade to a database adapter that supports it, or ' +\n 'submit an HMAC-signed enrollment instead.',\n );\n }\n\n // Parse the public key first — if it's malformed the signature\n // cannot possibly verify and we want a specific error.\n try {\n importedPublicKey = importPublicKeyFromSpki(request.publicKey as string);\n } catch (err) {\n throw new EnrollmentError(\n err instanceof Error\n ? `Invalid enrollment public key: ${err.message}`\n : 'Invalid enrollment public key',\n );\n }\n\n // Atomically consume the challenge. This must happen BEFORE\n // signature verification, otherwise two concurrent requests\n // with the same challenge could both succeed.\n challengeRecord = await database.consumeEnrollmentChallenge(\n request.attestationChallenge,\n );\n if (!challengeRecord) {\n throw new ChallengeInvalidError(\n 'Enrollment challenge is missing, expired, or already consumed',\n request.attestationChallenge,\n );\n }\n if (challengeRecord.expiresAt.getTime() < Date.now()) {\n throw new ChallengeInvalidError(\n 'Enrollment challenge has expired',\n request.attestationChallenge,\n );\n }\n\n const canonical = canonicalEnrollmentMessage({\n publicKey: request.publicKey as string,\n model: request.model,\n manufacturer: request.manufacturer,\n osVersion: request.osVersion,\n serialNumber: request.serialNumber,\n imei: request.imei,\n macAddress: request.macAddress,\n androidId: request.androidId,\n method: request.method,\n timestamp: request.timestamp,\n challenge: request.attestationChallenge,\n });\n\n const verified = verifyEcdsaSignature(\n importedPublicKey,\n canonical,\n request.signature,\n );\n if (!verified) {\n throw new EnrollmentError(\n 'Invalid enrollment signature (device-pinned-key path)',\n );\n }\n }\n\n // Custom validation\n if (enrollment?.validate) {\n const isValid = await enrollment.validate(request);\n if (!isValid) {\n throw new EnrollmentError('Enrollment validation failed');\n }\n }\n\n // Determine enrollment ID\n const enrollmentId =\n request.macAddress ||\n request.serialNumber ||\n request.imei ||\n request.androidId;\n\n if (!enrollmentId) {\n throw new EnrollmentError(\n 'Device must provide at least one identifier (macAddress, serialNumber, imei, or androidId)'\n );\n }\n\n // Check if device already exists\n let device = await database.findDeviceByEnrollmentId(enrollmentId);\n\n if (device) {\n // Device re-enrolling. If the device is already on the\n // pinned-key path, the submitted public key MUST match the\n // pinned one — otherwise we reject loudly. This is how we\n // prevent an attacker who extracted the enrollment secret\n // from hijacking an enrolled device's identity: without the\n // original private key they cannot produce a valid signature,\n // and even if they could (via a forged HMAC fallback), the\n // pinned key still identifies the legitimate device.\n if (isPinnedKeyPath && device.publicKey) {\n if (device.publicKey !== request.publicKey) {\n throw new PublicKeyMismatchError(device.id);\n }\n }\n\n const updateInput: UpdateDeviceInput = {\n status: 'enrolled',\n model: request.model,\n manufacturer: request.manufacturer,\n osVersion: request.osVersion,\n lastSync: new Date(),\n };\n\n // Pin the key on first pinned-key enrollment for a device\n // that originally enrolled on HMAC. This is the migration\n // path: a device that used to sign with the shared secret\n // can upgrade by sending its freshly-generated public key on\n // its next enrollment, and the server will pin it from then\n // on.\n if (isPinnedKeyPath && !device.publicKey) {\n updateInput.publicKey = request.publicKey;\n updateInput.enrollmentMethod = 'pinned-key';\n }\n\n device = await database.updateDevice(device.id, updateInput);\n } else if (enrollment?.autoEnroll) {\n // Auto-create device\n device = await database.createDevice({\n enrollmentId,\n model: request.model,\n manufacturer: request.manufacturer,\n osVersion: request.osVersion,\n serialNumber: request.serialNumber,\n imei: request.imei,\n macAddress: request.macAddress,\n androidId: request.androidId,\n policyId: request.policyId || enrollment.defaultPolicyId,\n });\n\n // Pin the public key on first enrollment for pinned-key path.\n // `CreateDeviceInput` deliberately doesn't carry auth fields —\n // we keep auth state a post-creation concern so legacy\n // adapters don't have to know about it.\n if (isPinnedKeyPath) {\n device = await database.updateDevice(device.id, {\n publicKey: request.publicKey,\n enrollmentMethod: 'pinned-key',\n });\n }\n\n // Add to default group if configured\n if (enrollment.defaultGroupId) {\n await database.addDeviceToGroup(device.id, enrollment.defaultGroupId);\n }\n } else if (enrollment?.requireApproval) {\n // Create pending device\n device = await database.createDevice({\n enrollmentId,\n model: request.model,\n manufacturer: request.manufacturer,\n osVersion: request.osVersion,\n serialNumber: request.serialNumber,\n imei: request.imei,\n macAddress: request.macAddress,\n androidId: request.androidId,\n });\n\n // Pin the public key even for pending devices — we want to\n // know which key originally enrolled once an admin approves.\n if (isPinnedKeyPath) {\n device = await database.updateDevice(device.id, {\n publicKey: request.publicKey,\n enrollmentMethod: 'pinned-key',\n });\n }\n // Status remains 'pending'\n } else {\n throw new EnrollmentError(\n 'Device not registered and auto-enroll is disabled'\n );\n }\n\n // Get policy\n let policy: Policy | null = null;\n if (device.policyId) {\n policy = await database.findPolicy(device.policyId);\n }\n if (!policy) {\n policy = await database.findDefaultPolicy();\n }\n\n // Generate JWT token for device auth\n const tokenSecret =\n config.auth?.deviceTokenSecret || enrollment?.deviceSecret || '';\n const tokenExpiration = config.auth?.deviceTokenExpiration || 365 * 24 * 60 * 60;\n const token = generateDeviceToken(device.id, tokenSecret, tokenExpiration);\n\n // Emit enrollment event\n await emit('device.enrolled', { device });\n\n // Call config hook if defined\n if (config.onDeviceEnrolled) {\n await config.onDeviceEnrolled(device);\n }\n\n // Call plugin hooks\n for (const plugin of plugins) {\n if (plugin.onEnroll) {\n await plugin.onEnroll(device, request);\n }\n if (plugin.onDeviceEnrolled) {\n await plugin.onDeviceEnrolled(device);\n }\n }\n\n return {\n deviceId: device.id,\n enrollmentId: device.enrollmentId,\n policyId: policy?.id,\n policy: policy || undefined,\n serverUrl: config.serverUrl || '',\n pushConfig: {\n provider: push?.provider || 'polling',\n fcmSenderId: (push?.fcmCredentials as any)?.project_id,\n mqttUrl: push?.mqttUrl,\n mqttTopic: push?.mqttTopicPrefix\n ? `${push.mqttTopicPrefix}/${device.id}`\n : `openmdm/devices/${device.id}`,\n pollingInterval: push?.pollingInterval || 60,\n },\n token,\n tokenExpiresAt: new Date(Date.now() + tokenExpiration * 1000),\n };\n };\n\n // ============================================\n // Heartbeat Processing\n // ============================================\n\n const processHeartbeat = async (\n deviceId: string,\n heartbeat: Heartbeat\n ): Promise<void> => {\n const device = await database.findDevice(deviceId);\n if (!device) {\n throw new DeviceNotFoundError(deviceId);\n }\n\n // Update device with heartbeat data\n const updateData: UpdateDeviceInput = {\n lastHeartbeat: heartbeat.timestamp,\n batteryLevel: heartbeat.batteryLevel,\n storageUsed: heartbeat.storageUsed,\n storageTotal: heartbeat.storageTotal,\n installedApps: heartbeat.installedApps,\n };\n\n if (heartbeat.location) {\n updateData.location = heartbeat.location;\n }\n\n const updatedDevice = await database.updateDevice(deviceId, updateData);\n\n // Emit heartbeat event\n await emit('device.heartbeat', { device: updatedDevice, heartbeat });\n\n // Emit location event if location changed\n if (heartbeat.location) {\n await emit('device.locationUpdated', {\n device: updatedDevice,\n location: heartbeat.location,\n });\n }\n\n // Check for app changes\n if (device.installedApps && heartbeat.installedApps) {\n const oldApps = new Map(\n device.installedApps.map((a) => [a.packageName, a])\n );\n const newApps = new Map(\n heartbeat.installedApps.map((a) => [a.packageName, a])\n );\n\n // Check for new installs\n for (const [pkg, app] of newApps) {\n const oldApp = oldApps.get(pkg);\n if (!oldApp) {\n await emit('app.installed', { device: updatedDevice, app });\n } else if (oldApp.version !== app.version) {\n await emit('app.updated', {\n device: updatedDevice,\n app,\n oldVersion: oldApp.version,\n });\n }\n }\n\n // Check for uninstalls\n for (const [pkg] of oldApps) {\n if (!newApps.has(pkg)) {\n await emit('app.uninstalled', {\n device: updatedDevice,\n packageName: pkg,\n });\n }\n }\n }\n\n // Call config hook if defined\n if (config.onHeartbeat) {\n await config.onHeartbeat(updatedDevice, heartbeat);\n }\n\n // Call plugin hooks\n for (const plugin of plugins) {\n if (plugin.onHeartbeat) {\n await plugin.onHeartbeat(updatedDevice, heartbeat);\n }\n }\n };\n\n // ============================================\n // Token Verification\n // ============================================\n\n const verifyDeviceToken = async (\n token: string\n ): Promise<{ deviceId: string } | null> => {\n try {\n const tokenSecret =\n config.auth?.deviceTokenSecret || enrollment?.deviceSecret || '';\n\n const parts = token.split('.');\n if (parts.length !== 3) {\n return null;\n }\n\n const [header, payload, signature] = parts;\n\n // Verify signature\n const expectedSignature = createHmac('sha256', tokenSecret)\n .update(`${header}.${payload}`)\n .digest('base64url');\n\n if (signature !== expectedSignature) {\n return null;\n }\n\n // Decode payload\n const decoded = JSON.parse(\n Buffer.from(payload, 'base64url').toString('utf-8')\n );\n\n // Check expiration\n if (decoded.exp && decoded.exp < Math.floor(Date.now() / 1000)) {\n return null;\n }\n\n return { deviceId: decoded.sub };\n } catch {\n return null;\n }\n };\n\n // ============================================\n // Plugin Management\n // ============================================\n\n const getPlugins = (): MDMPlugin[] => plugins;\n\n const getPlugin = (name: string): MDMPlugin | undefined => {\n return plugins.find((p) => p.name === name);\n };\n\n // ============================================\n // Create Instance\n // ============================================\n\n const instance: MDMInstance = {\n devices,\n policies,\n apps,\n commands,\n groups,\n push: pushAdapter,\n webhooks: webhookManager,\n db: database,\n logger,\n config,\n on,\n emit,\n enroll,\n processHeartbeat,\n verifyDeviceToken,\n getPlugins,\n getPlugin,\n // Enterprise managers (optional)\n tenants: tenantManager,\n authorization: authorizationManager,\n audit: auditManager,\n schedules: scheduleManager,\n messageQueue: messageQueueManager,\n dashboard: dashboardManager,\n pluginStorage: pluginStorageAdapter,\n };\n\n // Initialize plugins\n (async () => {\n for (const plugin of plugins) {\n if (plugin.onInit) {\n try {\n await plugin.onInit(instance);\n logger.info({ plugin: plugin.name }, 'Plugin initialized');\n } catch (error) {\n logger.error(\n { plugin: plugin.name, err: errorMessage(error) },\n 'Failed to initialize plugin',\n );\n }\n }\n }\n })();\n\n return instance;\n}\n\n// ============================================\n// Push Adapter Factory\n// ============================================\n\nfunction createPushAdapter(\n config: MDMConfig['push'],\n database: MDMConfig['database'],\n logger: Logger,\n): PushAdapter {\n if (!config) {\n return createStubPushAdapter(logger);\n }\n\n const pushLogger = logger.child({ component: 'push' });\n\n // The actual implementations will be provided by separate packages\n // This is a base implementation that logs and stores tokens\n return {\n async send(deviceId: string, message: PushMessage): Promise<PushResult> {\n pushLogger.debug(\n { deviceId, type: message.type, payload: message.payload },\n 'send',\n );\n\n // In production, this would be replaced by FCM/MQTT adapter\n return { success: true, messageId: randomUUID() };\n },\n\n async sendBatch(\n deviceIds: string[],\n message: PushMessage\n ): Promise<PushBatchResult> {\n pushLogger.debug(\n { count: deviceIds.length, type: message.type },\n 'sendBatch',\n );\n\n const results = deviceIds.map((deviceId) => ({\n deviceId,\n result: { success: true, messageId: randomUUID() },\n }));\n\n return {\n successCount: deviceIds.length,\n failureCount: 0,\n results,\n };\n },\n\n async registerToken(deviceId: string, token: string): Promise<void> {\n // Polling doesn't use push tokens\n if (config.provider === 'polling') {\n return;\n }\n await database.upsertPushToken({\n deviceId,\n provider: config.provider,\n token,\n });\n },\n\n async unregisterToken(deviceId: string): Promise<void> {\n // Polling doesn't use push tokens\n if (config.provider === 'polling') {\n return;\n }\n await database.deletePushToken(deviceId, config.provider);\n },\n };\n}\n\nfunction createStubPushAdapter(logger: Logger): PushAdapter {\n const stubLogger = logger.child({ component: 'push-stub' });\n return {\n async send(deviceId: string, message: PushMessage): Promise<PushResult> {\n stubLogger.debug({ deviceId, type: message.type }, 'send (stub)');\n return { success: true, messageId: 'stub' };\n },\n\n async sendBatch(\n deviceIds: string[],\n message: PushMessage\n ): Promise<PushBatchResult> {\n stubLogger.debug(\n { count: deviceIds.length, type: message.type },\n 'sendBatch (stub)',\n );\n return {\n successCount: deviceIds.length,\n failureCount: 0,\n results: deviceIds.map((deviceId) => ({\n deviceId,\n result: { success: true, messageId: 'stub' },\n })),\n };\n },\n };\n}\n\n// ============================================\n// Utility Functions\n// ============================================\n\nexport function verifyEnrollmentSignature(\n request: EnrollmentRequest,\n secret: string\n): boolean {\n const { signature, ...data } = request;\n\n if (!signature) {\n return false;\n }\n\n // Reconstruct the message that was signed. This must stay in lockstep with\n // @openmdm/client's generateEnrollmentSignature — any change here is a wire\n // break and must land in both places. A contract test in core/tests guards\n // the format and will fail on divergence.\n const message = [\n data.model,\n data.manufacturer,\n data.osVersion,\n data.serialNumber || '',\n data.imei || '',\n data.macAddress || '',\n data.androidId || '',\n data.method,\n data.timestamp,\n ].join('|');\n\n const expectedSignature = createHmac('sha256', secret)\n .update(message)\n .digest('hex');\n\n try {\n return timingSafeEqual(\n Buffer.from(signature, 'hex'),\n Buffer.from(expectedSignature, 'hex')\n );\n } catch {\n return false;\n }\n}\n\nfunction generateDeviceToken(\n deviceId: string,\n secret: string,\n expirationSeconds: number\n): string {\n const header = Buffer.from(\n JSON.stringify({ alg: 'HS256', typ: 'JWT' })\n ).toString('base64url');\n\n const now = Math.floor(Date.now() / 1000);\n const payload = Buffer.from(\n JSON.stringify({\n sub: deviceId,\n iat: now,\n exp: now + expirationSeconds,\n iss: 'openmdm',\n })\n ).toString('base64url');\n\n const signature = createHmac('sha256', secret)\n .update(`${header}.${payload}`)\n .digest('base64url');\n\n return `${header}.${payload}.${signature}`;\n}\n"]}
|