library.dr-conversion 0.3.0 → 0.3.2

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/cli.js +204 -8
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![npm version](https://badge.fury.io/js/library.dr-conversion.svg)](https://www.npmjs.com/package/library.dr-conversion)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
- **Library.DR-Conversion** (v0.2.9) is a TypeScript library that provides a unified, platform-agnostic interface for building chat bots that work across multiple platforms like Discord, Root, and potentially others. Write your bot logic once, and deploy it anywhere!
8
+ **Library.DR-Conversion** (v0.3.2) is a TypeScript library that provides a unified, platform-agnostic interface for building chat bots that work across multiple platforms like Discord, Root, and potentially others. Write your bot logic once, and deploy it anywhere!
9
9
 
10
10
  ## ✨ Features
11
11
 
package/cli.js CHANGED
@@ -49,6 +49,53 @@ function detectPlatform() {
49
49
  }
50
50
  }
51
51
 
52
+ // Validate a root manifest object against minimal Root requirements
53
+ function validateManifestObject(manifest) {
54
+ const errors = [];
55
+ if (!manifest || typeof manifest !== 'object') {
56
+ errors.push('Manifest must be a JSON object');
57
+ return { valid: false, errors };
58
+ }
59
+
60
+ if (!manifest.id || typeof manifest.id !== 'string') {
61
+ errors.push('Missing or invalid "id" (string)');
62
+ }
63
+
64
+ if (!manifest.version || typeof manifest.version !== 'string') {
65
+ errors.push('Missing or invalid "version" (string)');
66
+ }
67
+
68
+ if (!manifest.package || typeof manifest.package !== 'object') {
69
+ errors.push('Missing "package" object');
70
+ } else {
71
+ if (manifest.package.server) {
72
+ const server = manifest.package.server;
73
+ if (!server.launch || typeof server.launch !== 'string') {
74
+ errors.push('package.server.launch is required and must be a string');
75
+ }
76
+ if (!Array.isArray(server.deploy) || server.deploy.length === 0) {
77
+ errors.push('package.server.deploy must be a non-empty array');
78
+ }
79
+ if (!Array.isArray(server.node_modules) || server.node_modules.length === 0) {
80
+ errors.push('package.server.node_modules must be a non-empty array');
81
+ }
82
+ }
83
+
84
+ if (manifest.package.client) {
85
+ const client = manifest.package.client;
86
+ // accept either entry or deploy
87
+ if (!client.entry && (!Array.isArray(client.deploy) || client.deploy.length === 0)) {
88
+ errors.push('package.client.entry or package.client.deploy is required');
89
+ }
90
+ if (client.assets && !Array.isArray(client.assets)) {
91
+ errors.push('package.client.assets must be an array if provided');
92
+ }
93
+ }
94
+ }
95
+
96
+ return { valid: errors.length === 0, errors };
97
+ }
98
+
52
99
  program
53
100
  .name('library.dr-conversion')
54
101
  .description('CLI tools for Library.DR-Conversion v0.2.9')
@@ -279,6 +326,62 @@ npx @rootsdk/cli publish
279
326
  fs.writeFileSync(path.join(projectDir, 'MANIFEST.md'), manifestReadme);
280
327
  }
281
328
 
329
+ // Create root-app-manifest.json for Root Apps (client-side)
330
+ if (options.platform === 'root-app') {
331
+ const appManifest = {
332
+ id: generateUUID(),
333
+ version: '1.0.0',
334
+ name: options.name,
335
+ description: `${options.name} - Root App`,
336
+ author: '',
337
+ homepage: '',
338
+ package: {
339
+ client: {
340
+ entry: 'dist/index.html',
341
+ assets: ['dist'],
342
+ node_modules: ['node_modules']
343
+ }
344
+ },
345
+ settings: {
346
+ ui: []
347
+ },
348
+ permissions: {
349
+ channel: {
350
+ CreateMessage: true,
351
+ ReadMessage: true
352
+ }
353
+ }
354
+ };
355
+
356
+ fs.writeFileSync(
357
+ path.join(projectDir, 'root-manifest.json'),
358
+ JSON.stringify(appManifest, null, 2)
359
+ );
360
+
361
+ const appManifestReadme = `# Root App Manifest
362
+
363
+ This project includes a generated root-manifest.json to help document your app.
364
+
365
+ This manifest follows the Root App manifest overview and provides the basic fields used by the Root platform:
366
+ - 'id': Unique UUID for the app
367
+ - 'version': Semver version
368
+ - 'package.client.entry': The client entry HTML for the app
369
+ - 'package.client.assets': Client assets to include in the upload
370
+ - 'permissions': Channel-level permissions used by the app
371
+
372
+ Notes:
373
+ - Update 'version' following semantic versioning when you make changes.
374
+ - Review permissions and remove any that aren't needed.
375
+ - Configure UI settings in the 'settings.ui' array (see Root docs for details):
376
+ https://docs.rootapp.com/docs/app-docs/configure/manifest-overview/
377
+
378
+ Deployment:
379
+ Build your app and follow the Root platform instructions to upload or register it.
380
+ `;
381
+
382
+ fs.writeFileSync(path.join(projectDir, 'MANIFEST.md'), appManifestReadme);
383
+ }
384
+
282
385
  console.log(`✅ Created ${options.name}`);
283
386
  console.log(`\n📝 Next steps:`);
284
387
  console.log(` cd ${options.name}`);
@@ -324,6 +427,43 @@ program
324
427
  console.log('✅ Configuration is valid');
325
428
  });
326
429
 
430
+ program
431
+ .command('validate-manifest')
432
+ .description('Validate root-manifest.json in the current folder')
433
+ .option('-f, --file <path>', 'Manifest file path', 'root-manifest.json')
434
+ .action((options) => {
435
+ const file = options.file || 'root-manifest.json';
436
+ if (!fs.existsSync(file)) {
437
+ console.error(`❌ Manifest not found: ${file}`);
438
+ process.exit(1);
439
+ }
440
+
441
+ let raw;
442
+ try {
443
+ raw = fs.readFileSync(file, 'utf8');
444
+ } catch (err) {
445
+ console.error('❌ Failed to read manifest:', err.message);
446
+ process.exit(1);
447
+ }
448
+
449
+ let manifest;
450
+ try {
451
+ manifest = JSON.parse(raw);
452
+ } catch (err) {
453
+ console.error('❌ Manifest is not valid JSON:', err.message);
454
+ process.exit(1);
455
+ }
456
+
457
+ const result = validateManifestObject(manifest);
458
+ if (!result.valid) {
459
+ console.error('❌ Manifest validation failed:');
460
+ for (const e of result.errors) console.error(' -', e);
461
+ process.exit(1);
462
+ }
463
+
464
+ console.log('✅ Manifest is valid');
465
+ });
466
+
327
467
  program
328
468
  .command('generate-manifest')
329
469
  .description('Generate a manifest file for Root Bots or Root Apps (auto-detects platform)')
@@ -341,16 +481,15 @@ program
341
481
  }
342
482
 
343
483
  const isRootBot = platform === 'root';
344
- const manifestFile = isRootBot ? 'root-manifest.json' : 'root-app-manifest.json';
484
+ const manifestFile = 'root-manifest.json';
345
485
 
346
486
  console.log(`\n🔍 Detected platform: ${isRootBot ? 'Root Bot (server-side)' : 'Root App (client-side)'}`);
347
487
 
348
488
  // Check if manifest already exists
349
489
  if (fs.existsSync(manifestFile)) {
350
- console.log(`⚠️ ${manifestFile} already exists in this directory.`);
351
- if (!options.interactive) {
352
- console.log('Use --interactive to configure a new one anyway.');
353
- return;
490
+ console.log(`⚠️ ${manifestFile} already exists it will be overwritten.`);
491
+ if (options.interactive) {
492
+ console.log('Interactive mode will update fields and overwrite the manifest.');
354
493
  }
355
494
  }
356
495
 
@@ -385,6 +524,16 @@ program
385
524
  description: '',
386
525
  author: '',
387
526
  homepage: '',
527
+ package: {
528
+ client: {
529
+ entry: 'dist/index.html',
530
+ assets: ['dist'],
531
+ node_modules: ['node_modules']
532
+ }
533
+ },
534
+ settings: {
535
+ ui: []
536
+ },
388
537
  permissions: {
389
538
  channel: {}
390
539
  }
@@ -483,13 +632,21 @@ program
483
632
  rl.close();
484
633
  }
485
634
 
486
- // Write manifest file
635
+ // Write manifest file (overwrite if exists)
487
636
  fs.writeFileSync(
488
637
  manifestFile,
489
638
  JSON.stringify(manifest, null, 2)
490
639
  );
491
-
492
- console.log(`\n✅ Generated ${manifestFile} successfully!\n`);
640
+
641
+ // Validate generated manifest
642
+ const validation = validateManifestObject(manifest);
643
+ if (!validation.valid) {
644
+ console.error('\n❌ Generated manifest failed validation:');
645
+ for (const e of validation.errors) console.error(' -', e);
646
+ process.exit(1);
647
+ }
648
+
649
+ console.log(`\n✅ Generated and validated ${manifestFile} successfully!\n`);
493
650
  console.log('📋 Manifest Details:');
494
651
  console.log(` Platform: ${isRootBot ? 'Root Bot (server-side)' : 'Root App (client-side)'}`);
495
652
  console.log(` ID: ${manifest.id}`);
@@ -519,6 +676,45 @@ program
519
676
  console.log('');
520
677
  });
521
678
 
679
+ program
680
+ .command('publish')
681
+ .description('Validate and publish the current root-manifest.json using @rootsdk/cli')
682
+ .option('-f, --file <path>', 'Manifest file to publish', 'root-manifest.json')
683
+ .option('--no-validate', 'Skip manifest validation step')
684
+ .action((options) => {
685
+ const file = options.file || 'root-manifest.json';
686
+ if (!fs.existsSync(file)) {
687
+ console.error(`❌ Manifest not found: ${file}`);
688
+ process.exit(1);
689
+ }
690
+
691
+ if (options.validate !== false) {
692
+ let manifest;
693
+ try {
694
+ manifest = JSON.parse(fs.readFileSync(file, 'utf8'));
695
+ } catch (err) {
696
+ console.error('❌ Failed to parse manifest:', err.message);
697
+ process.exit(1);
698
+ }
699
+
700
+ const result = validateManifestObject(manifest);
701
+ if (!result.valid) {
702
+ console.error('❌ Manifest validation failed:');
703
+ for (const e of result.errors) console.error(' -', e);
704
+ process.exit(1);
705
+ }
706
+ console.log('✅ Manifest validation passed');
707
+ }
708
+
709
+ try {
710
+ console.log('🔁 Running publish via @rootsdk/cli...');
711
+ execSync('npx @rootsdk/cli publish', { stdio: 'inherit' });
712
+ } catch (err) {
713
+ console.error('❌ Publish failed:', err.message);
714
+ process.exit(1);
715
+ }
716
+ });
717
+
522
718
  program
523
719
  .command('setup')
524
720
  .description('Interactive setup wizard to install only the dependencies you need')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "library.dr-conversion",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Unified interface for building multi-platform chat bots (Discord, Root, and more)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",