@openmdm/core 0.2.0 → 0.4.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 +105 -3
- package/dist/index.js +1555 -41
- package/dist/index.js.map +1 -1
- package/dist/schema.d.ts +9 -0
- package/dist/schema.js +261 -0
- package/dist/schema.js.map +1 -1
- package/dist/types.d.ts +594 -2
- package/dist/types.js +21 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/audit.ts +317 -0
- package/src/authorization.ts +418 -0
- package/src/dashboard.ts +327 -0
- package/src/index.ts +222 -0
- package/src/plugin-storage.ts +128 -0
- package/src/queue.ts +161 -0
- package/src/schedule.ts +325 -0
- package/src/schema.ts +278 -0
- package/src/tenant.ts +237 -0
- package/src/types.ts +711 -0
package/src/types.ts
CHANGED
|
@@ -28,6 +28,7 @@ export interface Device {
|
|
|
28
28
|
|
|
29
29
|
// MDM State
|
|
30
30
|
policyId?: string | null;
|
|
31
|
+
agentVersion?: string | null; // MDM agent version installed on device
|
|
31
32
|
lastHeartbeat?: Date | null;
|
|
32
33
|
lastSync?: Date | null;
|
|
33
34
|
|
|
@@ -80,6 +81,7 @@ export interface UpdateDeviceInput {
|
|
|
80
81
|
externalId?: string | null;
|
|
81
82
|
status?: DeviceStatus;
|
|
82
83
|
policyId?: string | null;
|
|
84
|
+
agentVersion?: string | null;
|
|
83
85
|
model?: string;
|
|
84
86
|
manufacturer?: string;
|
|
85
87
|
osVersion?: string;
|
|
@@ -374,6 +376,7 @@ export type CommandType =
|
|
|
374
376
|
| 'setTimeZone' // Set device timezone
|
|
375
377
|
| 'enableAdb' // Enable/disable ADB debugging
|
|
376
378
|
| 'rollbackApp' // Rollback to previous app version
|
|
379
|
+
| 'updateAgent' // Update MDM agent to a new version
|
|
377
380
|
| 'custom';
|
|
378
381
|
|
|
379
382
|
export type CommandStatus =
|
|
@@ -660,6 +663,37 @@ export interface MDMConfig {
|
|
|
660
663
|
onHeartbeat?: (device: Device, heartbeat: Heartbeat) => Promise<void>;
|
|
661
664
|
onCommand?: (command: Command) => Promise<void>;
|
|
662
665
|
onEvent?: (event: MDMEvent) => Promise<void>;
|
|
666
|
+
|
|
667
|
+
// Enterprise features
|
|
668
|
+
/** Multi-tenancy configuration */
|
|
669
|
+
multiTenancy?: {
|
|
670
|
+
enabled: boolean;
|
|
671
|
+
defaultTenantId?: string;
|
|
672
|
+
tenantResolver?: (context: unknown) => Promise<string | null>;
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
/** Authorization (RBAC) configuration */
|
|
676
|
+
authorization?: {
|
|
677
|
+
enabled: boolean;
|
|
678
|
+
defaultRole?: string;
|
|
679
|
+
};
|
|
680
|
+
|
|
681
|
+
/** Audit logging configuration */
|
|
682
|
+
audit?: {
|
|
683
|
+
enabled: boolean;
|
|
684
|
+
retentionDays?: number;
|
|
685
|
+
};
|
|
686
|
+
|
|
687
|
+
/** Scheduling configuration */
|
|
688
|
+
scheduling?: {
|
|
689
|
+
enabled: boolean;
|
|
690
|
+
timezone?: string;
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
/** Plugin storage configuration */
|
|
694
|
+
pluginStorage?: {
|
|
695
|
+
adapter: 'database' | 'memory';
|
|
696
|
+
};
|
|
663
697
|
}
|
|
664
698
|
|
|
665
699
|
export interface StorageConfig {
|
|
@@ -834,6 +868,82 @@ export interface DatabaseAdapter {
|
|
|
834
868
|
updateRollback?(id: string, data: Partial<AppRollback>): Promise<AppRollback>;
|
|
835
869
|
listRollbacks?(filter?: { deviceId?: string; packageName?: string }): Promise<AppRollback[]>;
|
|
836
870
|
|
|
871
|
+
// Group Hierarchy (optional)
|
|
872
|
+
getGroupChildren?(parentId: string | null): Promise<Group[]>;
|
|
873
|
+
getGroupAncestors?(groupId: string): Promise<Group[]>;
|
|
874
|
+
getGroupDescendants?(groupId: string): Promise<Group[]>;
|
|
875
|
+
getGroupTree?(rootId?: string): Promise<GroupTreeNode[]>;
|
|
876
|
+
getGroupEffectivePolicy?(groupId: string): Promise<Policy | null>;
|
|
877
|
+
moveGroup?(groupId: string, newParentId: string | null): Promise<Group>;
|
|
878
|
+
getGroupHierarchyStats?(): Promise<GroupHierarchyStats>;
|
|
879
|
+
|
|
880
|
+
// Tenants (optional - for multi-tenancy)
|
|
881
|
+
findTenant?(id: string): Promise<Tenant | null>;
|
|
882
|
+
findTenantBySlug?(slug: string): Promise<Tenant | null>;
|
|
883
|
+
listTenants?(filter?: TenantFilter): Promise<TenantListResult>;
|
|
884
|
+
createTenant?(data: CreateTenantInput): Promise<Tenant>;
|
|
885
|
+
updateTenant?(id: string, data: UpdateTenantInput): Promise<Tenant>;
|
|
886
|
+
deleteTenant?(id: string): Promise<void>;
|
|
887
|
+
getTenantStats?(tenantId: string): Promise<TenantStats>;
|
|
888
|
+
|
|
889
|
+
// Users (optional - for RBAC)
|
|
890
|
+
findUser?(id: string): Promise<User | null>;
|
|
891
|
+
findUserByEmail?(email: string, tenantId?: string): Promise<User | null>;
|
|
892
|
+
listUsers?(filter?: UserFilter): Promise<UserListResult>;
|
|
893
|
+
createUser?(data: CreateUserInput): Promise<User>;
|
|
894
|
+
updateUser?(id: string, data: UpdateUserInput): Promise<User>;
|
|
895
|
+
deleteUser?(id: string): Promise<void>;
|
|
896
|
+
|
|
897
|
+
// Roles (optional - for RBAC)
|
|
898
|
+
findRole?(id: string): Promise<Role | null>;
|
|
899
|
+
listRoles?(tenantId?: string): Promise<Role[]>;
|
|
900
|
+
createRole?(data: CreateRoleInput): Promise<Role>;
|
|
901
|
+
updateRole?(id: string, data: UpdateRoleInput): Promise<Role>;
|
|
902
|
+
deleteRole?(id: string): Promise<void>;
|
|
903
|
+
assignRoleToUser?(userId: string, roleId: string): Promise<void>;
|
|
904
|
+
removeRoleFromUser?(userId: string, roleId: string): Promise<void>;
|
|
905
|
+
getUserRoles?(userId: string): Promise<Role[]>;
|
|
906
|
+
|
|
907
|
+
// Audit Logs (optional - for compliance)
|
|
908
|
+
createAuditLog?(data: CreateAuditLogInput): Promise<AuditLog>;
|
|
909
|
+
listAuditLogs?(filter?: AuditLogFilter): Promise<AuditLogListResult>;
|
|
910
|
+
deleteAuditLogs?(filter: { olderThan?: Date; tenantId?: string }): Promise<number>;
|
|
911
|
+
|
|
912
|
+
// Scheduled Tasks (optional - for scheduling)
|
|
913
|
+
findScheduledTask?(id: string): Promise<ScheduledTask | null>;
|
|
914
|
+
listScheduledTasks?(filter?: ScheduledTaskFilter): Promise<ScheduledTaskListResult>;
|
|
915
|
+
createScheduledTask?(data: CreateScheduledTaskInput): Promise<ScheduledTask>;
|
|
916
|
+
updateScheduledTask?(id: string, data: UpdateScheduledTaskInput): Promise<ScheduledTask>;
|
|
917
|
+
deleteScheduledTask?(id: string): Promise<void>;
|
|
918
|
+
getUpcomingTasks?(hours: number): Promise<ScheduledTask[]>;
|
|
919
|
+
createTaskExecution?(data: { taskId: string }): Promise<TaskExecution>;
|
|
920
|
+
updateTaskExecution?(id: string, data: Partial<TaskExecution>): Promise<TaskExecution>;
|
|
921
|
+
listTaskExecutions?(taskId: string, limit?: number): Promise<TaskExecution[]>;
|
|
922
|
+
|
|
923
|
+
// Message Queue (optional - for persistent messaging)
|
|
924
|
+
enqueueMessage?(data: EnqueueMessageInput): Promise<QueuedMessage>;
|
|
925
|
+
dequeueMessages?(deviceId: string, limit?: number): Promise<QueuedMessage[]>;
|
|
926
|
+
peekMessages?(deviceId: string, limit?: number): Promise<QueuedMessage[]>;
|
|
927
|
+
acknowledgeMessage?(messageId: string): Promise<void>;
|
|
928
|
+
failMessage?(messageId: string, error: string): Promise<void>;
|
|
929
|
+
retryFailedMessages?(maxAttempts?: number): Promise<number>;
|
|
930
|
+
purgeExpiredMessages?(): Promise<number>;
|
|
931
|
+
getQueueStats?(tenantId?: string): Promise<QueueStats>;
|
|
932
|
+
|
|
933
|
+
// Plugin Storage (optional)
|
|
934
|
+
getPluginValue?(pluginName: string, key: string): Promise<unknown | null>;
|
|
935
|
+
setPluginValue?(pluginName: string, key: string, value: unknown): Promise<void>;
|
|
936
|
+
deletePluginValue?(pluginName: string, key: string): Promise<void>;
|
|
937
|
+
listPluginKeys?(pluginName: string, prefix?: string): Promise<string[]>;
|
|
938
|
+
clearPluginData?(pluginName: string): Promise<void>;
|
|
939
|
+
|
|
940
|
+
// Dashboard (optional - for analytics)
|
|
941
|
+
getDashboardStats?(tenantId?: string): Promise<DashboardStats>;
|
|
942
|
+
getDeviceStatusBreakdown?(tenantId?: string): Promise<DeviceStatusBreakdown>;
|
|
943
|
+
getEnrollmentTrend?(days: number, tenantId?: string): Promise<EnrollmentTrendPoint[]>;
|
|
944
|
+
getCommandSuccessRates?(tenantId?: string): Promise<CommandSuccessRates>;
|
|
945
|
+
getAppInstallationSummary?(tenantId?: string): Promise<AppInstallationSummary>;
|
|
946
|
+
|
|
837
947
|
// Transactions (optional)
|
|
838
948
|
transaction?<T>(fn: () => Promise<T>): Promise<T>;
|
|
839
949
|
}
|
|
@@ -966,6 +1076,21 @@ export interface MDMInstance {
|
|
|
966
1076
|
/** Group management */
|
|
967
1077
|
groups: GroupManager;
|
|
968
1078
|
|
|
1079
|
+
/** Tenant management (if multi-tenancy enabled) */
|
|
1080
|
+
tenants?: TenantManager;
|
|
1081
|
+
/** Authorization management (RBAC) */
|
|
1082
|
+
authorization?: AuthorizationManager;
|
|
1083
|
+
/** Audit logging */
|
|
1084
|
+
audit?: AuditManager;
|
|
1085
|
+
/** Scheduled task management */
|
|
1086
|
+
schedules?: ScheduleManager;
|
|
1087
|
+
/** Persistent message queue */
|
|
1088
|
+
messageQueue?: MessageQueueManager;
|
|
1089
|
+
/** Dashboard analytics */
|
|
1090
|
+
dashboard?: DashboardManager;
|
|
1091
|
+
/** Plugin storage */
|
|
1092
|
+
pluginStorage?: PluginStorageAdapter;
|
|
1093
|
+
|
|
969
1094
|
/** Push notification service */
|
|
970
1095
|
push: PushAdapter;
|
|
971
1096
|
|
|
@@ -1056,15 +1181,577 @@ export interface CommandManager {
|
|
|
1056
1181
|
}
|
|
1057
1182
|
|
|
1058
1183
|
export interface GroupManager {
|
|
1184
|
+
// Basic CRUD operations
|
|
1059
1185
|
get(id: string): Promise<Group | null>;
|
|
1060
1186
|
list(): Promise<Group[]>;
|
|
1061
1187
|
create(data: CreateGroupInput): Promise<Group>;
|
|
1062
1188
|
update(id: string, data: UpdateGroupInput): Promise<Group>;
|
|
1063
1189
|
delete(id: string): Promise<void>;
|
|
1190
|
+
|
|
1191
|
+
// Device management
|
|
1064
1192
|
getDevices(groupId: string): Promise<Device[]>;
|
|
1065
1193
|
addDevice(groupId: string, deviceId: string): Promise<void>;
|
|
1066
1194
|
removeDevice(groupId: string, deviceId: string): Promise<void>;
|
|
1195
|
+
|
|
1196
|
+
// Hierarchy operations
|
|
1067
1197
|
getChildren(groupId: string): Promise<Group[]>;
|
|
1198
|
+
getTree(rootId?: string): Promise<GroupTreeNode[]>;
|
|
1199
|
+
getAncestors(groupId: string): Promise<Group[]>;
|
|
1200
|
+
getDescendants(groupId: string): Promise<Group[]>;
|
|
1201
|
+
move(groupId: string, newParentId: string | null): Promise<Group>;
|
|
1202
|
+
getEffectivePolicy(groupId: string): Promise<Policy | null>;
|
|
1203
|
+
getHierarchyStats(): Promise<GroupHierarchyStats>;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
// ============================================
|
|
1207
|
+
// Group Hierarchy Types
|
|
1208
|
+
// ============================================
|
|
1209
|
+
|
|
1210
|
+
export interface GroupTreeNode extends Group {
|
|
1211
|
+
children: GroupTreeNode[];
|
|
1212
|
+
depth: number;
|
|
1213
|
+
path: string[];
|
|
1214
|
+
effectivePolicyId?: string | null;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
export interface GroupHierarchyStats {
|
|
1218
|
+
totalGroups: number;
|
|
1219
|
+
maxDepth: number;
|
|
1220
|
+
groupsWithDevices: number;
|
|
1221
|
+
groupsWithPolicies: number;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
// ============================================
|
|
1225
|
+
// Tenant Types (Multi-tenancy)
|
|
1226
|
+
// ============================================
|
|
1227
|
+
|
|
1228
|
+
export type TenantStatus = 'active' | 'suspended' | 'pending';
|
|
1229
|
+
|
|
1230
|
+
export interface Tenant {
|
|
1231
|
+
id: string;
|
|
1232
|
+
name: string;
|
|
1233
|
+
slug: string;
|
|
1234
|
+
status: TenantStatus;
|
|
1235
|
+
settings?: TenantSettings | null;
|
|
1236
|
+
metadata?: Record<string, unknown> | null;
|
|
1237
|
+
createdAt: Date;
|
|
1238
|
+
updatedAt: Date;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
export interface TenantSettings {
|
|
1242
|
+
maxDevices?: number;
|
|
1243
|
+
maxUsers?: number;
|
|
1244
|
+
features?: string[];
|
|
1245
|
+
branding?: {
|
|
1246
|
+
logo?: string;
|
|
1247
|
+
primaryColor?: string;
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
export interface CreateTenantInput {
|
|
1252
|
+
name: string;
|
|
1253
|
+
slug: string;
|
|
1254
|
+
settings?: TenantSettings;
|
|
1255
|
+
metadata?: Record<string, unknown>;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
export interface UpdateTenantInput {
|
|
1259
|
+
name?: string;
|
|
1260
|
+
slug?: string;
|
|
1261
|
+
status?: TenantStatus;
|
|
1262
|
+
settings?: TenantSettings;
|
|
1263
|
+
metadata?: Record<string, unknown>;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
export interface TenantFilter {
|
|
1267
|
+
status?: TenantStatus;
|
|
1268
|
+
search?: string;
|
|
1269
|
+
limit?: number;
|
|
1270
|
+
offset?: number;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
export interface TenantListResult {
|
|
1274
|
+
tenants: Tenant[];
|
|
1275
|
+
total: number;
|
|
1276
|
+
limit: number;
|
|
1277
|
+
offset: number;
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
export interface TenantStats {
|
|
1281
|
+
deviceCount: number;
|
|
1282
|
+
userCount: number;
|
|
1283
|
+
policyCount: number;
|
|
1284
|
+
appCount: number;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
// ============================================
|
|
1288
|
+
// RBAC Types (Role-Based Access Control)
|
|
1289
|
+
// ============================================
|
|
1290
|
+
|
|
1291
|
+
export type PermissionAction = 'create' | 'read' | 'update' | 'delete' | 'manage' | '*';
|
|
1292
|
+
export type PermissionResource = 'devices' | 'policies' | 'apps' | 'groups' | 'commands' | 'users' | 'roles' | 'tenants' | 'audit' | '*';
|
|
1293
|
+
|
|
1294
|
+
export interface Permission {
|
|
1295
|
+
action: PermissionAction;
|
|
1296
|
+
resource: PermissionResource;
|
|
1297
|
+
resourceId?: string;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
export interface Role {
|
|
1301
|
+
id: string;
|
|
1302
|
+
tenantId?: string | null;
|
|
1303
|
+
name: string;
|
|
1304
|
+
description?: string | null;
|
|
1305
|
+
permissions: Permission[];
|
|
1306
|
+
isSystem: boolean;
|
|
1307
|
+
createdAt: Date;
|
|
1308
|
+
updatedAt: Date;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
export interface CreateRoleInput {
|
|
1312
|
+
tenantId?: string;
|
|
1313
|
+
name: string;
|
|
1314
|
+
description?: string;
|
|
1315
|
+
permissions: Permission[];
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
export interface UpdateRoleInput {
|
|
1319
|
+
name?: string;
|
|
1320
|
+
description?: string;
|
|
1321
|
+
permissions?: Permission[];
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
export interface User {
|
|
1325
|
+
id: string;
|
|
1326
|
+
tenantId?: string | null;
|
|
1327
|
+
email: string;
|
|
1328
|
+
name?: string | null;
|
|
1329
|
+
status: 'active' | 'inactive' | 'pending';
|
|
1330
|
+
metadata?: Record<string, unknown> | null;
|
|
1331
|
+
lastLoginAt?: Date | null;
|
|
1332
|
+
createdAt: Date;
|
|
1333
|
+
updatedAt: Date;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
export interface UserWithRoles extends User {
|
|
1337
|
+
roles: Role[];
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
export interface CreateUserInput {
|
|
1341
|
+
tenantId?: string;
|
|
1342
|
+
email: string;
|
|
1343
|
+
name?: string;
|
|
1344
|
+
status?: 'active' | 'inactive' | 'pending';
|
|
1345
|
+
metadata?: Record<string, unknown>;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
export interface UpdateUserInput {
|
|
1349
|
+
email?: string;
|
|
1350
|
+
name?: string;
|
|
1351
|
+
status?: 'active' | 'inactive' | 'pending';
|
|
1352
|
+
metadata?: Record<string, unknown>;
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
export interface UserFilter {
|
|
1356
|
+
tenantId?: string;
|
|
1357
|
+
status?: 'active' | 'inactive' | 'pending';
|
|
1358
|
+
search?: string;
|
|
1359
|
+
limit?: number;
|
|
1360
|
+
offset?: number;
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
export interface UserListResult {
|
|
1364
|
+
users: User[];
|
|
1365
|
+
total: number;
|
|
1366
|
+
limit: number;
|
|
1367
|
+
offset: number;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
// ============================================
|
|
1371
|
+
// Audit Types
|
|
1372
|
+
// ============================================
|
|
1373
|
+
|
|
1374
|
+
export type AuditAction = 'create' | 'read' | 'update' | 'delete' | 'login' | 'logout' | 'enroll' | 'unenroll' | 'command' | 'export' | 'import' | 'custom';
|
|
1375
|
+
|
|
1376
|
+
export interface AuditLog {
|
|
1377
|
+
id: string;
|
|
1378
|
+
tenantId?: string | null;
|
|
1379
|
+
userId?: string | null;
|
|
1380
|
+
action: AuditAction;
|
|
1381
|
+
resource: string;
|
|
1382
|
+
resourceId?: string | null;
|
|
1383
|
+
status: 'success' | 'failure';
|
|
1384
|
+
error?: string | null;
|
|
1385
|
+
details?: Record<string, unknown> | null;
|
|
1386
|
+
ipAddress?: string | null;
|
|
1387
|
+
userAgent?: string | null;
|
|
1388
|
+
createdAt: Date;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
export interface CreateAuditLogInput {
|
|
1392
|
+
tenantId?: string;
|
|
1393
|
+
userId?: string;
|
|
1394
|
+
action: AuditAction;
|
|
1395
|
+
resource: string;
|
|
1396
|
+
resourceId?: string;
|
|
1397
|
+
status?: 'success' | 'failure';
|
|
1398
|
+
error?: string;
|
|
1399
|
+
details?: Record<string, unknown>;
|
|
1400
|
+
ipAddress?: string;
|
|
1401
|
+
userAgent?: string;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
export interface AuditConfig {
|
|
1405
|
+
enabled: boolean;
|
|
1406
|
+
retentionDays?: number;
|
|
1407
|
+
skipReadOperations?: boolean;
|
|
1408
|
+
logActions?: AuditAction[];
|
|
1409
|
+
logResources?: string[];
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
export interface AuditSummary {
|
|
1413
|
+
totalLogs: number;
|
|
1414
|
+
byAction: Record<AuditAction, number>;
|
|
1415
|
+
byResource: Record<string, number>;
|
|
1416
|
+
byStatus: { success: number; failure: number };
|
|
1417
|
+
topUsers: Array<{ userId: string; count: number }>;
|
|
1418
|
+
recentFailures: AuditLog[];
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
export interface AuditLogFilter {
|
|
1422
|
+
tenantId?: string;
|
|
1423
|
+
userId?: string;
|
|
1424
|
+
action?: string;
|
|
1425
|
+
resource?: string;
|
|
1426
|
+
resourceId?: string;
|
|
1427
|
+
startDate?: Date;
|
|
1428
|
+
endDate?: Date;
|
|
1429
|
+
limit?: number;
|
|
1430
|
+
offset?: number;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
export interface AuditLogListResult {
|
|
1434
|
+
logs: AuditLog[];
|
|
1435
|
+
total: number;
|
|
1436
|
+
limit: number;
|
|
1437
|
+
offset: number;
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
// ============================================
|
|
1441
|
+
// Schedule Types
|
|
1442
|
+
// ============================================
|
|
1443
|
+
|
|
1444
|
+
export type TaskType = 'command' | 'policy_update' | 'app_install' | 'maintenance' | 'custom';
|
|
1445
|
+
export type ScheduledTaskStatus = 'active' | 'paused' | 'completed' | 'failed';
|
|
1446
|
+
|
|
1447
|
+
export interface MaintenanceWindow {
|
|
1448
|
+
daysOfWeek: number[];
|
|
1449
|
+
startTime: string;
|
|
1450
|
+
endTime: string;
|
|
1451
|
+
timezone: string;
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
export interface TaskSchedule {
|
|
1455
|
+
type: 'once' | 'recurring' | 'window';
|
|
1456
|
+
executeAt?: Date;
|
|
1457
|
+
cron?: string;
|
|
1458
|
+
window?: MaintenanceWindow;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
export interface ScheduledTask {
|
|
1462
|
+
id: string;
|
|
1463
|
+
tenantId?: string | null;
|
|
1464
|
+
name: string;
|
|
1465
|
+
description?: string | null;
|
|
1466
|
+
taskType: TaskType;
|
|
1467
|
+
schedule: TaskSchedule;
|
|
1468
|
+
target?: DeployTarget;
|
|
1469
|
+
payload?: Record<string, unknown> | null;
|
|
1470
|
+
status: ScheduledTaskStatus;
|
|
1471
|
+
nextRunAt?: Date | null;
|
|
1472
|
+
lastRunAt?: Date | null;
|
|
1473
|
+
maxRetries: number;
|
|
1474
|
+
retryCount: number;
|
|
1475
|
+
createdAt: Date;
|
|
1476
|
+
updatedAt: Date;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
export interface CreateScheduledTaskInput {
|
|
1480
|
+
tenantId?: string;
|
|
1481
|
+
name: string;
|
|
1482
|
+
description?: string;
|
|
1483
|
+
taskType: TaskType;
|
|
1484
|
+
schedule: TaskSchedule;
|
|
1485
|
+
target?: DeployTarget;
|
|
1486
|
+
payload?: Record<string, unknown>;
|
|
1487
|
+
maxRetries?: number;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
export interface UpdateScheduledTaskInput {
|
|
1491
|
+
name?: string;
|
|
1492
|
+
description?: string;
|
|
1493
|
+
schedule?: TaskSchedule;
|
|
1494
|
+
target?: DeployTarget;
|
|
1495
|
+
payload?: Record<string, unknown>;
|
|
1496
|
+
status?: ScheduledTaskStatus;
|
|
1497
|
+
maxRetries?: number;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
export interface ScheduledTaskFilter {
|
|
1501
|
+
tenantId?: string;
|
|
1502
|
+
taskType?: TaskType | TaskType[];
|
|
1503
|
+
status?: ScheduledTaskStatus | ScheduledTaskStatus[];
|
|
1504
|
+
limit?: number;
|
|
1505
|
+
offset?: number;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
export interface ScheduledTaskListResult {
|
|
1509
|
+
tasks: ScheduledTask[];
|
|
1510
|
+
total: number;
|
|
1511
|
+
limit: number;
|
|
1512
|
+
offset: number;
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
export interface TaskExecution {
|
|
1516
|
+
id: string;
|
|
1517
|
+
taskId: string;
|
|
1518
|
+
status: 'running' | 'completed' | 'failed';
|
|
1519
|
+
startedAt: Date;
|
|
1520
|
+
completedAt?: Date | null;
|
|
1521
|
+
devicesProcessed: number;
|
|
1522
|
+
devicesSucceeded: number;
|
|
1523
|
+
devicesFailed: number;
|
|
1524
|
+
error?: string | null;
|
|
1525
|
+
details?: Record<string, unknown> | null;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
// ============================================
|
|
1529
|
+
// Message Queue Types
|
|
1530
|
+
// ============================================
|
|
1531
|
+
|
|
1532
|
+
export type QueueMessageStatus = 'pending' | 'processing' | 'delivered' | 'failed' | 'expired';
|
|
1533
|
+
|
|
1534
|
+
export interface QueuedMessage {
|
|
1535
|
+
id: string;
|
|
1536
|
+
tenantId?: string | null;
|
|
1537
|
+
deviceId: string;
|
|
1538
|
+
messageType: string;
|
|
1539
|
+
payload: Record<string, unknown>;
|
|
1540
|
+
priority: 'high' | 'normal' | 'low';
|
|
1541
|
+
status: QueueMessageStatus;
|
|
1542
|
+
attempts: number;
|
|
1543
|
+
maxAttempts: number;
|
|
1544
|
+
lastAttemptAt?: Date | null;
|
|
1545
|
+
lastError?: string | null;
|
|
1546
|
+
expiresAt?: Date | null;
|
|
1547
|
+
createdAt: Date;
|
|
1548
|
+
updatedAt: Date;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
export interface EnqueueMessageInput {
|
|
1552
|
+
tenantId?: string;
|
|
1553
|
+
deviceId: string;
|
|
1554
|
+
messageType: string;
|
|
1555
|
+
payload: Record<string, unknown>;
|
|
1556
|
+
priority?: 'high' | 'normal' | 'low';
|
|
1557
|
+
maxAttempts?: number;
|
|
1558
|
+
ttlSeconds?: number;
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
export interface QueueStats {
|
|
1562
|
+
pending: number;
|
|
1563
|
+
processing: number;
|
|
1564
|
+
delivered: number;
|
|
1565
|
+
failed: number;
|
|
1566
|
+
expired: number;
|
|
1567
|
+
byDevice: Record<string, number>;
|
|
1568
|
+
oldestPending?: Date;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
// ============================================
|
|
1572
|
+
// Dashboard Types
|
|
1573
|
+
// ============================================
|
|
1574
|
+
|
|
1575
|
+
export interface DashboardStats {
|
|
1576
|
+
devices: {
|
|
1577
|
+
total: number;
|
|
1578
|
+
enrolled: number;
|
|
1579
|
+
active: number;
|
|
1580
|
+
blocked: number;
|
|
1581
|
+
pending: number;
|
|
1582
|
+
};
|
|
1583
|
+
policies: {
|
|
1584
|
+
total: number;
|
|
1585
|
+
deployed: number;
|
|
1586
|
+
};
|
|
1587
|
+
applications: {
|
|
1588
|
+
total: number;
|
|
1589
|
+
deployed: number;
|
|
1590
|
+
};
|
|
1591
|
+
commands: {
|
|
1592
|
+
pendingCount: number;
|
|
1593
|
+
last24hTotal: number;
|
|
1594
|
+
last24hSuccess: number;
|
|
1595
|
+
last24hFailed: number;
|
|
1596
|
+
};
|
|
1597
|
+
groups: {
|
|
1598
|
+
total: number;
|
|
1599
|
+
withDevices: number;
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
export interface DeviceStatusBreakdown {
|
|
1604
|
+
byStatus: Record<DeviceStatus, number>;
|
|
1605
|
+
byOs: Record<string, number>;
|
|
1606
|
+
byManufacturer: Record<string, number>;
|
|
1607
|
+
byModel: Record<string, number>;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
export interface EnrollmentTrendPoint {
|
|
1611
|
+
date: Date;
|
|
1612
|
+
enrolled: number;
|
|
1613
|
+
unenrolled: number;
|
|
1614
|
+
netChange: number;
|
|
1615
|
+
totalDevices: number;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
export interface CommandSuccessRates {
|
|
1619
|
+
overall: {
|
|
1620
|
+
total: number;
|
|
1621
|
+
completed: number;
|
|
1622
|
+
failed: number;
|
|
1623
|
+
successRate: number;
|
|
1624
|
+
};
|
|
1625
|
+
byType: Record<string, {
|
|
1626
|
+
total: number;
|
|
1627
|
+
completed: number;
|
|
1628
|
+
failed: number;
|
|
1629
|
+
successRate: number;
|
|
1630
|
+
avgExecutionTimeMs?: number;
|
|
1631
|
+
}>;
|
|
1632
|
+
last24h: {
|
|
1633
|
+
total: number;
|
|
1634
|
+
completed: number;
|
|
1635
|
+
failed: number;
|
|
1636
|
+
pending: number;
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
export interface AppInstallationSummary {
|
|
1641
|
+
total: number;
|
|
1642
|
+
byStatus: Record<string, number>;
|
|
1643
|
+
recentFailures: Array<{
|
|
1644
|
+
packageName: string;
|
|
1645
|
+
deviceId: string;
|
|
1646
|
+
error: string;
|
|
1647
|
+
timestamp: Date;
|
|
1648
|
+
}>;
|
|
1649
|
+
topInstalled: Array<{
|
|
1650
|
+
packageName: string;
|
|
1651
|
+
name: string;
|
|
1652
|
+
installedCount: number;
|
|
1653
|
+
}>;
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
// ============================================
|
|
1657
|
+
// Plugin Storage Types
|
|
1658
|
+
// ============================================
|
|
1659
|
+
|
|
1660
|
+
export interface PluginStorageAdapter {
|
|
1661
|
+
get<T>(pluginName: string, key: string): Promise<T | null>;
|
|
1662
|
+
set<T>(pluginName: string, key: string, value: T): Promise<void>;
|
|
1663
|
+
delete(pluginName: string, key: string): Promise<void>;
|
|
1664
|
+
list(pluginName: string, prefix?: string): Promise<string[]>;
|
|
1665
|
+
clear(pluginName: string): Promise<void>;
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
export interface PluginStorageEntry {
|
|
1669
|
+
pluginName: string;
|
|
1670
|
+
key: string;
|
|
1671
|
+
value: unknown;
|
|
1672
|
+
createdAt: Date;
|
|
1673
|
+
updatedAt: Date;
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
// ============================================
|
|
1677
|
+
// Enterprise Manager Interfaces
|
|
1678
|
+
// ============================================
|
|
1679
|
+
|
|
1680
|
+
export interface TenantManager {
|
|
1681
|
+
get(id: string): Promise<Tenant | null>;
|
|
1682
|
+
getBySlug(slug: string): Promise<Tenant | null>;
|
|
1683
|
+
list(filter?: TenantFilter): Promise<TenantListResult>;
|
|
1684
|
+
create(data: CreateTenantInput): Promise<Tenant>;
|
|
1685
|
+
update(id: string, data: UpdateTenantInput): Promise<Tenant>;
|
|
1686
|
+
delete(id: string, cascade?: boolean): Promise<void>;
|
|
1687
|
+
getStats(tenantId: string): Promise<TenantStats>;
|
|
1688
|
+
activate(id: string): Promise<Tenant>;
|
|
1689
|
+
deactivate(id: string): Promise<Tenant>;
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
export interface AuthorizationManager {
|
|
1693
|
+
createRole(data: CreateRoleInput): Promise<Role>;
|
|
1694
|
+
getRole(id: string): Promise<Role | null>;
|
|
1695
|
+
listRoles(tenantId?: string): Promise<Role[]>;
|
|
1696
|
+
updateRole(id: string, data: UpdateRoleInput): Promise<Role>;
|
|
1697
|
+
deleteRole(id: string): Promise<void>;
|
|
1698
|
+
createUser(data: CreateUserInput): Promise<User>;
|
|
1699
|
+
getUser(id: string): Promise<UserWithRoles | null>;
|
|
1700
|
+
getUserByEmail(email: string, tenantId?: string): Promise<UserWithRoles | null>;
|
|
1701
|
+
listUsers(filter?: UserFilter): Promise<UserListResult>;
|
|
1702
|
+
updateUser(id: string, data: UpdateUserInput): Promise<User>;
|
|
1703
|
+
deleteUser(id: string): Promise<void>;
|
|
1704
|
+
assignRole(userId: string, roleId: string): Promise<void>;
|
|
1705
|
+
removeRole(userId: string, roleId: string): Promise<void>;
|
|
1706
|
+
getUserRoles(userId: string): Promise<Role[]>;
|
|
1707
|
+
can(userId: string, action: PermissionAction, resource: PermissionResource, resourceId?: string): Promise<boolean>;
|
|
1708
|
+
canAny(userId: string, permissions: Array<{ action: PermissionAction; resource: PermissionResource }>): Promise<boolean>;
|
|
1709
|
+
requirePermission(userId: string, action: PermissionAction, resource: PermissionResource, resourceId?: string): Promise<void>;
|
|
1710
|
+
isAdmin(userId: string): Promise<boolean>;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
export interface AuditManager {
|
|
1714
|
+
log(entry: CreateAuditLogInput): Promise<AuditLog>;
|
|
1715
|
+
list(filter?: AuditLogFilter): Promise<AuditLogListResult>;
|
|
1716
|
+
getByResource(resource: string, resourceId: string): Promise<AuditLog[]>;
|
|
1717
|
+
getByUser(userId: string, filter?: AuditLogFilter): Promise<AuditLogListResult>;
|
|
1718
|
+
export(filter: AuditLogFilter, format: 'json' | 'csv'): Promise<string>;
|
|
1719
|
+
purge(olderThanDays?: number): Promise<number>;
|
|
1720
|
+
getSummary(tenantId?: string, days?: number): Promise<AuditSummary>;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
export interface ScheduleManager {
|
|
1724
|
+
get(id: string): Promise<ScheduledTask | null>;
|
|
1725
|
+
list(filter?: ScheduledTaskFilter): Promise<ScheduledTaskListResult>;
|
|
1726
|
+
create(data: CreateScheduledTaskInput): Promise<ScheduledTask>;
|
|
1727
|
+
update(id: string, data: UpdateScheduledTaskInput): Promise<ScheduledTask>;
|
|
1728
|
+
delete(id: string): Promise<void>;
|
|
1729
|
+
pause(id: string): Promise<ScheduledTask>;
|
|
1730
|
+
resume(id: string): Promise<ScheduledTask>;
|
|
1731
|
+
runNow(id: string): Promise<TaskExecution>;
|
|
1732
|
+
getUpcoming(hours: number): Promise<ScheduledTask[]>;
|
|
1733
|
+
getExecutions(taskId: string, limit?: number): Promise<TaskExecution[]>;
|
|
1734
|
+
calculateNextRun(schedule: TaskSchedule): Date | null;
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
export interface MessageQueueManager {
|
|
1738
|
+
enqueue(message: EnqueueMessageInput): Promise<QueuedMessage>;
|
|
1739
|
+
enqueueBatch(messages: EnqueueMessageInput[]): Promise<QueuedMessage[]>;
|
|
1740
|
+
dequeue(deviceId: string, limit?: number): Promise<QueuedMessage[]>;
|
|
1741
|
+
acknowledge(messageId: string): Promise<void>;
|
|
1742
|
+
fail(messageId: string, error: string): Promise<void>;
|
|
1743
|
+
retryFailed(maxAttempts?: number): Promise<number>;
|
|
1744
|
+
purgeExpired(): Promise<number>;
|
|
1745
|
+
getStats(tenantId?: string): Promise<QueueStats>;
|
|
1746
|
+
peek(deviceId: string, limit?: number): Promise<QueuedMessage[]>;
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
export interface DashboardManager {
|
|
1750
|
+
getStats(tenantId?: string): Promise<DashboardStats>;
|
|
1751
|
+
getDeviceStatusBreakdown(tenantId?: string): Promise<DeviceStatusBreakdown>;
|
|
1752
|
+
getEnrollmentTrend(days: number, tenantId?: string): Promise<EnrollmentTrendPoint[]>;
|
|
1753
|
+
getCommandSuccessRates(tenantId?: string): Promise<CommandSuccessRates>;
|
|
1754
|
+
getAppInstallationSummary(tenantId?: string): Promise<AppInstallationSummary>;
|
|
1068
1755
|
}
|
|
1069
1756
|
|
|
1070
1757
|
// ============================================
|
|
@@ -1136,6 +1823,30 @@ export class ApplicationNotFoundError extends MDMError {
|
|
|
1136
1823
|
}
|
|
1137
1824
|
}
|
|
1138
1825
|
|
|
1826
|
+
export class TenantNotFoundError extends MDMError {
|
|
1827
|
+
constructor(identifier: string) {
|
|
1828
|
+
super(`Tenant not found: ${identifier}`, 'TENANT_NOT_FOUND', 404);
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
export class RoleNotFoundError extends MDMError {
|
|
1833
|
+
constructor(identifier: string) {
|
|
1834
|
+
super(`Role not found: ${identifier}`, 'ROLE_NOT_FOUND', 404);
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
export class GroupNotFoundError extends MDMError {
|
|
1839
|
+
constructor(identifier: string) {
|
|
1840
|
+
super(`Group not found: ${identifier}`, 'GROUP_NOT_FOUND', 404);
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
export class UserNotFoundError extends MDMError {
|
|
1845
|
+
constructor(identifier: string) {
|
|
1846
|
+
super(`User not found: ${identifier}`, 'USER_NOT_FOUND', 404);
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1139
1850
|
export class EnrollmentError extends MDMError {
|
|
1140
1851
|
constructor(message: string, details?: unknown) {
|
|
1141
1852
|
super(message, 'ENROLLMENT_ERROR', 400, details);
|