@openmdm/cli 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/device-2DJ2HDTB.js +210 -0
- package/dist/device-2DJ2HDTB.js.map +1 -0
- package/dist/enroll-WDHCQQCE.js +111 -0
- package/dist/enroll-WDHCQQCE.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +78 -0
- package/dist/index.js.map +1 -0
- package/dist/init-625O2CRF.js +141 -0
- package/dist/init-625O2CRF.js.map +1 -0
- package/dist/migrate-HMECTTGA.js +245 -0
- package/dist/migrate-HMECTTGA.js.map +1 -0
- package/dist/policy-QGI5X7DH.js +222 -0
- package/dist/policy-QGI5X7DH.js.map +1 -0
- package/dist/push-GOOMUZVI.js +27 -0
- package/dist/push-GOOMUZVI.js.map +1 -0
- package/dist/stats-7LZFNZT2.js +78 -0
- package/dist/stats-7LZFNZT2.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/init.ts"],"sourcesContent":["import chalk from 'chalk';\nimport inquirer from 'inquirer';\nimport fs from 'fs/promises';\nimport path from 'path';\nimport ora from 'ora';\n\ninterface InitOptions {\n database: string;\n push: string;\n}\n\nconst TEMPLATE_ENV = `# OpenMDM Configuration\n# Generated by openmdm init\n\n# Database Configuration\nDATABASE_URL=postgres://user:password@localhost:5432/openmdm\n\n# Push Notification Configuration\nPUSH_PROVIDER={{push}}\n\n# FCM Configuration (if using FCM)\n# GOOGLE_APPLICATION_CREDENTIALS=./firebase-service-account.json\n# FIREBASE_PROJECT_ID=your-project-id\n\n# MQTT Configuration (if using MQTT)\n# MQTT_BROKER_URL=mqtt://localhost:1883\n# MQTT_USERNAME=\n# MQTT_PASSWORD=\n\n# Security\nDEVICE_SECRET={{deviceSecret}}\nJWT_SECRET={{jwtSecret}}\n\n# Server\nPORT=3000\nSERVER_URL=http://localhost:3000\n`;\n\nconst TEMPLATE_CONFIG = `import { createMDM } from '@openmdm/core';\nimport { drizzleAdapter } from '@openmdm/drizzle-adapter';\n{{pushImport}}\nimport { drizzle } from 'drizzle-orm/postgres-js';\nimport postgres from 'postgres';\n\n// Database connection\nconst connection = postgres(process.env.DATABASE_URL!);\nconst db = drizzle(connection);\n\n// Create MDM instance\nexport const mdm = createMDM({\n database: drizzleAdapter(db),\n {{pushConfig}}\n enrollment: {\n deviceSecret: process.env.DEVICE_SECRET!,\n autoEnroll: true,\n },\n auth: {\n deviceTokenSecret: process.env.JWT_SECRET!,\n },\n serverUrl: process.env.SERVER_URL,\n});\n`;\n\nexport async function initProject(options: InitOptions): Promise<void> {\n console.log(chalk.blue('\\\\nš Initializing OpenMDM Project\\\\n'));\n\n // Interactive prompts\n const answers = await inquirer.prompt([\n {\n type: 'input',\n name: 'projectName',\n message: 'Project name:',\n default: 'my-mdm-server',\n },\n {\n type: 'list',\n name: 'database',\n message: 'Database:',\n choices: ['postgres', 'mysql', 'sqlite'],\n default: options.database,\n },\n {\n type: 'list',\n name: 'push',\n message: 'Push notification provider:',\n choices: ['fcm', 'mqtt', 'polling'],\n default: options.push,\n },\n {\n type: 'confirm',\n name: 'createFiles',\n message: 'Create configuration files?',\n default: true,\n },\n ]);\n\n if (!answers.createFiles) {\n console.log(chalk.yellow('\\\\nSkipping file creation.'));\n return;\n }\n\n const spinner = ora('Creating configuration files...').start();\n\n try {\n // Generate secrets\n const deviceSecret = generateSecret(32);\n const jwtSecret = generateSecret(64);\n\n // Create .env file\n const envContent = TEMPLATE_ENV\n .replace('{{push}}', answers.push)\n .replace('{{deviceSecret}}', deviceSecret)\n .replace('{{jwtSecret}}', jwtSecret);\n\n await fs.writeFile('.env.example', envContent);\n spinner.succeed('Created .env.example');\n\n // Create config file\n let pushImport = '';\n let pushConfig = '';\n\n switch (answers.push) {\n case 'fcm':\n pushImport = \"import { fcmPushAdapterFromEnv } from '@openmdm/push-fcm';\";\n pushConfig = 'push: fcmPushAdapterFromEnv(),';\n break;\n case 'mqtt':\n pushImport = \"import { mqttPushAdapterFromEnv } from '@openmdm/push-mqtt';\";\n pushConfig = 'push: mqttPushAdapterFromEnv(),';\n break;\n default:\n pushConfig = '// No push provider configured';\n }\n\n const configContent = TEMPLATE_CONFIG\n .replace('{{pushImport}}', pushImport)\n .replace('{{pushConfig}}', pushConfig);\n\n await fs.mkdir('src', { recursive: true });\n await fs.writeFile('src/mdm.ts', configContent);\n spinner.succeed('Created src/mdm.ts');\n\n // Print next steps\n console.log(chalk.green('\\\\nā
OpenMDM project initialized!\\\\n'));\n console.log(chalk.white('Next steps:'));\n console.log(chalk.gray(' 1. Copy .env.example to .env and configure'));\n console.log(chalk.gray(' 2. Run database migrations: openmdm migrate'));\n console.log(chalk.gray(' 3. Start your server and integrate the MDM instance'));\n console.log('');\n } catch (error) {\n spinner.fail('Failed to create files');\n console.error(chalk.red(error));\n }\n}\n\nfunction generateSecret(length: number): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n let result = '';\n const randomArray = new Uint8Array(length);\n crypto.getRandomValues(randomArray);\n for (let i = 0; i < length; i++) {\n result += chars[randomArray[i] % chars.length];\n }\n return result;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/migrate.ts
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import ora from "ora";
|
|
6
|
+
var MIGRATION_SQL = `
|
|
7
|
+
-- OpenMDM Database Schema
|
|
8
|
+
-- PostgreSQL Migration
|
|
9
|
+
|
|
10
|
+
-- Device Status Enum
|
|
11
|
+
DO $$ BEGIN
|
|
12
|
+
CREATE TYPE mdm_device_status AS ENUM ('pending', 'enrolled', 'unenrolled', 'blocked');
|
|
13
|
+
EXCEPTION
|
|
14
|
+
WHEN duplicate_object THEN null;
|
|
15
|
+
END $$;
|
|
16
|
+
|
|
17
|
+
-- Command Status Enum
|
|
18
|
+
DO $$ BEGIN
|
|
19
|
+
CREATE TYPE mdm_command_status AS ENUM ('pending', 'sent', 'acknowledged', 'completed', 'failed', 'cancelled');
|
|
20
|
+
EXCEPTION
|
|
21
|
+
WHEN duplicate_object THEN null;
|
|
22
|
+
END $$;
|
|
23
|
+
|
|
24
|
+
-- Push Provider Enum
|
|
25
|
+
DO $$ BEGIN
|
|
26
|
+
CREATE TYPE mdm_push_provider AS ENUM ('fcm', 'mqtt', 'websocket');
|
|
27
|
+
EXCEPTION
|
|
28
|
+
WHEN duplicate_object THEN null;
|
|
29
|
+
END $$;
|
|
30
|
+
|
|
31
|
+
-- Devices Table
|
|
32
|
+
CREATE TABLE IF NOT EXISTS mdm_devices (
|
|
33
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
34
|
+
external_id VARCHAR(255),
|
|
35
|
+
enrollment_id VARCHAR(255) NOT NULL UNIQUE,
|
|
36
|
+
status mdm_device_status NOT NULL DEFAULT 'pending',
|
|
37
|
+
|
|
38
|
+
model VARCHAR(255),
|
|
39
|
+
manufacturer VARCHAR(255),
|
|
40
|
+
os_version VARCHAR(50),
|
|
41
|
+
serial_number VARCHAR(255),
|
|
42
|
+
imei VARCHAR(50),
|
|
43
|
+
mac_address VARCHAR(50),
|
|
44
|
+
android_id VARCHAR(255),
|
|
45
|
+
|
|
46
|
+
policy_id VARCHAR(255),
|
|
47
|
+
last_heartbeat TIMESTAMP,
|
|
48
|
+
last_sync TIMESTAMP,
|
|
49
|
+
|
|
50
|
+
battery_level INTEGER,
|
|
51
|
+
storage_used BIGINT,
|
|
52
|
+
storage_total BIGINT,
|
|
53
|
+
location JSONB,
|
|
54
|
+
installed_apps JSONB,
|
|
55
|
+
|
|
56
|
+
tags JSONB,
|
|
57
|
+
metadata JSONB,
|
|
58
|
+
|
|
59
|
+
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
60
|
+
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
-- Policies Table
|
|
64
|
+
CREATE TABLE IF NOT EXISTS mdm_policies (
|
|
65
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
66
|
+
name VARCHAR(255) NOT NULL,
|
|
67
|
+
description TEXT,
|
|
68
|
+
is_default BOOLEAN NOT NULL DEFAULT false,
|
|
69
|
+
settings JSONB NOT NULL DEFAULT '{}',
|
|
70
|
+
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
71
|
+
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
-- Applications Table
|
|
75
|
+
CREATE TABLE IF NOT EXISTS mdm_applications (
|
|
76
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
77
|
+
name VARCHAR(255) NOT NULL,
|
|
78
|
+
package_name VARCHAR(255) NOT NULL,
|
|
79
|
+
version VARCHAR(50) NOT NULL,
|
|
80
|
+
version_code INTEGER NOT NULL,
|
|
81
|
+
url TEXT NOT NULL,
|
|
82
|
+
hash VARCHAR(255),
|
|
83
|
+
size BIGINT,
|
|
84
|
+
min_sdk_version INTEGER,
|
|
85
|
+
|
|
86
|
+
show_icon BOOLEAN NOT NULL DEFAULT true,
|
|
87
|
+
run_after_install BOOLEAN NOT NULL DEFAULT false,
|
|
88
|
+
run_at_boot BOOLEAN NOT NULL DEFAULT false,
|
|
89
|
+
is_system BOOLEAN NOT NULL DEFAULT false,
|
|
90
|
+
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
91
|
+
|
|
92
|
+
metadata JSONB,
|
|
93
|
+
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
94
|
+
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
-- Commands Table
|
|
98
|
+
CREATE TABLE IF NOT EXISTS mdm_commands (
|
|
99
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
100
|
+
device_id VARCHAR(255) NOT NULL REFERENCES mdm_devices(id) ON DELETE CASCADE,
|
|
101
|
+
type VARCHAR(50) NOT NULL,
|
|
102
|
+
payload JSONB,
|
|
103
|
+
status mdm_command_status NOT NULL DEFAULT 'pending',
|
|
104
|
+
result JSONB,
|
|
105
|
+
error TEXT,
|
|
106
|
+
|
|
107
|
+
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
108
|
+
sent_at TIMESTAMP,
|
|
109
|
+
acknowledged_at TIMESTAMP,
|
|
110
|
+
completed_at TIMESTAMP
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
-- Events Table
|
|
114
|
+
CREATE TABLE IF NOT EXISTS mdm_events (
|
|
115
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
116
|
+
device_id VARCHAR(255) NOT NULL REFERENCES mdm_devices(id) ON DELETE CASCADE,
|
|
117
|
+
type VARCHAR(100) NOT NULL,
|
|
118
|
+
payload JSONB NOT NULL DEFAULT '{}',
|
|
119
|
+
created_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
-- Groups Table
|
|
123
|
+
CREATE TABLE IF NOT EXISTS mdm_groups (
|
|
124
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
125
|
+
name VARCHAR(255) NOT NULL,
|
|
126
|
+
description TEXT,
|
|
127
|
+
policy_id VARCHAR(255) REFERENCES mdm_policies(id) ON DELETE SET NULL,
|
|
128
|
+
parent_id VARCHAR(255) REFERENCES mdm_groups(id) ON DELETE SET NULL,
|
|
129
|
+
metadata JSONB,
|
|
130
|
+
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
131
|
+
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
-- Device Groups Junction Table
|
|
135
|
+
CREATE TABLE IF NOT EXISTS mdm_device_groups (
|
|
136
|
+
device_id VARCHAR(255) NOT NULL REFERENCES mdm_devices(id) ON DELETE CASCADE,
|
|
137
|
+
group_id VARCHAR(255) NOT NULL REFERENCES mdm_groups(id) ON DELETE CASCADE,
|
|
138
|
+
PRIMARY KEY (device_id, group_id)
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
-- Push Tokens Table
|
|
142
|
+
CREATE TABLE IF NOT EXISTS mdm_push_tokens (
|
|
143
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
144
|
+
device_id VARCHAR(255) NOT NULL REFERENCES mdm_devices(id) ON DELETE CASCADE,
|
|
145
|
+
provider mdm_push_provider NOT NULL,
|
|
146
|
+
token TEXT NOT NULL,
|
|
147
|
+
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
148
|
+
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
149
|
+
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
|
150
|
+
UNIQUE(device_id, provider)
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
-- App Deployments Table
|
|
154
|
+
CREATE TABLE IF NOT EXISTS mdm_app_deployments (
|
|
155
|
+
id VARCHAR(255) PRIMARY KEY,
|
|
156
|
+
application_id VARCHAR(255) NOT NULL REFERENCES mdm_applications(id) ON DELETE CASCADE,
|
|
157
|
+
target_type VARCHAR(20) NOT NULL, -- 'device', 'policy', 'group'
|
|
158
|
+
target_id VARCHAR(255) NOT NULL,
|
|
159
|
+
created_at TIMESTAMP NOT NULL DEFAULT NOW()
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
-- Indexes
|
|
163
|
+
CREATE INDEX IF NOT EXISTS idx_devices_status ON mdm_devices(status);
|
|
164
|
+
CREATE INDEX IF NOT EXISTS idx_devices_policy ON mdm_devices(policy_id);
|
|
165
|
+
CREATE INDEX IF NOT EXISTS idx_devices_enrollment ON mdm_devices(enrollment_id);
|
|
166
|
+
CREATE INDEX IF NOT EXISTS idx_devices_last_heartbeat ON mdm_devices(last_heartbeat);
|
|
167
|
+
|
|
168
|
+
CREATE INDEX IF NOT EXISTS idx_commands_device ON mdm_commands(device_id);
|
|
169
|
+
CREATE INDEX IF NOT EXISTS idx_commands_status ON mdm_commands(status);
|
|
170
|
+
CREATE INDEX IF NOT EXISTS idx_commands_device_status ON mdm_commands(device_id, status);
|
|
171
|
+
|
|
172
|
+
CREATE INDEX IF NOT EXISTS idx_events_device ON mdm_events(device_id);
|
|
173
|
+
CREATE INDEX IF NOT EXISTS idx_events_type ON mdm_events(type);
|
|
174
|
+
CREATE INDEX IF NOT EXISTS idx_events_created ON mdm_events(created_at);
|
|
175
|
+
|
|
176
|
+
CREATE INDEX IF NOT EXISTS idx_applications_package ON mdm_applications(package_name);
|
|
177
|
+
CREATE INDEX IF NOT EXISTS idx_push_tokens_device ON mdm_push_tokens(device_id);
|
|
178
|
+
`;
|
|
179
|
+
var ROLLBACK_SQL = `
|
|
180
|
+
-- OpenMDM Database Rollback
|
|
181
|
+
|
|
182
|
+
DROP TABLE IF EXISTS mdm_app_deployments;
|
|
183
|
+
DROP TABLE IF EXISTS mdm_push_tokens;
|
|
184
|
+
DROP TABLE IF EXISTS mdm_device_groups;
|
|
185
|
+
DROP TABLE IF EXISTS mdm_events;
|
|
186
|
+
DROP TABLE IF EXISTS mdm_commands;
|
|
187
|
+
DROP TABLE IF EXISTS mdm_applications;
|
|
188
|
+
DROP TABLE IF EXISTS mdm_groups;
|
|
189
|
+
DROP TABLE IF EXISTS mdm_devices;
|
|
190
|
+
DROP TABLE IF EXISTS mdm_policies;
|
|
191
|
+
|
|
192
|
+
DROP TYPE IF EXISTS mdm_push_provider;
|
|
193
|
+
DROP TYPE IF EXISTS mdm_command_status;
|
|
194
|
+
DROP TYPE IF EXISTS mdm_device_status;
|
|
195
|
+
`;
|
|
196
|
+
async function runMigrations(options) {
|
|
197
|
+
console.log(chalk.blue("\\n\u{1F4E6} OpenMDM Database Migration\\n"));
|
|
198
|
+
const databaseUrl = process.env.DATABASE_URL;
|
|
199
|
+
if (!databaseUrl && !options.dryRun) {
|
|
200
|
+
console.error(chalk.red("Error: DATABASE_URL environment variable is required"));
|
|
201
|
+
console.log(chalk.gray("Set it in your .env file or export it before running migrations."));
|
|
202
|
+
process.exit(1);
|
|
203
|
+
}
|
|
204
|
+
if (options.rollback) {
|
|
205
|
+
console.log(chalk.yellow("\u26A0\uFE0F Rolling back migrations...\\n"));
|
|
206
|
+
if (options.dryRun) {
|
|
207
|
+
console.log(chalk.gray("SQL to execute:"));
|
|
208
|
+
console.log(ROLLBACK_SQL);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const spinner2 = ora("Rolling back...").start();
|
|
212
|
+
try {
|
|
213
|
+
console.log(chalk.gray("\\nRollback SQL:"));
|
|
214
|
+
console.log(ROLLBACK_SQL);
|
|
215
|
+
spinner2.succeed("Rollback SQL generated");
|
|
216
|
+
console.log(chalk.yellow("\\n\u26A0\uFE0F Execute the above SQL manually or use a database client."));
|
|
217
|
+
} catch (error) {
|
|
218
|
+
spinner2.fail("Rollback failed");
|
|
219
|
+
console.error(chalk.red(error));
|
|
220
|
+
}
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (options.dryRun) {
|
|
224
|
+
console.log(chalk.gray("SQL to execute:"));
|
|
225
|
+
console.log(MIGRATION_SQL);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const spinner = ora("Running migrations...").start();
|
|
229
|
+
try {
|
|
230
|
+
console.log(chalk.gray("\\nMigration SQL:"));
|
|
231
|
+
console.log(MIGRATION_SQL);
|
|
232
|
+
spinner.succeed("Migration SQL generated");
|
|
233
|
+
console.log(chalk.green("\\n\u2705 Migration complete!"));
|
|
234
|
+
console.log(chalk.gray("\\nExecute the above SQL against your database,"));
|
|
235
|
+
console.log(chalk.gray("or integrate with Drizzle Kit for automated migrations:"));
|
|
236
|
+
console.log(chalk.gray(" npx drizzle-kit push:pg"));
|
|
237
|
+
} catch (error) {
|
|
238
|
+
spinner.fail("Migration failed");
|
|
239
|
+
console.error(chalk.red(error));
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
export {
|
|
243
|
+
runMigrations
|
|
244
|
+
};
|
|
245
|
+
//# sourceMappingURL=migrate-HMECTTGA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/migrate.ts"],"sourcesContent":["import chalk from 'chalk';\nimport ora from 'ora';\n\ninterface MigrateOptions {\n dryRun?: boolean;\n rollback?: boolean;\n}\n\nconst MIGRATION_SQL = `\n-- OpenMDM Database Schema\n-- PostgreSQL Migration\n\n-- Device Status Enum\nDO $$ BEGIN\n CREATE TYPE mdm_device_status AS ENUM ('pending', 'enrolled', 'unenrolled', 'blocked');\nEXCEPTION\n WHEN duplicate_object THEN null;\nEND $$;\n\n-- Command Status Enum\nDO $$ BEGIN\n CREATE TYPE mdm_command_status AS ENUM ('pending', 'sent', 'acknowledged', 'completed', 'failed', 'cancelled');\nEXCEPTION\n WHEN duplicate_object THEN null;\nEND $$;\n\n-- Push Provider Enum\nDO $$ BEGIN\n CREATE TYPE mdm_push_provider AS ENUM ('fcm', 'mqtt', 'websocket');\nEXCEPTION\n WHEN duplicate_object THEN null;\nEND $$;\n\n-- Devices Table\nCREATE TABLE IF NOT EXISTS mdm_devices (\n id VARCHAR(255) PRIMARY KEY,\n external_id VARCHAR(255),\n enrollment_id VARCHAR(255) NOT NULL UNIQUE,\n status mdm_device_status NOT NULL DEFAULT 'pending',\n\n model VARCHAR(255),\n manufacturer VARCHAR(255),\n os_version VARCHAR(50),\n serial_number VARCHAR(255),\n imei VARCHAR(50),\n mac_address VARCHAR(50),\n android_id VARCHAR(255),\n\n policy_id VARCHAR(255),\n last_heartbeat TIMESTAMP,\n last_sync TIMESTAMP,\n\n battery_level INTEGER,\n storage_used BIGINT,\n storage_total BIGINT,\n location JSONB,\n installed_apps JSONB,\n\n tags JSONB,\n metadata JSONB,\n\n created_at TIMESTAMP NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMP NOT NULL DEFAULT NOW()\n);\n\n-- Policies Table\nCREATE TABLE IF NOT EXISTS mdm_policies (\n id VARCHAR(255) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n description TEXT,\n is_default BOOLEAN NOT NULL DEFAULT false,\n settings JSONB NOT NULL DEFAULT '{}',\n created_at TIMESTAMP NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMP NOT NULL DEFAULT NOW()\n);\n\n-- Applications Table\nCREATE TABLE IF NOT EXISTS mdm_applications (\n id VARCHAR(255) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n package_name VARCHAR(255) NOT NULL,\n version VARCHAR(50) NOT NULL,\n version_code INTEGER NOT NULL,\n url TEXT NOT NULL,\n hash VARCHAR(255),\n size BIGINT,\n min_sdk_version INTEGER,\n\n show_icon BOOLEAN NOT NULL DEFAULT true,\n run_after_install BOOLEAN NOT NULL DEFAULT false,\n run_at_boot BOOLEAN NOT NULL DEFAULT false,\n is_system BOOLEAN NOT NULL DEFAULT false,\n is_active BOOLEAN NOT NULL DEFAULT true,\n\n metadata JSONB,\n created_at TIMESTAMP NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMP NOT NULL DEFAULT NOW()\n);\n\n-- Commands Table\nCREATE TABLE IF NOT EXISTS mdm_commands (\n id VARCHAR(255) PRIMARY KEY,\n device_id VARCHAR(255) NOT NULL REFERENCES mdm_devices(id) ON DELETE CASCADE,\n type VARCHAR(50) NOT NULL,\n payload JSONB,\n status mdm_command_status NOT NULL DEFAULT 'pending',\n result JSONB,\n error TEXT,\n\n created_at TIMESTAMP NOT NULL DEFAULT NOW(),\n sent_at TIMESTAMP,\n acknowledged_at TIMESTAMP,\n completed_at TIMESTAMP\n);\n\n-- Events Table\nCREATE TABLE IF NOT EXISTS mdm_events (\n id VARCHAR(255) PRIMARY KEY,\n device_id VARCHAR(255) NOT NULL REFERENCES mdm_devices(id) ON DELETE CASCADE,\n type VARCHAR(100) NOT NULL,\n payload JSONB NOT NULL DEFAULT '{}',\n created_at TIMESTAMP NOT NULL DEFAULT NOW()\n);\n\n-- Groups Table\nCREATE TABLE IF NOT EXISTS mdm_groups (\n id VARCHAR(255) PRIMARY KEY,\n name VARCHAR(255) NOT NULL,\n description TEXT,\n policy_id VARCHAR(255) REFERENCES mdm_policies(id) ON DELETE SET NULL,\n parent_id VARCHAR(255) REFERENCES mdm_groups(id) ON DELETE SET NULL,\n metadata JSONB,\n created_at TIMESTAMP NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMP NOT NULL DEFAULT NOW()\n);\n\n-- Device Groups Junction Table\nCREATE TABLE IF NOT EXISTS mdm_device_groups (\n device_id VARCHAR(255) NOT NULL REFERENCES mdm_devices(id) ON DELETE CASCADE,\n group_id VARCHAR(255) NOT NULL REFERENCES mdm_groups(id) ON DELETE CASCADE,\n PRIMARY KEY (device_id, group_id)\n);\n\n-- Push Tokens Table\nCREATE TABLE IF NOT EXISTS mdm_push_tokens (\n id VARCHAR(255) PRIMARY KEY,\n device_id VARCHAR(255) NOT NULL REFERENCES mdm_devices(id) ON DELETE CASCADE,\n provider mdm_push_provider NOT NULL,\n token TEXT NOT NULL,\n is_active BOOLEAN NOT NULL DEFAULT true,\n created_at TIMESTAMP NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMP NOT NULL DEFAULT NOW(),\n UNIQUE(device_id, provider)\n);\n\n-- App Deployments Table\nCREATE TABLE IF NOT EXISTS mdm_app_deployments (\n id VARCHAR(255) PRIMARY KEY,\n application_id VARCHAR(255) NOT NULL REFERENCES mdm_applications(id) ON DELETE CASCADE,\n target_type VARCHAR(20) NOT NULL, -- 'device', 'policy', 'group'\n target_id VARCHAR(255) NOT NULL,\n created_at TIMESTAMP NOT NULL DEFAULT NOW()\n);\n\n-- Indexes\nCREATE INDEX IF NOT EXISTS idx_devices_status ON mdm_devices(status);\nCREATE INDEX IF NOT EXISTS idx_devices_policy ON mdm_devices(policy_id);\nCREATE INDEX IF NOT EXISTS idx_devices_enrollment ON mdm_devices(enrollment_id);\nCREATE INDEX IF NOT EXISTS idx_devices_last_heartbeat ON mdm_devices(last_heartbeat);\n\nCREATE INDEX IF NOT EXISTS idx_commands_device ON mdm_commands(device_id);\nCREATE INDEX IF NOT EXISTS idx_commands_status ON mdm_commands(status);\nCREATE INDEX IF NOT EXISTS idx_commands_device_status ON mdm_commands(device_id, status);\n\nCREATE INDEX IF NOT EXISTS idx_events_device ON mdm_events(device_id);\nCREATE INDEX IF NOT EXISTS idx_events_type ON mdm_events(type);\nCREATE INDEX IF NOT EXISTS idx_events_created ON mdm_events(created_at);\n\nCREATE INDEX IF NOT EXISTS idx_applications_package ON mdm_applications(package_name);\nCREATE INDEX IF NOT EXISTS idx_push_tokens_device ON mdm_push_tokens(device_id);\n`;\n\nconst ROLLBACK_SQL = `\n-- OpenMDM Database Rollback\n\nDROP TABLE IF EXISTS mdm_app_deployments;\nDROP TABLE IF EXISTS mdm_push_tokens;\nDROP TABLE IF EXISTS mdm_device_groups;\nDROP TABLE IF EXISTS mdm_events;\nDROP TABLE IF EXISTS mdm_commands;\nDROP TABLE IF EXISTS mdm_applications;\nDROP TABLE IF EXISTS mdm_groups;\nDROP TABLE IF EXISTS mdm_devices;\nDROP TABLE IF EXISTS mdm_policies;\n\nDROP TYPE IF EXISTS mdm_push_provider;\nDROP TYPE IF EXISTS mdm_command_status;\nDROP TYPE IF EXISTS mdm_device_status;\n`;\n\nexport async function runMigrations(options: MigrateOptions): Promise<void> {\n console.log(chalk.blue('\\\\nš¦ OpenMDM Database Migration\\\\n'));\n\n const databaseUrl = process.env.DATABASE_URL;\n\n if (!databaseUrl && !options.dryRun) {\n console.error(chalk.red('Error: DATABASE_URL environment variable is required'));\n console.log(chalk.gray('Set it in your .env file or export it before running migrations.'));\n process.exit(1);\n }\n\n if (options.rollback) {\n console.log(chalk.yellow('ā ļø Rolling back migrations...\\\\n'));\n\n if (options.dryRun) {\n console.log(chalk.gray('SQL to execute:'));\n console.log(ROLLBACK_SQL);\n return;\n }\n\n const spinner = ora('Rolling back...').start();\n\n try {\n // In a real implementation, we'd use a database client here\n // For now, just output the SQL\n console.log(chalk.gray('\\\\nRollback SQL:'));\n console.log(ROLLBACK_SQL);\n spinner.succeed('Rollback SQL generated');\n\n console.log(chalk.yellow('\\\\nā ļø Execute the above SQL manually or use a database client.'));\n } catch (error) {\n spinner.fail('Rollback failed');\n console.error(chalk.red(error));\n }\n\n return;\n }\n\n if (options.dryRun) {\n console.log(chalk.gray('SQL to execute:'));\n console.log(MIGRATION_SQL);\n return;\n }\n\n const spinner = ora('Running migrations...').start();\n\n try {\n // In a real implementation, we'd connect to the database and execute\n // For now, output the SQL\n console.log(chalk.gray('\\\\nMigration SQL:'));\n console.log(MIGRATION_SQL);\n spinner.succeed('Migration SQL generated');\n\n console.log(chalk.green('\\\\nā
Migration complete!'));\n console.log(chalk.gray('\\\\nExecute the above SQL against your database,'));\n console.log(chalk.gray('or integrate with Drizzle Kit for automated migrations:'));\n console.log(chalk.gray(' npx drizzle-kit push:pg'));\n } catch (error) {\n spinner.fail('Migration failed');\n console.error(chalk.red(error));\n }\n}\n"],"mappings":";;;AAAA,OAAO,WAAW;AAClB,OAAO,SAAS;AAOhB,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8KtB,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBrB,eAAsB,cAAc,SAAwC;AAC1E,UAAQ,IAAI,MAAM,KAAK,4CAAqC,CAAC;AAE7D,QAAM,cAAc,QAAQ,IAAI;AAEhC,MAAI,CAAC,eAAe,CAAC,QAAQ,QAAQ;AACnC,YAAQ,MAAM,MAAM,IAAI,sDAAsD,CAAC;AAC/E,YAAQ,IAAI,MAAM,KAAK,kEAAkE,CAAC;AAC1F,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,QAAQ,UAAU;AACpB,YAAQ,IAAI,MAAM,OAAO,6CAAmC,CAAC;AAE7D,QAAI,QAAQ,QAAQ;AAClB,cAAQ,IAAI,MAAM,KAAK,iBAAiB,CAAC;AACzC,cAAQ,IAAI,YAAY;AACxB;AAAA,IACF;AAEA,UAAMA,WAAU,IAAI,iBAAiB,EAAE,MAAM;AAE7C,QAAI;AAGF,cAAQ,IAAI,MAAM,KAAK,kBAAkB,CAAC;AAC1C,cAAQ,IAAI,YAAY;AACxB,MAAAA,SAAQ,QAAQ,wBAAwB;AAExC,cAAQ,IAAI,MAAM,OAAO,2EAAiE,CAAC;AAAA,IAC7F,SAAS,OAAO;AACd,MAAAA,SAAQ,KAAK,iBAAiB;AAC9B,cAAQ,MAAM,MAAM,IAAI,KAAK,CAAC;AAAA,IAChC;AAEA;AAAA,EACF;AAEA,MAAI,QAAQ,QAAQ;AAClB,YAAQ,IAAI,MAAM,KAAK,iBAAiB,CAAC;AACzC,YAAQ,IAAI,aAAa;AACzB;AAAA,EACF;AAEA,QAAM,UAAU,IAAI,uBAAuB,EAAE,MAAM;AAEnD,MAAI;AAGF,YAAQ,IAAI,MAAM,KAAK,mBAAmB,CAAC;AAC3C,YAAQ,IAAI,aAAa;AACzB,YAAQ,QAAQ,yBAAyB;AAEzC,YAAQ,IAAI,MAAM,MAAM,+BAA0B,CAAC;AACnD,YAAQ,IAAI,MAAM,KAAK,iDAAiD,CAAC;AACzE,YAAQ,IAAI,MAAM,KAAK,yDAAyD,CAAC;AACjF,YAAQ,IAAI,MAAM,KAAK,2BAA2B,CAAC;AAAA,EACrD,SAAS,OAAO;AACd,YAAQ,KAAK,kBAAkB;AAC/B,YAAQ,MAAM,MAAM,IAAI,KAAK,CAAC;AAAA,EAChC;AACF;","names":["spinner"]}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/policy.ts
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import inquirer from "inquirer";
|
|
6
|
+
import ora from "ora";
|
|
7
|
+
import fs from "fs/promises";
|
|
8
|
+
var mockPolicies = [
|
|
9
|
+
{
|
|
10
|
+
id: "policy_001",
|
|
11
|
+
name: "Default Policy",
|
|
12
|
+
description: "Standard policy for all devices",
|
|
13
|
+
isDefault: true,
|
|
14
|
+
settings: {
|
|
15
|
+
kioskMode: false,
|
|
16
|
+
lockStatusBar: false,
|
|
17
|
+
heartbeatInterval: 60
|
|
18
|
+
},
|
|
19
|
+
deviceCount: 45
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "policy_002",
|
|
23
|
+
name: "Kiosk Mode",
|
|
24
|
+
description: "Single-app kiosk mode for retail displays",
|
|
25
|
+
isDefault: false,
|
|
26
|
+
settings: {
|
|
27
|
+
kioskMode: true,
|
|
28
|
+
mainApp: "com.example.kiosk",
|
|
29
|
+
lockStatusBar: true,
|
|
30
|
+
lockNavigationBar: true
|
|
31
|
+
},
|
|
32
|
+
deviceCount: 12
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: "policy_003",
|
|
36
|
+
name: "High Security",
|
|
37
|
+
description: "Strict security policy for corporate devices",
|
|
38
|
+
isDefault: false,
|
|
39
|
+
settings: {
|
|
40
|
+
kioskMode: false,
|
|
41
|
+
encryptionRequired: true,
|
|
42
|
+
passwordPolicy: {
|
|
43
|
+
required: true,
|
|
44
|
+
minLength: 8,
|
|
45
|
+
complexity: "alphanumeric"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
deviceCount: 28
|
|
49
|
+
}
|
|
50
|
+
];
|
|
51
|
+
async function listPolicies(options) {
|
|
52
|
+
const spinner = ora("Fetching policies...").start();
|
|
53
|
+
try {
|
|
54
|
+
const policies = [...mockPolicies];
|
|
55
|
+
spinner.stop();
|
|
56
|
+
if (options.json) {
|
|
57
|
+
console.log(JSON.stringify(policies, null, 2));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
console.log(chalk.blue("\\n\u{1F4CB} Policies\\n"));
|
|
61
|
+
if (policies.length === 0) {
|
|
62
|
+
console.log(chalk.gray("No policies found."));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
console.log(
|
|
66
|
+
chalk.gray(`${"ID".padEnd(15)} ${"Name".padEnd(25)} ${"Default".padEnd(10)} ${"Devices".padEnd(10)}`)
|
|
67
|
+
);
|
|
68
|
+
console.log(chalk.gray("-".repeat(60)));
|
|
69
|
+
for (const policy of policies) {
|
|
70
|
+
const defaultStr = policy.isDefault ? chalk.green("Yes") : "No";
|
|
71
|
+
console.log(
|
|
72
|
+
`${policy.id.padEnd(15)} ${policy.name.padEnd(25)} ${defaultStr.padEnd(10)} ${policy.deviceCount.toString().padEnd(10)}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
console.log(chalk.gray(`\\nTotal: ${policies.length} policies`));
|
|
76
|
+
} catch (error) {
|
|
77
|
+
spinner.fail("Failed to fetch policies");
|
|
78
|
+
console.error(chalk.red(error));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async function showPolicy(policyId, options) {
|
|
82
|
+
const spinner = ora(`Fetching policy ${policyId}...`).start();
|
|
83
|
+
try {
|
|
84
|
+
const policy = mockPolicies.find((p) => p.id === policyId);
|
|
85
|
+
spinner.stop();
|
|
86
|
+
if (!policy) {
|
|
87
|
+
console.log(chalk.red(`\\nPolicy not found: ${policyId}`));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (options.json) {
|
|
91
|
+
console.log(JSON.stringify(policy, null, 2));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
console.log(chalk.blue(`\\n\u{1F4CB} Policy: ${policy.name}\\n`));
|
|
95
|
+
console.log(` ${chalk.gray("ID:")} ${policy.id}`);
|
|
96
|
+
console.log(` ${chalk.gray("Description:")} ${policy.description || "-"}`);
|
|
97
|
+
console.log(
|
|
98
|
+
` ${chalk.gray("Default:")} ${policy.isDefault ? chalk.green("Yes") : "No"}`
|
|
99
|
+
);
|
|
100
|
+
console.log(` ${chalk.gray("Devices:")} ${policy.deviceCount}`);
|
|
101
|
+
console.log("");
|
|
102
|
+
console.log(chalk.gray(" Settings:"));
|
|
103
|
+
console.log(JSON.stringify(policy.settings, null, 4).split("\\n").map((l) => " " + l).join("\\n"));
|
|
104
|
+
console.log("");
|
|
105
|
+
} catch (error) {
|
|
106
|
+
spinner.fail("Failed to fetch policy");
|
|
107
|
+
console.error(chalk.red(error));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async function createPolicy(options) {
|
|
111
|
+
if (options.file) {
|
|
112
|
+
const spinner2 = ora("Reading policy file...").start();
|
|
113
|
+
try {
|
|
114
|
+
const content = await fs.readFile(options.file, "utf-8");
|
|
115
|
+
const policy2 = JSON.parse(content);
|
|
116
|
+
spinner2.succeed("Policy file read");
|
|
117
|
+
console.log(chalk.blue("\\nPolicy to create:"));
|
|
118
|
+
console.log(` Name: ${policy2.name}`);
|
|
119
|
+
console.log(` Description: ${policy2.description || "-"}`);
|
|
120
|
+
const { confirm } = await inquirer.prompt([
|
|
121
|
+
{
|
|
122
|
+
type: "confirm",
|
|
123
|
+
name: "confirm",
|
|
124
|
+
message: "Create this policy?",
|
|
125
|
+
default: true
|
|
126
|
+
}
|
|
127
|
+
]);
|
|
128
|
+
if (confirm) {
|
|
129
|
+
spinner2.start("Creating policy...");
|
|
130
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
131
|
+
spinner2.succeed(`Policy "${policy2.name}" created`);
|
|
132
|
+
}
|
|
133
|
+
} catch (error) {
|
|
134
|
+
spinner2.fail("Failed to create policy from file");
|
|
135
|
+
console.error(chalk.red(error));
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
console.log(chalk.blue("\\n\u{1F4CB} Create New Policy\\n"));
|
|
140
|
+
const answers = await inquirer.prompt([
|
|
141
|
+
{
|
|
142
|
+
type: "input",
|
|
143
|
+
name: "name",
|
|
144
|
+
message: "Policy name:",
|
|
145
|
+
validate: (input) => input.length > 0 || "Name is required"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
type: "input",
|
|
149
|
+
name: "description",
|
|
150
|
+
message: "Description (optional):"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
type: "confirm",
|
|
154
|
+
name: "kioskMode",
|
|
155
|
+
message: "Enable kiosk mode?",
|
|
156
|
+
default: false
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
type: "input",
|
|
160
|
+
name: "mainApp",
|
|
161
|
+
message: "Kiosk app package name:",
|
|
162
|
+
when: (answers2) => answers2.kioskMode
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
type: "confirm",
|
|
166
|
+
name: "lockStatusBar",
|
|
167
|
+
message: "Lock status bar?",
|
|
168
|
+
when: (answers2) => answers2.kioskMode,
|
|
169
|
+
default: true
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
type: "number",
|
|
173
|
+
name: "heartbeatInterval",
|
|
174
|
+
message: "Heartbeat interval (seconds):",
|
|
175
|
+
default: 60
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
type: "confirm",
|
|
179
|
+
name: "isDefault",
|
|
180
|
+
message: "Set as default policy?",
|
|
181
|
+
default: false
|
|
182
|
+
}
|
|
183
|
+
]);
|
|
184
|
+
const policy = {
|
|
185
|
+
name: answers.name,
|
|
186
|
+
description: answers.description || null,
|
|
187
|
+
isDefault: answers.isDefault,
|
|
188
|
+
settings: {
|
|
189
|
+
kioskMode: answers.kioskMode,
|
|
190
|
+
mainApp: answers.mainApp,
|
|
191
|
+
lockStatusBar: answers.lockStatusBar ?? false,
|
|
192
|
+
heartbeatInterval: answers.heartbeatInterval
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
const spinner = ora("Creating policy...").start();
|
|
196
|
+
try {
|
|
197
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
198
|
+
spinner.succeed(`Policy "${policy.name}" created`);
|
|
199
|
+
console.log(chalk.gray("\\nPolicy ID: policy_" + Date.now()));
|
|
200
|
+
} catch (error) {
|
|
201
|
+
spinner.fail("Failed to create policy");
|
|
202
|
+
console.error(chalk.red(error));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async function applyPolicy(policyId, deviceId) {
|
|
206
|
+
const spinner = ora(`Applying policy ${policyId} to device ${deviceId}...`).start();
|
|
207
|
+
try {
|
|
208
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
209
|
+
spinner.succeed(`Policy applied to device ${deviceId}`);
|
|
210
|
+
console.log(chalk.gray("The device will receive the new policy on its next sync."));
|
|
211
|
+
} catch (error) {
|
|
212
|
+
spinner.fail("Failed to apply policy");
|
|
213
|
+
console.error(chalk.red(error));
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
export {
|
|
217
|
+
applyPolicy,
|
|
218
|
+
createPolicy,
|
|
219
|
+
listPolicies,
|
|
220
|
+
showPolicy
|
|
221
|
+
};
|
|
222
|
+
//# sourceMappingURL=policy-QGI5X7DH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/policy.ts"],"sourcesContent":["import chalk from 'chalk';\nimport inquirer from 'inquirer';\nimport ora from 'ora';\nimport fs from 'fs/promises';\n\ninterface ListOptions {\n json?: boolean;\n}\n\ninterface ShowOptions {\n json?: boolean;\n}\n\ninterface CreateOptions {\n file?: string;\n}\n\n// Mock data\nconst mockPolicies = [\n {\n id: 'policy_001',\n name: 'Default Policy',\n description: 'Standard policy for all devices',\n isDefault: true,\n settings: {\n kioskMode: false,\n lockStatusBar: false,\n heartbeatInterval: 60,\n },\n deviceCount: 45,\n },\n {\n id: 'policy_002',\n name: 'Kiosk Mode',\n description: 'Single-app kiosk mode for retail displays',\n isDefault: false,\n settings: {\n kioskMode: true,\n mainApp: 'com.example.kiosk',\n lockStatusBar: true,\n lockNavigationBar: true,\n },\n deviceCount: 12,\n },\n {\n id: 'policy_003',\n name: 'High Security',\n description: 'Strict security policy for corporate devices',\n isDefault: false,\n settings: {\n kioskMode: false,\n encryptionRequired: true,\n passwordPolicy: {\n required: true,\n minLength: 8,\n complexity: 'alphanumeric',\n },\n },\n deviceCount: 28,\n },\n];\n\nexport async function listPolicies(options: ListOptions): Promise<void> {\n const spinner = ora('Fetching policies...').start();\n\n try {\n const policies = [...mockPolicies];\n spinner.stop();\n\n if (options.json) {\n console.log(JSON.stringify(policies, null, 2));\n return;\n }\n\n console.log(chalk.blue('\\\\nš Policies\\\\n'));\n\n if (policies.length === 0) {\n console.log(chalk.gray('No policies found.'));\n return;\n }\n\n // Table header\n console.log(\n chalk.gray(`${'ID'.padEnd(15)} ${'Name'.padEnd(25)} ${'Default'.padEnd(10)} ${'Devices'.padEnd(10)}`)\n );\n console.log(chalk.gray('-'.repeat(60)));\n\n for (const policy of policies) {\n const defaultStr = policy.isDefault ? chalk.green('Yes') : 'No';\n console.log(\n `${policy.id.padEnd(15)} ${policy.name.padEnd(25)} ${defaultStr.padEnd(10)} ${policy.deviceCount\n .toString()\n .padEnd(10)}`\n );\n }\n\n console.log(chalk.gray(`\\\\nTotal: ${policies.length} policies`));\n } catch (error) {\n spinner.fail('Failed to fetch policies');\n console.error(chalk.red(error));\n }\n}\n\nexport async function showPolicy(policyId: string, options: ShowOptions): Promise<void> {\n const spinner = ora(`Fetching policy ${policyId}...`).start();\n\n try {\n const policy = mockPolicies.find(p => p.id === policyId);\n spinner.stop();\n\n if (!policy) {\n console.log(chalk.red(`\\\\nPolicy not found: ${policyId}`));\n return;\n }\n\n if (options.json) {\n console.log(JSON.stringify(policy, null, 2));\n return;\n }\n\n console.log(chalk.blue(`\\\\nš Policy: ${policy.name}\\\\n`));\n console.log(` ${chalk.gray('ID:')} ${policy.id}`);\n console.log(` ${chalk.gray('Description:')} ${policy.description || '-'}`);\n console.log(\n ` ${chalk.gray('Default:')} ${policy.isDefault ? chalk.green('Yes') : 'No'}`\n );\n console.log(` ${chalk.gray('Devices:')} ${policy.deviceCount}`);\n console.log('');\n console.log(chalk.gray(' Settings:'));\n console.log(JSON.stringify(policy.settings, null, 4).split('\\\\n').map(l => ' ' + l).join('\\\\n'));\n console.log('');\n } catch (error) {\n spinner.fail('Failed to fetch policy');\n console.error(chalk.red(error));\n }\n}\n\nexport async function createPolicy(options: CreateOptions): Promise<void> {\n if (options.file) {\n // Create from file\n const spinner = ora('Reading policy file...').start();\n try {\n const content = await fs.readFile(options.file, 'utf-8');\n const policy = JSON.parse(content);\n spinner.succeed('Policy file read');\n\n console.log(chalk.blue('\\\\nPolicy to create:'));\n console.log(` Name: ${policy.name}`);\n console.log(` Description: ${policy.description || '-'}`);\n\n const { confirm } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'confirm',\n message: 'Create this policy?',\n default: true,\n },\n ]);\n\n if (confirm) {\n spinner.start('Creating policy...');\n await new Promise(resolve => setTimeout(resolve, 1000));\n spinner.succeed(`Policy \"${policy.name}\" created`);\n }\n } catch (error) {\n spinner.fail('Failed to create policy from file');\n console.error(chalk.red(error));\n }\n return;\n }\n\n // Interactive creation\n console.log(chalk.blue('\\\\nš Create New Policy\\\\n'));\n\n const answers = await inquirer.prompt([\n {\n type: 'input',\n name: 'name',\n message: 'Policy name:',\n validate: (input) => input.length > 0 || 'Name is required',\n },\n {\n type: 'input',\n name: 'description',\n message: 'Description (optional):',\n },\n {\n type: 'confirm',\n name: 'kioskMode',\n message: 'Enable kiosk mode?',\n default: false,\n },\n {\n type: 'input',\n name: 'mainApp',\n message: 'Kiosk app package name:',\n when: (answers) => answers.kioskMode,\n },\n {\n type: 'confirm',\n name: 'lockStatusBar',\n message: 'Lock status bar?',\n when: (answers) => answers.kioskMode,\n default: true,\n },\n {\n type: 'number',\n name: 'heartbeatInterval',\n message: 'Heartbeat interval (seconds):',\n default: 60,\n },\n {\n type: 'confirm',\n name: 'isDefault',\n message: 'Set as default policy?',\n default: false,\n },\n ]);\n\n const policy = {\n name: answers.name,\n description: answers.description || null,\n isDefault: answers.isDefault,\n settings: {\n kioskMode: answers.kioskMode,\n mainApp: answers.mainApp,\n lockStatusBar: answers.lockStatusBar ?? false,\n heartbeatInterval: answers.heartbeatInterval,\n },\n };\n\n const spinner = ora('Creating policy...').start();\n\n try {\n await new Promise(resolve => setTimeout(resolve, 1000));\n spinner.succeed(`Policy \"${policy.name}\" created`);\n console.log(chalk.gray('\\\\nPolicy ID: policy_' + Date.now()));\n } catch (error) {\n spinner.fail('Failed to create policy');\n console.error(chalk.red(error));\n }\n}\n\nexport async function applyPolicy(policyId: string, deviceId: string): Promise<void> {\n const spinner = ora(`Applying policy ${policyId} to device ${deviceId}...`).start();\n\n try {\n await new Promise(resolve => setTimeout(resolve, 1000));\n spinner.succeed(`Policy applied to device ${deviceId}`);\n console.log(chalk.gray('The device will receive the new policy on its next sync.'));\n } catch (error) {\n spinner.fail('Failed to apply policy');\n console.error(chalk.red(error));\n }\n}\n"],"mappings":"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","names":["spinner","policy","answers"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/push.ts
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import ora from "ora";
|
|
6
|
+
async function testPush(deviceId, options) {
|
|
7
|
+
console.log(chalk.blue("\\n\u{1F4F2} Send Test Push Notification\\n"));
|
|
8
|
+
const title = options.title || "Test Notification";
|
|
9
|
+
const message = options.message || "This is a test from OpenMDM";
|
|
10
|
+
console.log(` ${chalk.gray("Device:")} ${deviceId}`);
|
|
11
|
+
console.log(` ${chalk.gray("Title:")} ${title}`);
|
|
12
|
+
console.log(` ${chalk.gray("Message:")} ${message}`);
|
|
13
|
+
console.log("");
|
|
14
|
+
const spinner = ora("Sending push notification...").start();
|
|
15
|
+
try {
|
|
16
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
17
|
+
spinner.succeed("Push notification sent");
|
|
18
|
+
console.log(chalk.gray("\\nThe notification should appear on the device shortly."));
|
|
19
|
+
} catch (error) {
|
|
20
|
+
spinner.fail("Failed to send push notification");
|
|
21
|
+
console.error(chalk.red(error));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
testPush
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=push-GOOMUZVI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/push.ts"],"sourcesContent":["import chalk from 'chalk';\nimport ora from 'ora';\n\ninterface PushOptions {\n title?: string;\n message?: string;\n}\n\nexport async function testPush(deviceId: string, options: PushOptions): Promise<void> {\n console.log(chalk.blue('\\\\nš² Send Test Push Notification\\\\n'));\n\n const title = options.title || 'Test Notification';\n const message = options.message || 'This is a test from OpenMDM';\n\n console.log(` ${chalk.gray('Device:')} ${deviceId}`);\n console.log(` ${chalk.gray('Title:')} ${title}`);\n console.log(` ${chalk.gray('Message:')} ${message}`);\n console.log('');\n\n const spinner = ora('Sending push notification...').start();\n\n try {\n // In real implementation, this would use the push adapter\n await new Promise(resolve => setTimeout(resolve, 1500));\n spinner.succeed('Push notification sent');\n\n console.log(chalk.gray('\\\\nThe notification should appear on the device shortly.'));\n } catch (error) {\n spinner.fail('Failed to send push notification');\n console.error(chalk.red(error));\n }\n}\n"],"mappings":";;;AAAA,OAAO,WAAW;AAClB,OAAO,SAAS;AAOhB,eAAsB,SAAS,UAAkB,SAAqC;AACpF,UAAQ,IAAI,MAAM,KAAK,6CAAsC,CAAC;AAE9D,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,UAAU,QAAQ,WAAW;AAEnC,UAAQ,IAAI,KAAK,MAAM,KAAK,SAAS,CAAC,KAAK,QAAQ,EAAE;AACrD,UAAQ,IAAI,KAAK,MAAM,KAAK,QAAQ,CAAC,MAAM,KAAK,EAAE;AAClD,UAAQ,IAAI,KAAK,MAAM,KAAK,UAAU,CAAC,IAAI,OAAO,EAAE;AACpD,UAAQ,IAAI,EAAE;AAEd,QAAM,UAAU,IAAI,8BAA8B,EAAE,MAAM;AAE1D,MAAI;AAEF,UAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,IAAI,CAAC;AACtD,YAAQ,QAAQ,wBAAwB;AAExC,YAAQ,IAAI,MAAM,KAAK,0DAA0D,CAAC;AAAA,EACpF,SAAS,OAAO;AACd,YAAQ,KAAK,kCAAkC;AAC/C,YAAQ,MAAM,MAAM,IAAI,KAAK,CAAC;AAAA,EAChC;AACF;","names":[]}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/commands/stats.ts
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import ora from "ora";
|
|
6
|
+
async function showStats(options) {
|
|
7
|
+
const spinner = ora("Fetching statistics...").start();
|
|
8
|
+
try {
|
|
9
|
+
const stats = {
|
|
10
|
+
devices: {
|
|
11
|
+
total: 85,
|
|
12
|
+
enrolled: 72,
|
|
13
|
+
pending: 8,
|
|
14
|
+
blocked: 5,
|
|
15
|
+
online: 45,
|
|
16
|
+
offline: 40
|
|
17
|
+
},
|
|
18
|
+
policies: {
|
|
19
|
+
total: 5,
|
|
20
|
+
withDevices: 4
|
|
21
|
+
},
|
|
22
|
+
commands: {
|
|
23
|
+
pending: 12,
|
|
24
|
+
completedToday: 156,
|
|
25
|
+
failedToday: 3
|
|
26
|
+
},
|
|
27
|
+
system: {
|
|
28
|
+
uptime: "15 days, 4 hours",
|
|
29
|
+
version: "0.1.0",
|
|
30
|
+
lastBackup: new Date(Date.now() - 864e5).toISOString()
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
spinner.stop();
|
|
34
|
+
if (options.json) {
|
|
35
|
+
console.log(JSON.stringify(stats, null, 2));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
console.log(chalk.blue("\\n\u{1F4CA} OpenMDM Statistics\\n"));
|
|
39
|
+
console.log(chalk.white.bold(" Devices"));
|
|
40
|
+
console.log(chalk.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
41
|
+
console.log(` Total: ${chalk.cyan(stats.devices.total)}`);
|
|
42
|
+
console.log(` Enrolled: ${chalk.green(stats.devices.enrolled)}`);
|
|
43
|
+
console.log(` Pending: ${chalk.yellow(stats.devices.pending)}`);
|
|
44
|
+
console.log(` Blocked: ${chalk.red(stats.devices.blocked)}`);
|
|
45
|
+
console.log("");
|
|
46
|
+
console.log(` Online: ${chalk.green(stats.devices.online)}`);
|
|
47
|
+
console.log(` Offline: ${chalk.gray(stats.devices.offline)}`);
|
|
48
|
+
console.log("");
|
|
49
|
+
console.log(chalk.white.bold(" Policies"));
|
|
50
|
+
console.log(chalk.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
51
|
+
console.log(` Total: ${chalk.cyan(stats.policies.total)}`);
|
|
52
|
+
console.log(` With devices: ${chalk.cyan(stats.policies.withDevices)}`);
|
|
53
|
+
console.log("");
|
|
54
|
+
console.log(chalk.white.bold(" Commands (Today)"));
|
|
55
|
+
console.log(chalk.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
56
|
+
console.log(` Pending: ${chalk.yellow(stats.commands.pending)}`);
|
|
57
|
+
console.log(` Completed: ${chalk.green(stats.commands.completedToday)}`);
|
|
58
|
+
console.log(` Failed: ${chalk.red(stats.commands.failedToday)}`);
|
|
59
|
+
console.log("");
|
|
60
|
+
console.log(chalk.white.bold(" System"));
|
|
61
|
+
console.log(chalk.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
62
|
+
console.log(` Version: ${chalk.cyan(stats.system.version)}`);
|
|
63
|
+
console.log(` Uptime: ${stats.system.uptime}`);
|
|
64
|
+
console.log(` Last backup: ${formatDate(stats.system.lastBackup)}`);
|
|
65
|
+
console.log("");
|
|
66
|
+
} catch (error) {
|
|
67
|
+
spinner.fail("Failed to fetch statistics");
|
|
68
|
+
console.error(chalk.red(error));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function formatDate(isoString) {
|
|
72
|
+
const date = new Date(isoString);
|
|
73
|
+
return date.toLocaleString();
|
|
74
|
+
}
|
|
75
|
+
export {
|
|
76
|
+
showStats
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=stats-7LZFNZT2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/stats.ts"],"sourcesContent":["import chalk from 'chalk';\nimport ora from 'ora';\n\ninterface StatsOptions {\n json?: boolean;\n}\n\nexport async function showStats(options: StatsOptions): Promise<void> {\n const spinner = ora('Fetching statistics...').start();\n\n try {\n // Mock statistics - in real implementation, this queries the database\n const stats = {\n devices: {\n total: 85,\n enrolled: 72,\n pending: 8,\n blocked: 5,\n online: 45,\n offline: 40,\n },\n policies: {\n total: 5,\n withDevices: 4,\n },\n commands: {\n pending: 12,\n completedToday: 156,\n failedToday: 3,\n },\n system: {\n uptime: '15 days, 4 hours',\n version: '0.1.0',\n lastBackup: new Date(Date.now() - 86400000).toISOString(),\n },\n };\n\n spinner.stop();\n\n if (options.json) {\n console.log(JSON.stringify(stats, null, 2));\n return;\n }\n\n console.log(chalk.blue('\\\\nš OpenMDM Statistics\\\\n'));\n\n // Devices section\n console.log(chalk.white.bold(' Devices'));\n console.log(chalk.gray(' āāāāāāāāāāāāāāāāāāāāā'));\n console.log(` Total: ${chalk.cyan(stats.devices.total)}`);\n console.log(` Enrolled: ${chalk.green(stats.devices.enrolled)}`);\n console.log(` Pending: ${chalk.yellow(stats.devices.pending)}`);\n console.log(` Blocked: ${chalk.red(stats.devices.blocked)}`);\n console.log('');\n console.log(` Online: ${chalk.green(stats.devices.online)}`);\n console.log(` Offline: ${chalk.gray(stats.devices.offline)}`);\n console.log('');\n\n // Policies section\n console.log(chalk.white.bold(' Policies'));\n console.log(chalk.gray(' āāāāāāāāāāāāāāāāāāāāā'));\n console.log(` Total: ${chalk.cyan(stats.policies.total)}`);\n console.log(` With devices: ${chalk.cyan(stats.policies.withDevices)}`);\n console.log('');\n\n // Commands section\n console.log(chalk.white.bold(' Commands (Today)'));\n console.log(chalk.gray(' āāāāāāāāāāāāāāāāāāāāā'));\n console.log(` Pending: ${chalk.yellow(stats.commands.pending)}`);\n console.log(` Completed: ${chalk.green(stats.commands.completedToday)}`);\n console.log(` Failed: ${chalk.red(stats.commands.failedToday)}`);\n console.log('');\n\n // System section\n console.log(chalk.white.bold(' System'));\n console.log(chalk.gray(' āāāāāāāāāāāāāāāāāāāāā'));\n console.log(` Version: ${chalk.cyan(stats.system.version)}`);\n console.log(` Uptime: ${stats.system.uptime}`);\n console.log(` Last backup: ${formatDate(stats.system.lastBackup)}`);\n console.log('');\n } catch (error) {\n spinner.fail('Failed to fetch statistics');\n console.error(chalk.red(error));\n }\n}\n\nfunction formatDate(isoString: string): string {\n const date = new Date(isoString);\n return date.toLocaleString();\n}\n"],"mappings":";;;AAAA,OAAO,WAAW;AAClB,OAAO,SAAS;AAMhB,eAAsB,UAAU,SAAsC;AACpE,QAAM,UAAU,IAAI,wBAAwB,EAAE,MAAM;AAEpD,MAAI;AAEF,UAAM,QAAQ;AAAA,MACZ,SAAS;AAAA,QACP,OAAO;AAAA,QACP,UAAU;AAAA,QACV,SAAS;AAAA,QACT,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,SAAS;AAAA,MACX;AAAA,MACA,UAAU;AAAA,QACR,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,MACA,UAAU;AAAA,QACR,SAAS;AAAA,QACT,gBAAgB;AAAA,QAChB,aAAa;AAAA,MACf;AAAA,MACA,QAAQ;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,KAAQ,EAAE,YAAY;AAAA,MAC1D;AAAA,IACF;AAEA,YAAQ,KAAK;AAEb,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAC1C;AAAA,IACF;AAEA,YAAQ,IAAI,MAAM,KAAK,oCAA6B,CAAC;AAGrD,YAAQ,IAAI,MAAM,MAAM,KAAK,WAAW,CAAC;AACzC,YAAQ,IAAI,MAAM,KAAK,kIAAyB,CAAC;AACjD,YAAQ,IAAI,eAAe,MAAM,KAAK,MAAM,QAAQ,KAAK,CAAC,EAAE;AAC5D,YAAQ,IAAI,eAAe,MAAM,MAAM,MAAM,QAAQ,QAAQ,CAAC,EAAE;AAChE,YAAQ,IAAI,eAAe,MAAM,OAAO,MAAM,QAAQ,OAAO,CAAC,EAAE;AAChE,YAAQ,IAAI,eAAe,MAAM,IAAI,MAAM,QAAQ,OAAO,CAAC,EAAE;AAC7D,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,eAAe,MAAM,MAAM,MAAM,QAAQ,MAAM,CAAC,EAAE;AAC9D,YAAQ,IAAI,eAAe,MAAM,KAAK,MAAM,QAAQ,OAAO,CAAC,EAAE;AAC9D,YAAQ,IAAI,EAAE;AAGd,YAAQ,IAAI,MAAM,MAAM,KAAK,YAAY,CAAC;AAC1C,YAAQ,IAAI,MAAM,KAAK,kIAAyB,CAAC;AACjD,YAAQ,IAAI,mBAAmB,MAAM,KAAK,MAAM,SAAS,KAAK,CAAC,EAAE;AACjE,YAAQ,IAAI,mBAAmB,MAAM,KAAK,MAAM,SAAS,WAAW,CAAC,EAAE;AACvE,YAAQ,IAAI,EAAE;AAGd,YAAQ,IAAI,MAAM,MAAM,KAAK,oBAAoB,CAAC;AAClD,YAAQ,IAAI,MAAM,KAAK,kIAAyB,CAAC;AACjD,YAAQ,IAAI,gBAAgB,MAAM,OAAO,MAAM,SAAS,OAAO,CAAC,EAAE;AAClE,YAAQ,IAAI,gBAAgB,MAAM,MAAM,MAAM,SAAS,cAAc,CAAC,EAAE;AACxE,YAAQ,IAAI,gBAAgB,MAAM,IAAI,MAAM,SAAS,WAAW,CAAC,EAAE;AACnE,YAAQ,IAAI,EAAE;AAGd,YAAQ,IAAI,MAAM,MAAM,KAAK,UAAU,CAAC;AACxC,YAAQ,IAAI,MAAM,KAAK,kIAAyB,CAAC;AACjD,YAAQ,IAAI,kBAAkB,MAAM,KAAK,MAAM,OAAO,OAAO,CAAC,EAAE;AAChE,YAAQ,IAAI,kBAAkB,MAAM,OAAO,MAAM,EAAE;AACnD,YAAQ,IAAI,kBAAkB,WAAW,MAAM,OAAO,UAAU,CAAC,EAAE;AACnE,YAAQ,IAAI,EAAE;AAAA,EAChB,SAAS,OAAO;AACd,YAAQ,KAAK,4BAA4B;AACzC,YAAQ,MAAM,MAAM,IAAI,KAAK,CAAC;AAAA,EAChC;AACF;AAEA,SAAS,WAAW,WAA2B;AAC7C,QAAM,OAAO,IAAI,KAAK,SAAS;AAC/B,SAAO,KAAK,eAAe;AAC7B;","names":[]}
|