@openmdm/core 0.2.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/LICENSE +21 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.js +1368 -0
- package/dist/index.js.map +1 -0
- package/dist/schema.d.ts +78 -0
- package/dist/schema.js +415 -0
- package/dist/schema.js.map +1 -0
- package/dist/types.d.ts +899 -0
- package/dist/types.js +49 -0
- package/dist/types.js.map +1 -0
- package/package.json +67 -0
- package/src/index.ts +1145 -0
- package/src/schema.ts +533 -0
- package/src/types.ts +1161 -0
- package/src/webhooks.ts +314 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,1161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenMDM Core Types
|
|
3
|
+
*
|
|
4
|
+
* These types define the core data structures for the MDM system.
|
|
5
|
+
* Designed to be database-agnostic and framework-agnostic.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ============================================
|
|
9
|
+
// Device Types
|
|
10
|
+
// ============================================
|
|
11
|
+
|
|
12
|
+
export type DeviceStatus = 'pending' | 'enrolled' | 'unenrolled' | 'blocked';
|
|
13
|
+
|
|
14
|
+
export interface Device {
|
|
15
|
+
id: string;
|
|
16
|
+
externalId?: string | null;
|
|
17
|
+
enrollmentId: string;
|
|
18
|
+
status: DeviceStatus;
|
|
19
|
+
|
|
20
|
+
// Device Info
|
|
21
|
+
model?: string | null;
|
|
22
|
+
manufacturer?: string | null;
|
|
23
|
+
osVersion?: string | null;
|
|
24
|
+
serialNumber?: string | null;
|
|
25
|
+
imei?: string | null;
|
|
26
|
+
macAddress?: string | null;
|
|
27
|
+
androidId?: string | null;
|
|
28
|
+
|
|
29
|
+
// MDM State
|
|
30
|
+
policyId?: string | null;
|
|
31
|
+
lastHeartbeat?: Date | null;
|
|
32
|
+
lastSync?: Date | null;
|
|
33
|
+
|
|
34
|
+
// Telemetry
|
|
35
|
+
batteryLevel?: number | null;
|
|
36
|
+
storageUsed?: number | null;
|
|
37
|
+
storageTotal?: number | null;
|
|
38
|
+
location?: DeviceLocation | null;
|
|
39
|
+
installedApps?: InstalledApp[] | null;
|
|
40
|
+
|
|
41
|
+
// Metadata
|
|
42
|
+
tags?: Record<string, string> | null;
|
|
43
|
+
metadata?: Record<string, unknown> | null;
|
|
44
|
+
|
|
45
|
+
// Timestamps
|
|
46
|
+
createdAt: Date;
|
|
47
|
+
updatedAt: Date;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface DeviceLocation {
|
|
51
|
+
latitude: number;
|
|
52
|
+
longitude: number;
|
|
53
|
+
accuracy?: number;
|
|
54
|
+
timestamp: Date;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface InstalledApp {
|
|
58
|
+
packageName: string;
|
|
59
|
+
version: string;
|
|
60
|
+
versionCode?: number;
|
|
61
|
+
installedAt?: Date;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface CreateDeviceInput {
|
|
65
|
+
enrollmentId: string;
|
|
66
|
+
externalId?: string;
|
|
67
|
+
model?: string;
|
|
68
|
+
manufacturer?: string;
|
|
69
|
+
osVersion?: string;
|
|
70
|
+
serialNumber?: string;
|
|
71
|
+
imei?: string;
|
|
72
|
+
macAddress?: string;
|
|
73
|
+
androidId?: string;
|
|
74
|
+
policyId?: string;
|
|
75
|
+
tags?: Record<string, string>;
|
|
76
|
+
metadata?: Record<string, unknown>;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface UpdateDeviceInput {
|
|
80
|
+
externalId?: string | null;
|
|
81
|
+
status?: DeviceStatus;
|
|
82
|
+
policyId?: string | null;
|
|
83
|
+
model?: string;
|
|
84
|
+
manufacturer?: string;
|
|
85
|
+
osVersion?: string;
|
|
86
|
+
batteryLevel?: number | null;
|
|
87
|
+
storageUsed?: number | null;
|
|
88
|
+
storageTotal?: number | null;
|
|
89
|
+
lastHeartbeat?: Date;
|
|
90
|
+
lastSync?: Date;
|
|
91
|
+
installedApps?: InstalledApp[];
|
|
92
|
+
location?: DeviceLocation;
|
|
93
|
+
tags?: Record<string, string>;
|
|
94
|
+
metadata?: Record<string, unknown>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface DeviceFilter {
|
|
98
|
+
status?: DeviceStatus | DeviceStatus[];
|
|
99
|
+
policyId?: string;
|
|
100
|
+
groupId?: string;
|
|
101
|
+
search?: string;
|
|
102
|
+
tags?: Record<string, string>;
|
|
103
|
+
limit?: number;
|
|
104
|
+
offset?: number;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface DeviceListResult {
|
|
108
|
+
devices: Device[];
|
|
109
|
+
total: number;
|
|
110
|
+
limit: number;
|
|
111
|
+
offset: number;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ============================================
|
|
115
|
+
// Policy Types
|
|
116
|
+
// ============================================
|
|
117
|
+
|
|
118
|
+
export interface Policy {
|
|
119
|
+
id: string;
|
|
120
|
+
name: string;
|
|
121
|
+
description?: string | null;
|
|
122
|
+
isDefault: boolean;
|
|
123
|
+
settings: PolicySettings;
|
|
124
|
+
createdAt: Date;
|
|
125
|
+
updatedAt: Date;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface PolicySettings {
|
|
129
|
+
// Kiosk Mode
|
|
130
|
+
kioskMode?: boolean;
|
|
131
|
+
mainApp?: string;
|
|
132
|
+
allowedApps?: string[];
|
|
133
|
+
kioskExitPassword?: string;
|
|
134
|
+
|
|
135
|
+
// Lock Features
|
|
136
|
+
lockStatusBar?: boolean;
|
|
137
|
+
lockNavigationBar?: boolean;
|
|
138
|
+
lockSettings?: boolean;
|
|
139
|
+
lockPowerButton?: boolean;
|
|
140
|
+
blockInstall?: boolean;
|
|
141
|
+
blockUninstall?: boolean;
|
|
142
|
+
|
|
143
|
+
// Hardware Controls
|
|
144
|
+
bluetooth?: HardwareControl;
|
|
145
|
+
wifi?: HardwareControl;
|
|
146
|
+
gps?: HardwareControl;
|
|
147
|
+
mobileData?: HardwareControl;
|
|
148
|
+
camera?: HardwareControl;
|
|
149
|
+
microphone?: HardwareControl;
|
|
150
|
+
usb?: HardwareControl;
|
|
151
|
+
nfc?: HardwareControl;
|
|
152
|
+
|
|
153
|
+
// Update Settings
|
|
154
|
+
systemUpdatePolicy?: SystemUpdatePolicy;
|
|
155
|
+
updateWindow?: TimeWindow;
|
|
156
|
+
|
|
157
|
+
// Security
|
|
158
|
+
passwordPolicy?: PasswordPolicy;
|
|
159
|
+
encryptionRequired?: boolean;
|
|
160
|
+
factoryResetProtection?: boolean;
|
|
161
|
+
safeBootDisabled?: boolean;
|
|
162
|
+
|
|
163
|
+
// Telemetry
|
|
164
|
+
heartbeatInterval?: number;
|
|
165
|
+
locationReportInterval?: number;
|
|
166
|
+
locationEnabled?: boolean;
|
|
167
|
+
|
|
168
|
+
// Network
|
|
169
|
+
wifiConfigs?: WifiConfig[];
|
|
170
|
+
vpnConfig?: VpnConfig;
|
|
171
|
+
|
|
172
|
+
// Applications
|
|
173
|
+
applications?: PolicyApplication[];
|
|
174
|
+
|
|
175
|
+
// Custom settings (for plugins)
|
|
176
|
+
custom?: Record<string, unknown>;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export type HardwareControl = 'on' | 'off' | 'user';
|
|
180
|
+
export type SystemUpdatePolicy = 'auto' | 'windowed' | 'postpone' | 'manual';
|
|
181
|
+
|
|
182
|
+
export interface TimeWindow {
|
|
183
|
+
start: string; // "HH:MM"
|
|
184
|
+
end: string; // "HH:MM"
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface PasswordPolicy {
|
|
188
|
+
required: boolean;
|
|
189
|
+
minLength?: number;
|
|
190
|
+
complexity?: 'none' | 'numeric' | 'alphanumeric' | 'complex';
|
|
191
|
+
maxFailedAttempts?: number;
|
|
192
|
+
expirationDays?: number;
|
|
193
|
+
historyLength?: number;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export interface WifiConfig {
|
|
197
|
+
ssid: string;
|
|
198
|
+
securityType: 'none' | 'wep' | 'wpa' | 'wpa2' | 'wpa3';
|
|
199
|
+
password?: string;
|
|
200
|
+
hidden?: boolean;
|
|
201
|
+
autoConnect?: boolean;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export interface VpnConfig {
|
|
205
|
+
type: 'pptp' | 'l2tp' | 'ipsec' | 'openvpn' | 'wireguard';
|
|
206
|
+
server: string;
|
|
207
|
+
username?: string;
|
|
208
|
+
password?: string;
|
|
209
|
+
certificate?: string;
|
|
210
|
+
config?: Record<string, unknown>;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export interface PolicyApplication {
|
|
214
|
+
packageName: string;
|
|
215
|
+
action: 'install' | 'update' | 'uninstall';
|
|
216
|
+
version?: string;
|
|
217
|
+
required?: boolean;
|
|
218
|
+
autoUpdate?: boolean;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export interface CreatePolicyInput {
|
|
222
|
+
name: string;
|
|
223
|
+
description?: string;
|
|
224
|
+
isDefault?: boolean;
|
|
225
|
+
settings: PolicySettings;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export interface UpdatePolicyInput {
|
|
229
|
+
name?: string;
|
|
230
|
+
description?: string | null;
|
|
231
|
+
isDefault?: boolean;
|
|
232
|
+
settings?: PolicySettings;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// ============================================
|
|
236
|
+
// Application Types
|
|
237
|
+
// ============================================
|
|
238
|
+
|
|
239
|
+
export interface Application {
|
|
240
|
+
id: string;
|
|
241
|
+
name: string;
|
|
242
|
+
packageName: string;
|
|
243
|
+
version: string;
|
|
244
|
+
versionCode: number;
|
|
245
|
+
url: string;
|
|
246
|
+
hash?: string | null;
|
|
247
|
+
size?: number | null;
|
|
248
|
+
minSdkVersion?: number | null;
|
|
249
|
+
|
|
250
|
+
// Deployment settings
|
|
251
|
+
showIcon: boolean;
|
|
252
|
+
runAfterInstall: boolean;
|
|
253
|
+
runAtBoot: boolean;
|
|
254
|
+
isSystem: boolean;
|
|
255
|
+
|
|
256
|
+
// State
|
|
257
|
+
isActive: boolean;
|
|
258
|
+
|
|
259
|
+
// Metadata
|
|
260
|
+
metadata?: Record<string, unknown> | null;
|
|
261
|
+
createdAt: Date;
|
|
262
|
+
updatedAt: Date;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export interface CreateApplicationInput {
|
|
266
|
+
name: string;
|
|
267
|
+
packageName: string;
|
|
268
|
+
version: string;
|
|
269
|
+
versionCode: number;
|
|
270
|
+
url: string;
|
|
271
|
+
hash?: string;
|
|
272
|
+
size?: number;
|
|
273
|
+
minSdkVersion?: number;
|
|
274
|
+
showIcon?: boolean;
|
|
275
|
+
runAfterInstall?: boolean;
|
|
276
|
+
runAtBoot?: boolean;
|
|
277
|
+
isSystem?: boolean;
|
|
278
|
+
metadata?: Record<string, unknown>;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export interface UpdateApplicationInput {
|
|
282
|
+
name?: string;
|
|
283
|
+
version?: string;
|
|
284
|
+
versionCode?: number;
|
|
285
|
+
url?: string;
|
|
286
|
+
hash?: string | null;
|
|
287
|
+
size?: number | null;
|
|
288
|
+
minSdkVersion?: number | null;
|
|
289
|
+
showIcon?: boolean;
|
|
290
|
+
runAfterInstall?: boolean;
|
|
291
|
+
runAtBoot?: boolean;
|
|
292
|
+
isActive?: boolean;
|
|
293
|
+
metadata?: Record<string, unknown> | null;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export interface DeployTarget {
|
|
297
|
+
devices?: string[];
|
|
298
|
+
policies?: string[];
|
|
299
|
+
groups?: string[];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// ============================================
|
|
303
|
+
// App Version & Rollback Types
|
|
304
|
+
// ============================================
|
|
305
|
+
|
|
306
|
+
export interface AppVersion {
|
|
307
|
+
id: string;
|
|
308
|
+
applicationId: string;
|
|
309
|
+
packageName: string;
|
|
310
|
+
version: string;
|
|
311
|
+
versionCode: number;
|
|
312
|
+
url: string;
|
|
313
|
+
hash?: string | null;
|
|
314
|
+
size?: number | null;
|
|
315
|
+
releaseNotes?: string | null;
|
|
316
|
+
isMinimumVersion: boolean;
|
|
317
|
+
createdAt: Date;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export interface AppRollback {
|
|
321
|
+
id: string;
|
|
322
|
+
deviceId: string;
|
|
323
|
+
packageName: string;
|
|
324
|
+
fromVersion: string;
|
|
325
|
+
fromVersionCode: number;
|
|
326
|
+
toVersion: string;
|
|
327
|
+
toVersionCode: number;
|
|
328
|
+
reason?: string | null;
|
|
329
|
+
status: 'pending' | 'in_progress' | 'completed' | 'failed';
|
|
330
|
+
error?: string | null;
|
|
331
|
+
initiatedBy?: string | null;
|
|
332
|
+
createdAt: Date;
|
|
333
|
+
completedAt?: Date | null;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export interface CreateAppRollbackInput {
|
|
337
|
+
deviceId: string;
|
|
338
|
+
packageName: string;
|
|
339
|
+
toVersionCode: number;
|
|
340
|
+
reason?: string;
|
|
341
|
+
initiatedBy?: string;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// ============================================
|
|
345
|
+
// Command Types
|
|
346
|
+
// ============================================
|
|
347
|
+
|
|
348
|
+
export type CommandType =
|
|
349
|
+
| 'reboot'
|
|
350
|
+
| 'shutdown'
|
|
351
|
+
| 'sync'
|
|
352
|
+
| 'lock'
|
|
353
|
+
| 'unlock'
|
|
354
|
+
| 'wipe'
|
|
355
|
+
| 'factoryReset'
|
|
356
|
+
| 'installApp'
|
|
357
|
+
| 'uninstallApp'
|
|
358
|
+
| 'updateApp'
|
|
359
|
+
| 'runApp'
|
|
360
|
+
| 'clearAppData'
|
|
361
|
+
| 'clearAppCache'
|
|
362
|
+
| 'shell'
|
|
363
|
+
| 'setPolicy'
|
|
364
|
+
| 'grantPermissions'
|
|
365
|
+
| 'exitKiosk'
|
|
366
|
+
| 'enterKiosk'
|
|
367
|
+
| 'setWifi'
|
|
368
|
+
| 'screenshot'
|
|
369
|
+
| 'getLocation'
|
|
370
|
+
| 'setVolume'
|
|
371
|
+
| 'sendNotification'
|
|
372
|
+
| 'whitelistBattery' // Whitelist app from battery optimization (Doze)
|
|
373
|
+
| 'enablePermissiveMode' // Enable permissive mode for debugging
|
|
374
|
+
| 'setTimeZone' // Set device timezone
|
|
375
|
+
| 'enableAdb' // Enable/disable ADB debugging
|
|
376
|
+
| 'rollbackApp' // Rollback to previous app version
|
|
377
|
+
| 'custom';
|
|
378
|
+
|
|
379
|
+
export type CommandStatus =
|
|
380
|
+
| 'pending'
|
|
381
|
+
| 'sent'
|
|
382
|
+
| 'acknowledged'
|
|
383
|
+
| 'completed'
|
|
384
|
+
| 'failed'
|
|
385
|
+
| 'cancelled';
|
|
386
|
+
|
|
387
|
+
export interface Command {
|
|
388
|
+
id: string;
|
|
389
|
+
deviceId: string;
|
|
390
|
+
type: CommandType;
|
|
391
|
+
payload?: Record<string, unknown> | null;
|
|
392
|
+
status: CommandStatus;
|
|
393
|
+
result?: CommandResult | null;
|
|
394
|
+
error?: string | null;
|
|
395
|
+
createdAt: Date;
|
|
396
|
+
sentAt?: Date | null;
|
|
397
|
+
acknowledgedAt?: Date | null;
|
|
398
|
+
completedAt?: Date | null;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export interface CommandResult {
|
|
402
|
+
success: boolean;
|
|
403
|
+
message?: string;
|
|
404
|
+
data?: unknown;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export interface SendCommandInput {
|
|
408
|
+
deviceId: string;
|
|
409
|
+
type: CommandType;
|
|
410
|
+
payload?: Record<string, unknown>;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export interface CommandFilter {
|
|
414
|
+
deviceId?: string;
|
|
415
|
+
status?: CommandStatus | CommandStatus[];
|
|
416
|
+
type?: CommandType | CommandType[];
|
|
417
|
+
limit?: number;
|
|
418
|
+
offset?: number;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// ============================================
|
|
422
|
+
// Event Types
|
|
423
|
+
// ============================================
|
|
424
|
+
|
|
425
|
+
export type EventType =
|
|
426
|
+
| 'device.enrolled'
|
|
427
|
+
| 'device.unenrolled'
|
|
428
|
+
| 'device.blocked'
|
|
429
|
+
| 'device.heartbeat'
|
|
430
|
+
| 'device.locationUpdated'
|
|
431
|
+
| 'device.statusChanged'
|
|
432
|
+
| 'device.policyChanged'
|
|
433
|
+
| 'app.installed'
|
|
434
|
+
| 'app.uninstalled'
|
|
435
|
+
| 'app.updated'
|
|
436
|
+
| 'app.crashed'
|
|
437
|
+
| 'app.started'
|
|
438
|
+
| 'app.stopped'
|
|
439
|
+
| 'policy.applied'
|
|
440
|
+
| 'policy.failed'
|
|
441
|
+
| 'command.received'
|
|
442
|
+
| 'command.acknowledged'
|
|
443
|
+
| 'command.completed'
|
|
444
|
+
| 'command.failed'
|
|
445
|
+
| 'security.tamper'
|
|
446
|
+
| 'security.rootDetected'
|
|
447
|
+
| 'security.screenLocked'
|
|
448
|
+
| 'security.screenUnlocked'
|
|
449
|
+
| 'custom';
|
|
450
|
+
|
|
451
|
+
export interface MDMEvent<T = unknown> {
|
|
452
|
+
id: string;
|
|
453
|
+
deviceId: string;
|
|
454
|
+
type: EventType;
|
|
455
|
+
payload: T;
|
|
456
|
+
createdAt: Date;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export interface EventFilter {
|
|
460
|
+
deviceId?: string;
|
|
461
|
+
type?: EventType | EventType[];
|
|
462
|
+
startDate?: Date;
|
|
463
|
+
endDate?: Date;
|
|
464
|
+
limit?: number;
|
|
465
|
+
offset?: number;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// ============================================
|
|
469
|
+
// Group Types
|
|
470
|
+
// ============================================
|
|
471
|
+
|
|
472
|
+
export interface Group {
|
|
473
|
+
id: string;
|
|
474
|
+
name: string;
|
|
475
|
+
description?: string | null;
|
|
476
|
+
policyId?: string | null;
|
|
477
|
+
parentId?: string | null;
|
|
478
|
+
metadata?: Record<string, unknown> | null;
|
|
479
|
+
createdAt: Date;
|
|
480
|
+
updatedAt: Date;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
export interface CreateGroupInput {
|
|
484
|
+
name: string;
|
|
485
|
+
description?: string;
|
|
486
|
+
policyId?: string;
|
|
487
|
+
parentId?: string;
|
|
488
|
+
metadata?: Record<string, unknown>;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
export interface UpdateGroupInput {
|
|
492
|
+
name?: string;
|
|
493
|
+
description?: string | null;
|
|
494
|
+
policyId?: string | null;
|
|
495
|
+
parentId?: string | null;
|
|
496
|
+
metadata?: Record<string, unknown> | null;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// ============================================
|
|
500
|
+
// Enrollment Types
|
|
501
|
+
// ============================================
|
|
502
|
+
|
|
503
|
+
export type EnrollmentMethod =
|
|
504
|
+
| 'qr'
|
|
505
|
+
| 'nfc'
|
|
506
|
+
| 'zero-touch'
|
|
507
|
+
| 'knox'
|
|
508
|
+
| 'manual'
|
|
509
|
+
| 'app-only'
|
|
510
|
+
| 'adb';
|
|
511
|
+
|
|
512
|
+
export interface EnrollmentRequest {
|
|
513
|
+
// Device identifiers (at least one required)
|
|
514
|
+
macAddress?: string;
|
|
515
|
+
serialNumber?: string;
|
|
516
|
+
imei?: string;
|
|
517
|
+
androidId?: string;
|
|
518
|
+
|
|
519
|
+
// Device info
|
|
520
|
+
model: string;
|
|
521
|
+
manufacturer: string;
|
|
522
|
+
osVersion: string;
|
|
523
|
+
sdkVersion?: number;
|
|
524
|
+
|
|
525
|
+
// Agent info
|
|
526
|
+
agentVersion?: string;
|
|
527
|
+
agentPackage?: string;
|
|
528
|
+
|
|
529
|
+
// Enrollment details
|
|
530
|
+
method: EnrollmentMethod;
|
|
531
|
+
timestamp: string;
|
|
532
|
+
signature: string;
|
|
533
|
+
|
|
534
|
+
// Optional pre-assigned policy/group
|
|
535
|
+
policyId?: string;
|
|
536
|
+
groupId?: string;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
export interface EnrollmentResponse {
|
|
540
|
+
deviceId: string;
|
|
541
|
+
enrollmentId: string;
|
|
542
|
+
policyId?: string;
|
|
543
|
+
policy?: Policy;
|
|
544
|
+
serverUrl: string;
|
|
545
|
+
pushConfig: PushConfig;
|
|
546
|
+
token: string;
|
|
547
|
+
refreshToken?: string;
|
|
548
|
+
tokenExpiresAt?: Date;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export interface PushConfig {
|
|
552
|
+
provider: 'fcm' | 'mqtt' | 'websocket' | 'polling';
|
|
553
|
+
fcmSenderId?: string;
|
|
554
|
+
mqttUrl?: string;
|
|
555
|
+
mqttTopic?: string;
|
|
556
|
+
mqttUsername?: string;
|
|
557
|
+
mqttPassword?: string;
|
|
558
|
+
wsUrl?: string;
|
|
559
|
+
pollingInterval?: number;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// ============================================
|
|
563
|
+
// Telemetry Types
|
|
564
|
+
// ============================================
|
|
565
|
+
|
|
566
|
+
export interface Heartbeat {
|
|
567
|
+
deviceId: string;
|
|
568
|
+
timestamp: Date;
|
|
569
|
+
|
|
570
|
+
// Battery
|
|
571
|
+
batteryLevel: number;
|
|
572
|
+
isCharging: boolean;
|
|
573
|
+
batteryHealth?: 'good' | 'overheat' | 'dead' | 'cold' | 'unknown';
|
|
574
|
+
|
|
575
|
+
// Storage
|
|
576
|
+
storageUsed: number;
|
|
577
|
+
storageTotal: number;
|
|
578
|
+
|
|
579
|
+
// Memory
|
|
580
|
+
memoryUsed: number;
|
|
581
|
+
memoryTotal: number;
|
|
582
|
+
|
|
583
|
+
// Network
|
|
584
|
+
networkType?: 'wifi' | 'cellular' | 'ethernet' | 'none';
|
|
585
|
+
networkName?: string; // SSID or carrier
|
|
586
|
+
signalStrength?: number;
|
|
587
|
+
ipAddress?: string;
|
|
588
|
+
|
|
589
|
+
// Location
|
|
590
|
+
location?: DeviceLocation;
|
|
591
|
+
|
|
592
|
+
// Apps
|
|
593
|
+
installedApps: InstalledApp[];
|
|
594
|
+
runningApps?: string[];
|
|
595
|
+
|
|
596
|
+
// Security
|
|
597
|
+
isRooted?: boolean;
|
|
598
|
+
isEncrypted?: boolean;
|
|
599
|
+
screenLockEnabled?: boolean;
|
|
600
|
+
|
|
601
|
+
// Agent status
|
|
602
|
+
agentVersion?: string;
|
|
603
|
+
policyVersion?: string;
|
|
604
|
+
lastPolicySync?: Date;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// ============================================
|
|
608
|
+
// Push Token Types
|
|
609
|
+
// ============================================
|
|
610
|
+
|
|
611
|
+
export interface PushToken {
|
|
612
|
+
id: string;
|
|
613
|
+
deviceId: string;
|
|
614
|
+
provider: 'fcm' | 'mqtt' | 'websocket';
|
|
615
|
+
token: string;
|
|
616
|
+
isActive: boolean;
|
|
617
|
+
createdAt: Date;
|
|
618
|
+
updatedAt: Date;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
export interface RegisterPushTokenInput {
|
|
622
|
+
deviceId: string;
|
|
623
|
+
provider: 'fcm' | 'mqtt' | 'websocket';
|
|
624
|
+
token: string;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// ============================================
|
|
628
|
+
// Configuration Types
|
|
629
|
+
// ============================================
|
|
630
|
+
|
|
631
|
+
export interface MDMConfig {
|
|
632
|
+
/** Database adapter for persistence */
|
|
633
|
+
database: DatabaseAdapter;
|
|
634
|
+
|
|
635
|
+
/** Authentication/authorization configuration */
|
|
636
|
+
auth?: AuthConfig;
|
|
637
|
+
|
|
638
|
+
/** Push notification provider configuration */
|
|
639
|
+
push?: PushProviderConfig;
|
|
640
|
+
|
|
641
|
+
/** Device enrollment configuration */
|
|
642
|
+
enrollment?: EnrollmentConfig;
|
|
643
|
+
|
|
644
|
+
/** Server URL (used in enrollment responses) */
|
|
645
|
+
serverUrl?: string;
|
|
646
|
+
|
|
647
|
+
/** APK/file storage configuration */
|
|
648
|
+
storage?: StorageConfig;
|
|
649
|
+
|
|
650
|
+
/** Outbound webhook configuration */
|
|
651
|
+
webhooks?: WebhookConfig;
|
|
652
|
+
|
|
653
|
+
/** Plugins to extend functionality */
|
|
654
|
+
plugins?: MDMPlugin[];
|
|
655
|
+
|
|
656
|
+
/** Event handlers */
|
|
657
|
+
onDeviceEnrolled?: (device: Device) => Promise<void>;
|
|
658
|
+
onDeviceUnenrolled?: (device: Device) => Promise<void>;
|
|
659
|
+
onDeviceBlocked?: (device: Device) => Promise<void>;
|
|
660
|
+
onHeartbeat?: (device: Device, heartbeat: Heartbeat) => Promise<void>;
|
|
661
|
+
onCommand?: (command: Command) => Promise<void>;
|
|
662
|
+
onEvent?: (event: MDMEvent) => Promise<void>;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
export interface StorageConfig {
|
|
666
|
+
/** Storage provider (s3, local, custom) */
|
|
667
|
+
provider: 's3' | 'local' | 'custom';
|
|
668
|
+
|
|
669
|
+
/** S3 configuration */
|
|
670
|
+
s3?: {
|
|
671
|
+
bucket: string;
|
|
672
|
+
region: string;
|
|
673
|
+
accessKeyId?: string;
|
|
674
|
+
secretAccessKey?: string;
|
|
675
|
+
endpoint?: string; // For S3-compatible services
|
|
676
|
+
presignedUrlExpiry?: number; // Seconds, default 3600
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
/** Local storage path */
|
|
680
|
+
localPath?: string;
|
|
681
|
+
|
|
682
|
+
/** Custom storage adapter */
|
|
683
|
+
customAdapter?: {
|
|
684
|
+
upload: (file: Buffer, key: string) => Promise<string>;
|
|
685
|
+
getUrl: (key: string) => Promise<string>;
|
|
686
|
+
delete: (key: string) => Promise<void>;
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
export interface WebhookConfig {
|
|
691
|
+
/** Webhook endpoints to notify */
|
|
692
|
+
endpoints?: WebhookEndpoint[];
|
|
693
|
+
|
|
694
|
+
/** Retry configuration */
|
|
695
|
+
retry?: {
|
|
696
|
+
maxRetries?: number;
|
|
697
|
+
initialDelay?: number;
|
|
698
|
+
maxDelay?: number;
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
/** Sign webhooks with HMAC secret */
|
|
702
|
+
signingSecret?: string;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
export interface WebhookEndpoint {
|
|
706
|
+
/** Unique identifier */
|
|
707
|
+
id: string;
|
|
708
|
+
/** Webhook URL */
|
|
709
|
+
url: string;
|
|
710
|
+
/** Events to trigger this webhook */
|
|
711
|
+
events: (EventType | '*')[];
|
|
712
|
+
/** Custom headers */
|
|
713
|
+
headers?: Record<string, string>;
|
|
714
|
+
/** Whether endpoint is active */
|
|
715
|
+
enabled: boolean;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
export interface AuthConfig {
|
|
719
|
+
/** Get current user from request context */
|
|
720
|
+
getUser: <T = unknown>(context: unknown) => Promise<T | null>;
|
|
721
|
+
/** Check if user has admin privileges */
|
|
722
|
+
isAdmin?: (user: unknown) => Promise<boolean>;
|
|
723
|
+
/** Check if user can access specific device */
|
|
724
|
+
canAccessDevice?: (user: unknown, deviceId: string) => Promise<boolean>;
|
|
725
|
+
/** Device JWT secret (for device auth tokens) */
|
|
726
|
+
deviceTokenSecret?: string;
|
|
727
|
+
/** Device token expiration in seconds (default: 365 days) */
|
|
728
|
+
deviceTokenExpiration?: number;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
export interface PushProviderConfig {
|
|
732
|
+
provider: 'fcm' | 'mqtt' | 'websocket' | 'polling';
|
|
733
|
+
|
|
734
|
+
// FCM configuration
|
|
735
|
+
fcmCredentials?: string | Record<string, unknown>;
|
|
736
|
+
fcmProjectId?: string;
|
|
737
|
+
|
|
738
|
+
// MQTT configuration
|
|
739
|
+
mqttUrl?: string;
|
|
740
|
+
mqttUsername?: string;
|
|
741
|
+
mqttPassword?: string;
|
|
742
|
+
mqttTopicPrefix?: string;
|
|
743
|
+
|
|
744
|
+
// WebSocket configuration
|
|
745
|
+
wsPath?: string;
|
|
746
|
+
wsPingInterval?: number;
|
|
747
|
+
|
|
748
|
+
// Polling fallback
|
|
749
|
+
pollingInterval?: number;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
export interface EnrollmentConfig {
|
|
753
|
+
/** Auto-enroll devices with valid signature */
|
|
754
|
+
autoEnroll?: boolean;
|
|
755
|
+
/** HMAC secret for device signature verification */
|
|
756
|
+
deviceSecret: string;
|
|
757
|
+
/** Allowed enrollment methods */
|
|
758
|
+
allowedMethods?: EnrollmentMethod[];
|
|
759
|
+
/** Default policy for new devices */
|
|
760
|
+
defaultPolicyId?: string;
|
|
761
|
+
/** Default group for new devices */
|
|
762
|
+
defaultGroupId?: string;
|
|
763
|
+
/** Require manual approval for enrollment */
|
|
764
|
+
requireApproval?: boolean;
|
|
765
|
+
/** Custom enrollment validation */
|
|
766
|
+
validate?: (request: EnrollmentRequest) => Promise<boolean>;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// ============================================
|
|
770
|
+
// Adapter Interfaces
|
|
771
|
+
// ============================================
|
|
772
|
+
|
|
773
|
+
export interface DatabaseAdapter {
|
|
774
|
+
// Devices
|
|
775
|
+
findDevice(id: string): Promise<Device | null>;
|
|
776
|
+
findDeviceByEnrollmentId(enrollmentId: string): Promise<Device | null>;
|
|
777
|
+
listDevices(filter?: DeviceFilter): Promise<DeviceListResult>;
|
|
778
|
+
createDevice(data: CreateDeviceInput): Promise<Device>;
|
|
779
|
+
updateDevice(id: string, data: UpdateDeviceInput): Promise<Device>;
|
|
780
|
+
deleteDevice(id: string): Promise<void>;
|
|
781
|
+
countDevices(filter?: DeviceFilter): Promise<number>;
|
|
782
|
+
|
|
783
|
+
// Policies
|
|
784
|
+
findPolicy(id: string): Promise<Policy | null>;
|
|
785
|
+
findDefaultPolicy(): Promise<Policy | null>;
|
|
786
|
+
listPolicies(): Promise<Policy[]>;
|
|
787
|
+
createPolicy(data: CreatePolicyInput): Promise<Policy>;
|
|
788
|
+
updatePolicy(id: string, data: UpdatePolicyInput): Promise<Policy>;
|
|
789
|
+
deletePolicy(id: string): Promise<void>;
|
|
790
|
+
|
|
791
|
+
// Applications
|
|
792
|
+
findApplication(id: string): Promise<Application | null>;
|
|
793
|
+
findApplicationByPackage(packageName: string, version?: string): Promise<Application | null>;
|
|
794
|
+
listApplications(activeOnly?: boolean): Promise<Application[]>;
|
|
795
|
+
createApplication(data: CreateApplicationInput): Promise<Application>;
|
|
796
|
+
updateApplication(id: string, data: UpdateApplicationInput): Promise<Application>;
|
|
797
|
+
deleteApplication(id: string): Promise<void>;
|
|
798
|
+
|
|
799
|
+
// Commands
|
|
800
|
+
findCommand(id: string): Promise<Command | null>;
|
|
801
|
+
listCommands(filter?: CommandFilter): Promise<Command[]>;
|
|
802
|
+
createCommand(data: SendCommandInput): Promise<Command>;
|
|
803
|
+
updateCommand(id: string, data: Partial<Command>): Promise<Command>;
|
|
804
|
+
getPendingCommands(deviceId: string): Promise<Command[]>;
|
|
805
|
+
|
|
806
|
+
// Events
|
|
807
|
+
createEvent(event: Omit<MDMEvent, 'id' | 'createdAt'>): Promise<MDMEvent>;
|
|
808
|
+
listEvents(filter?: EventFilter): Promise<MDMEvent[]>;
|
|
809
|
+
|
|
810
|
+
// Groups
|
|
811
|
+
findGroup(id: string): Promise<Group | null>;
|
|
812
|
+
listGroups(): Promise<Group[]>;
|
|
813
|
+
createGroup(data: CreateGroupInput): Promise<Group>;
|
|
814
|
+
updateGroup(id: string, data: UpdateGroupInput): Promise<Group>;
|
|
815
|
+
deleteGroup(id: string): Promise<void>;
|
|
816
|
+
listDevicesInGroup(groupId: string): Promise<Device[]>;
|
|
817
|
+
addDeviceToGroup(deviceId: string, groupId: string): Promise<void>;
|
|
818
|
+
removeDeviceFromGroup(deviceId: string, groupId: string): Promise<void>;
|
|
819
|
+
getDeviceGroups(deviceId: string): Promise<Group[]>;
|
|
820
|
+
|
|
821
|
+
// Push Tokens
|
|
822
|
+
findPushToken(deviceId: string, provider: string): Promise<PushToken | null>;
|
|
823
|
+
upsertPushToken(data: RegisterPushTokenInput): Promise<PushToken>;
|
|
824
|
+
deletePushToken(deviceId: string, provider?: string): Promise<void>;
|
|
825
|
+
|
|
826
|
+
// App Versions (optional - for version tracking)
|
|
827
|
+
listAppVersions?(packageName: string): Promise<AppVersion[]>;
|
|
828
|
+
createAppVersion?(data: Omit<AppVersion, 'id' | 'createdAt'>): Promise<AppVersion>;
|
|
829
|
+
setMinimumVersion?(packageName: string, versionCode: number): Promise<void>;
|
|
830
|
+
getMinimumVersion?(packageName: string): Promise<AppVersion | null>;
|
|
831
|
+
|
|
832
|
+
// Rollback History (optional)
|
|
833
|
+
createRollback?(data: CreateAppRollbackInput): Promise<AppRollback>;
|
|
834
|
+
updateRollback?(id: string, data: Partial<AppRollback>): Promise<AppRollback>;
|
|
835
|
+
listRollbacks?(filter?: { deviceId?: string; packageName?: string }): Promise<AppRollback[]>;
|
|
836
|
+
|
|
837
|
+
// Transactions (optional)
|
|
838
|
+
transaction?<T>(fn: () => Promise<T>): Promise<T>;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
export interface PushAdapter {
|
|
842
|
+
/** Send push message to a device */
|
|
843
|
+
send(deviceId: string, message: PushMessage): Promise<PushResult>;
|
|
844
|
+
/** Send push message to multiple devices */
|
|
845
|
+
sendBatch(deviceIds: string[], message: PushMessage): Promise<PushBatchResult>;
|
|
846
|
+
/** Register device push token */
|
|
847
|
+
registerToken?(deviceId: string, token: string): Promise<void>;
|
|
848
|
+
/** Unregister device push token */
|
|
849
|
+
unregisterToken?(deviceId: string): Promise<void>;
|
|
850
|
+
/** Subscribe device to topic */
|
|
851
|
+
subscribe?(deviceId: string, topic: string): Promise<void>;
|
|
852
|
+
/** Unsubscribe device from topic */
|
|
853
|
+
unsubscribe?(deviceId: string, topic: string): Promise<void>;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
export interface PushMessage {
|
|
857
|
+
type: string;
|
|
858
|
+
payload?: Record<string, unknown>;
|
|
859
|
+
priority?: 'high' | 'normal';
|
|
860
|
+
ttl?: number;
|
|
861
|
+
collapseKey?: string;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
export interface PushResult {
|
|
865
|
+
success: boolean;
|
|
866
|
+
messageId?: string;
|
|
867
|
+
error?: string;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
export interface PushBatchResult {
|
|
871
|
+
successCount: number;
|
|
872
|
+
failureCount: number;
|
|
873
|
+
results: Array<{ deviceId: string; result: PushResult }>;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// ============================================
|
|
877
|
+
// Plugin Interface
|
|
878
|
+
// ============================================
|
|
879
|
+
|
|
880
|
+
export interface MDMPlugin {
|
|
881
|
+
/** Unique plugin name */
|
|
882
|
+
name: string;
|
|
883
|
+
/** Plugin version */
|
|
884
|
+
version: string;
|
|
885
|
+
|
|
886
|
+
/** Called when MDM is initialized */
|
|
887
|
+
onInit?(mdm: MDMInstance): Promise<void>;
|
|
888
|
+
|
|
889
|
+
/** Called when MDM is destroyed */
|
|
890
|
+
onDestroy?(): Promise<void>;
|
|
891
|
+
|
|
892
|
+
/** Additional routes to mount */
|
|
893
|
+
routes?: PluginRoute[];
|
|
894
|
+
|
|
895
|
+
/** Middleware to apply to all routes */
|
|
896
|
+
middleware?: PluginMiddleware[];
|
|
897
|
+
|
|
898
|
+
/** Extend enrollment process */
|
|
899
|
+
onEnroll?(device: Device, request: EnrollmentRequest): Promise<void>;
|
|
900
|
+
|
|
901
|
+
/** Extend device processing */
|
|
902
|
+
onDeviceEnrolled?(device: Device): Promise<void>;
|
|
903
|
+
onDeviceUnenrolled?(device: Device): Promise<void>;
|
|
904
|
+
onHeartbeat?(device: Device, heartbeat: Heartbeat): Promise<void>;
|
|
905
|
+
|
|
906
|
+
/** Extend policy processing */
|
|
907
|
+
policySchema?: Record<string, unknown>;
|
|
908
|
+
validatePolicy?(settings: PolicySettings): Promise<{ valid: boolean; errors?: string[] }>;
|
|
909
|
+
applyPolicy?(device: Device, policy: Policy): Promise<void>;
|
|
910
|
+
|
|
911
|
+
/** Extend command processing */
|
|
912
|
+
commandTypes?: CommandType[];
|
|
913
|
+
executeCommand?(device: Device, command: Command): Promise<CommandResult>;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
export interface PluginRoute {
|
|
917
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
918
|
+
path: string;
|
|
919
|
+
handler: (context: unknown) => Promise<unknown>;
|
|
920
|
+
auth?: boolean;
|
|
921
|
+
admin?: boolean;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
export type PluginMiddleware = (
|
|
925
|
+
context: unknown,
|
|
926
|
+
next: () => Promise<unknown>
|
|
927
|
+
) => Promise<unknown>;
|
|
928
|
+
|
|
929
|
+
// ============================================
|
|
930
|
+
// MDM Instance Interface
|
|
931
|
+
// ============================================
|
|
932
|
+
|
|
933
|
+
export interface WebhookManager {
|
|
934
|
+
/** Deliver an event to all matching webhook endpoints */
|
|
935
|
+
deliver<T>(event: MDMEvent<T>): Promise<WebhookDeliveryResult[]>;
|
|
936
|
+
/** Add a webhook endpoint at runtime */
|
|
937
|
+
addEndpoint(endpoint: WebhookEndpoint): void;
|
|
938
|
+
/** Remove a webhook endpoint */
|
|
939
|
+
removeEndpoint(endpointId: string): void;
|
|
940
|
+
/** Update a webhook endpoint */
|
|
941
|
+
updateEndpoint(endpointId: string, updates: Partial<WebhookEndpoint>): void;
|
|
942
|
+
/** Get all configured endpoints */
|
|
943
|
+
getEndpoints(): WebhookEndpoint[];
|
|
944
|
+
/** Test a webhook endpoint with a test payload */
|
|
945
|
+
testEndpoint(endpointId: string): Promise<WebhookDeliveryResult>;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
export interface WebhookDeliveryResult {
|
|
949
|
+
endpointId: string;
|
|
950
|
+
success: boolean;
|
|
951
|
+
statusCode?: number;
|
|
952
|
+
error?: string;
|
|
953
|
+
retryCount: number;
|
|
954
|
+
deliveredAt?: Date;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
export interface MDMInstance {
|
|
958
|
+
/** Device management */
|
|
959
|
+
devices: DeviceManager;
|
|
960
|
+
/** Policy management */
|
|
961
|
+
policies: PolicyManager;
|
|
962
|
+
/** Application management */
|
|
963
|
+
apps: ApplicationManager;
|
|
964
|
+
/** Command management */
|
|
965
|
+
commands: CommandManager;
|
|
966
|
+
/** Group management */
|
|
967
|
+
groups: GroupManager;
|
|
968
|
+
|
|
969
|
+
/** Push notification service */
|
|
970
|
+
push: PushAdapter;
|
|
971
|
+
|
|
972
|
+
/** Webhook delivery (if configured) */
|
|
973
|
+
webhooks?: WebhookManager;
|
|
974
|
+
|
|
975
|
+
/** Database adapter */
|
|
976
|
+
db: DatabaseAdapter;
|
|
977
|
+
|
|
978
|
+
/** Configuration */
|
|
979
|
+
config: MDMConfig;
|
|
980
|
+
|
|
981
|
+
/** Subscribe to events */
|
|
982
|
+
on<T extends EventType>(event: T, handler: EventHandler<T>): () => void;
|
|
983
|
+
/** Emit an event */
|
|
984
|
+
emit<T extends EventType>(event: T, data: EventPayloadMap[T]): Promise<void>;
|
|
985
|
+
|
|
986
|
+
/** Process device enrollment */
|
|
987
|
+
enroll(request: EnrollmentRequest): Promise<EnrollmentResponse>;
|
|
988
|
+
/** Process device heartbeat */
|
|
989
|
+
processHeartbeat(deviceId: string, heartbeat: Heartbeat): Promise<void>;
|
|
990
|
+
/** Verify device token */
|
|
991
|
+
verifyDeviceToken(token: string): Promise<{ deviceId: string } | null>;
|
|
992
|
+
|
|
993
|
+
/** Get loaded plugins */
|
|
994
|
+
getPlugins(): MDMPlugin[];
|
|
995
|
+
/** Get plugin by name */
|
|
996
|
+
getPlugin(name: string): MDMPlugin | undefined;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
// ============================================
|
|
1000
|
+
// Manager Interfaces
|
|
1001
|
+
// ============================================
|
|
1002
|
+
|
|
1003
|
+
export interface DeviceManager {
|
|
1004
|
+
get(id: string): Promise<Device | null>;
|
|
1005
|
+
getByEnrollmentId(enrollmentId: string): Promise<Device | null>;
|
|
1006
|
+
list(filter?: DeviceFilter): Promise<DeviceListResult>;
|
|
1007
|
+
create(data: CreateDeviceInput): Promise<Device>;
|
|
1008
|
+
update(id: string, data: UpdateDeviceInput): Promise<Device>;
|
|
1009
|
+
delete(id: string): Promise<void>;
|
|
1010
|
+
assignPolicy(deviceId: string, policyId: string | null): Promise<Device>;
|
|
1011
|
+
addToGroup(deviceId: string, groupId: string): Promise<void>;
|
|
1012
|
+
removeFromGroup(deviceId: string, groupId: string): Promise<void>;
|
|
1013
|
+
getGroups(deviceId: string): Promise<Group[]>;
|
|
1014
|
+
sendCommand(deviceId: string, input: Omit<SendCommandInput, 'deviceId'>): Promise<Command>;
|
|
1015
|
+
sync(deviceId: string): Promise<Command>;
|
|
1016
|
+
reboot(deviceId: string): Promise<Command>;
|
|
1017
|
+
lock(deviceId: string, message?: string): Promise<Command>;
|
|
1018
|
+
wipe(deviceId: string, preserveData?: boolean): Promise<Command>;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
export interface PolicyManager {
|
|
1022
|
+
get(id: string): Promise<Policy | null>;
|
|
1023
|
+
getDefault(): Promise<Policy | null>;
|
|
1024
|
+
list(): Promise<Policy[]>;
|
|
1025
|
+
create(data: CreatePolicyInput): Promise<Policy>;
|
|
1026
|
+
update(id: string, data: UpdatePolicyInput): Promise<Policy>;
|
|
1027
|
+
delete(id: string): Promise<void>;
|
|
1028
|
+
setDefault(id: string): Promise<Policy>;
|
|
1029
|
+
getDevices(policyId: string): Promise<Device[]>;
|
|
1030
|
+
applyToDevice(policyId: string, deviceId: string): Promise<void>;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
export interface ApplicationManager {
|
|
1034
|
+
get(id: string): Promise<Application | null>;
|
|
1035
|
+
getByPackage(packageName: string, version?: string): Promise<Application | null>;
|
|
1036
|
+
list(activeOnly?: boolean): Promise<Application[]>;
|
|
1037
|
+
register(data: CreateApplicationInput): Promise<Application>;
|
|
1038
|
+
update(id: string, data: UpdateApplicationInput): Promise<Application>;
|
|
1039
|
+
delete(id: string): Promise<void>;
|
|
1040
|
+
activate(id: string): Promise<Application>;
|
|
1041
|
+
deactivate(id: string): Promise<Application>;
|
|
1042
|
+
deploy(packageName: string, target: DeployTarget): Promise<void>;
|
|
1043
|
+
installOnDevice(packageName: string, deviceId: string, version?: string): Promise<Command>;
|
|
1044
|
+
uninstallFromDevice(packageName: string, deviceId: string): Promise<Command>;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
export interface CommandManager {
|
|
1048
|
+
get(id: string): Promise<Command | null>;
|
|
1049
|
+
list(filter?: CommandFilter): Promise<Command[]>;
|
|
1050
|
+
send(input: SendCommandInput): Promise<Command>;
|
|
1051
|
+
cancel(id: string): Promise<Command>;
|
|
1052
|
+
acknowledge(id: string): Promise<Command>;
|
|
1053
|
+
complete(id: string, result: CommandResult): Promise<Command>;
|
|
1054
|
+
fail(id: string, error: string): Promise<Command>;
|
|
1055
|
+
getPending(deviceId: string): Promise<Command[]>;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
export interface GroupManager {
|
|
1059
|
+
get(id: string): Promise<Group | null>;
|
|
1060
|
+
list(): Promise<Group[]>;
|
|
1061
|
+
create(data: CreateGroupInput): Promise<Group>;
|
|
1062
|
+
update(id: string, data: UpdateGroupInput): Promise<Group>;
|
|
1063
|
+
delete(id: string): Promise<void>;
|
|
1064
|
+
getDevices(groupId: string): Promise<Device[]>;
|
|
1065
|
+
addDevice(groupId: string, deviceId: string): Promise<void>;
|
|
1066
|
+
removeDevice(groupId: string, deviceId: string): Promise<void>;
|
|
1067
|
+
getChildren(groupId: string): Promise<Group[]>;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// ============================================
|
|
1071
|
+
// Event Handler Types
|
|
1072
|
+
// ============================================
|
|
1073
|
+
|
|
1074
|
+
export type EventHandler<T extends EventType> = (
|
|
1075
|
+
event: MDMEvent<EventPayloadMap[T]>
|
|
1076
|
+
) => Promise<void> | void;
|
|
1077
|
+
|
|
1078
|
+
export interface EventPayloadMap {
|
|
1079
|
+
'device.enrolled': { device: Device };
|
|
1080
|
+
'device.unenrolled': { device: Device; reason?: string };
|
|
1081
|
+
'device.blocked': { device: Device; reason: string };
|
|
1082
|
+
'device.heartbeat': { device: Device; heartbeat: Heartbeat };
|
|
1083
|
+
'device.locationUpdated': { device: Device; location: DeviceLocation };
|
|
1084
|
+
'device.statusChanged': { device: Device; oldStatus: DeviceStatus; newStatus: DeviceStatus };
|
|
1085
|
+
'device.policyChanged': { device: Device; oldPolicyId?: string; newPolicyId?: string };
|
|
1086
|
+
'app.installed': { device: Device; app: InstalledApp };
|
|
1087
|
+
'app.uninstalled': { device: Device; packageName: string };
|
|
1088
|
+
'app.updated': { device: Device; app: InstalledApp; oldVersion: string };
|
|
1089
|
+
'app.crashed': { device: Device; packageName: string; error?: string };
|
|
1090
|
+
'app.started': { device: Device; packageName: string };
|
|
1091
|
+
'app.stopped': { device: Device; packageName: string };
|
|
1092
|
+
'policy.applied': { device: Device; policy: Policy };
|
|
1093
|
+
'policy.failed': { device: Device; policy: Policy; error: string };
|
|
1094
|
+
'command.received': { device: Device; command: Command };
|
|
1095
|
+
'command.acknowledged': { device: Device; command: Command };
|
|
1096
|
+
'command.completed': { device: Device; command: Command; result: CommandResult };
|
|
1097
|
+
'command.failed': { device: Device; command: Command; error: string };
|
|
1098
|
+
'security.tamper': { device: Device; type: string; details?: unknown };
|
|
1099
|
+
'security.rootDetected': { device: Device };
|
|
1100
|
+
'security.screenLocked': { device: Device };
|
|
1101
|
+
'security.screenUnlocked': { device: Device };
|
|
1102
|
+
custom: Record<string, unknown>;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
// ============================================
|
|
1106
|
+
// Error Types
|
|
1107
|
+
// ============================================
|
|
1108
|
+
|
|
1109
|
+
export class MDMError extends Error {
|
|
1110
|
+
constructor(
|
|
1111
|
+
message: string,
|
|
1112
|
+
public code: string,
|
|
1113
|
+
public statusCode: number = 500,
|
|
1114
|
+
public details?: unknown
|
|
1115
|
+
) {
|
|
1116
|
+
super(message);
|
|
1117
|
+
this.name = 'MDMError';
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
export class DeviceNotFoundError extends MDMError {
|
|
1122
|
+
constructor(deviceId: string) {
|
|
1123
|
+
super(`Device not found: ${deviceId}`, 'DEVICE_NOT_FOUND', 404);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
export class PolicyNotFoundError extends MDMError {
|
|
1128
|
+
constructor(policyId: string) {
|
|
1129
|
+
super(`Policy not found: ${policyId}`, 'POLICY_NOT_FOUND', 404);
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
export class ApplicationNotFoundError extends MDMError {
|
|
1134
|
+
constructor(identifier: string) {
|
|
1135
|
+
super(`Application not found: ${identifier}`, 'APPLICATION_NOT_FOUND', 404);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
export class EnrollmentError extends MDMError {
|
|
1140
|
+
constructor(message: string, details?: unknown) {
|
|
1141
|
+
super(message, 'ENROLLMENT_ERROR', 400, details);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
export class AuthenticationError extends MDMError {
|
|
1146
|
+
constructor(message: string = 'Authentication required') {
|
|
1147
|
+
super(message, 'AUTHENTICATION_ERROR', 401);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
export class AuthorizationError extends MDMError {
|
|
1152
|
+
constructor(message: string = 'Access denied') {
|
|
1153
|
+
super(message, 'AUTHORIZATION_ERROR', 403);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
export class ValidationError extends MDMError {
|
|
1158
|
+
constructor(message: string, details?: unknown) {
|
|
1159
|
+
super(message, 'VALIDATION_ERROR', 400, details);
|
|
1160
|
+
}
|
|
1161
|
+
}
|