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