@ktmcp-cli/seatmap-display 1.9.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.
- package/README.md +80 -0
- package/bin/seatmap-display.js +54 -0
- package/package.json +33 -0
- package/src/commands/config.js +42 -0
- package/src/commands/display-seat-maps.js +103 -0
- package/src/lib/api.js +59 -0
- package/src/lib/config.js +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Seatmap Display CLI
|
|
2
|
+
|
|
3
|
+
Production-ready command-line interface for the Seatmap Display API.
|
|
4
|
+
|
|
5
|
+
> **⚠️ Unofficial CLI** - This tool is an independent project built on the public API.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Complete coverage of Seatmap Display API endpoints
|
|
10
|
+
- Simple, intuitive command structure
|
|
11
|
+
- JSON and pretty-print output formats
|
|
12
|
+
- Persistent configuration storage
|
|
13
|
+
- Progress indicators for async operations
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g @ktmcp-cli/seatmap-display
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or install locally:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
cd seatmap-display
|
|
25
|
+
npm install
|
|
26
|
+
npm link
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
### Set API Key
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
seatmap-display config set apiKey YOUR_KEY_HERE
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Environment Variables
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
export API_KEY=your_key_here
|
|
41
|
+
export API_BASE_URL=https://api.example.com
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### View Configuration
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
seatmap-display config list
|
|
48
|
+
seatmap-display config get apiKey
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
### display-seat-maps
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# List items
|
|
57
|
+
seatmap-display display-seat-maps list
|
|
58
|
+
|
|
59
|
+
# Get item by ID
|
|
60
|
+
seatmap-display display-seat-maps get <id>
|
|
61
|
+
|
|
62
|
+
# Output as JSON
|
|
63
|
+
seatmap-display display-seat-maps list --json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Available Resources
|
|
67
|
+
|
|
68
|
+
- `display-seat-maps`
|
|
69
|
+
|
|
70
|
+
## JSON Output
|
|
71
|
+
|
|
72
|
+
All commands support `--json` flag for machine-readable output:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
seatmap-display display-seat-maps list --json
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT License - see LICENSE file for details.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { readFileSync } from 'fs';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { dirname, join } from 'path';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
|
|
9
|
+
import config from '../src/commands/config.js';
|
|
10
|
+
import displaySeatMaps from '../src/commands/display-seat-maps.js';
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = dirname(__filename);
|
|
14
|
+
|
|
15
|
+
const packageJson = JSON.parse(
|
|
16
|
+
readFileSync(join(__dirname, '../package.json'), 'utf-8')
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
const program = new Command();
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.name('seatmap-display')
|
|
23
|
+
.description(chalk.cyan('Before using this API, we recommend you read our **[Authorization Guide](https://developers.amadeus.com/self-service/apis-docs/guides/authorization-262)** for more information on how to generate an access token.
|
|
24
|
+
|
|
25
|
+
Please also be aware that our test environment is based on a subset of the production, if you are not returning any results try with big cities/airports like LON (London) or NYC (New-York).'))
|
|
26
|
+
.version(packageJson.version, '-v, --version', 'Output the current version')
|
|
27
|
+
.addHelpText('after', `
|
|
28
|
+
${chalk.bold('Examples:')}
|
|
29
|
+
$ seatmap-display config set apiKey YOUR_KEY
|
|
30
|
+
$ seatmap-display display-seat-maps list
|
|
31
|
+
$ seatmap-display display-seat-maps list --json
|
|
32
|
+
|
|
33
|
+
${chalk.bold('Environment Variables:')}
|
|
34
|
+
API_KEY API authentication key
|
|
35
|
+
API_BASE_URL API base URL
|
|
36
|
+
API_TIMEOUT Request timeout in ms (default: 30000)
|
|
37
|
+
|
|
38
|
+
${chalk.bold('Documentation:')}
|
|
39
|
+
GitHub: ${chalk.blue('https://github.com/ktmcp-cli/seatmap-display')}
|
|
40
|
+
`);
|
|
41
|
+
|
|
42
|
+
program.addCommand(config);
|
|
43
|
+
program.addCommand(displaySeatMaps);
|
|
44
|
+
|
|
45
|
+
process.on('unhandledRejection', (error) => {
|
|
46
|
+
console.error(chalk.red('Unhandled error:'), error);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
program.parse(process.argv);
|
|
51
|
+
|
|
52
|
+
if (!process.argv.slice(2).length) {
|
|
53
|
+
program.outputHelp();
|
|
54
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ktmcp-cli/seatmap-display",
|
|
3
|
+
"version": "1.9.2",
|
|
4
|
+
"description": "Before using this API, we recommend you read our **[Authorization Guide](https://developers.amadeus.com/self-service/apis-docs/guides/authorization-262)** for more information on how to generate an access token. \n\nPlease also be aware that our test environment is based on a subset of the production, if you are not returning any results try with big cities/airports like LON (London) or NYC (New-York).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "bin/seatmap-display.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"seatmap-display": "./bin/seatmap-display.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node bin/seatmap-display.js",
|
|
12
|
+
"dev": "node bin/seatmap-display.js"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"cli",
|
|
16
|
+
"api",
|
|
17
|
+
"seatmap-display",
|
|
18
|
+
"ktmcp"
|
|
19
|
+
],
|
|
20
|
+
"author": "KTMCP",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"commander": "^12.0.0",
|
|
24
|
+
"axios": "^1.6.0",
|
|
25
|
+
"chalk": "^5.3.0",
|
|
26
|
+
"conf": "^12.0.0",
|
|
27
|
+
"dotenv": "^16.4.0",
|
|
28
|
+
"ora": "^8.0.1"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18.0.0"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { loadConfig, setConfig, getConfig, saveConfig } from '../lib/config.js';
|
|
4
|
+
|
|
5
|
+
const config = new Command('config');
|
|
6
|
+
|
|
7
|
+
config.description('Manage CLI configuration');
|
|
8
|
+
|
|
9
|
+
config
|
|
10
|
+
.command('set <key> <value>')
|
|
11
|
+
.description('Set a configuration value')
|
|
12
|
+
.action((key, value) => {
|
|
13
|
+
if (setConfig(key, value)) {
|
|
14
|
+
console.log(chalk.green(`✓ Set ${key} = ${value}`));
|
|
15
|
+
} else {
|
|
16
|
+
console.error(chalk.red('Failed to save configuration'));
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
config
|
|
22
|
+
.command('get <key>')
|
|
23
|
+
.description('Get a configuration value')
|
|
24
|
+
.action((key) => {
|
|
25
|
+
const value = getConfig(key);
|
|
26
|
+
if (value !== undefined) {
|
|
27
|
+
console.log(chalk.cyan(`${key} = ${value}`));
|
|
28
|
+
} else {
|
|
29
|
+
console.log(chalk.yellow(`${key} is not set`));
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
config
|
|
34
|
+
.command('list')
|
|
35
|
+
.description('List all configuration values')
|
|
36
|
+
.action(() => {
|
|
37
|
+
const all = loadConfig();
|
|
38
|
+
console.log(chalk.cyan('Current configuration:'));
|
|
39
|
+
console.log(JSON.stringify(all, null, 2));
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export default config;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { createClient, handleError } from '../lib/api.js';
|
|
5
|
+
|
|
6
|
+
const displaySeatMaps = new Command('display-seat-maps');
|
|
7
|
+
|
|
8
|
+
displaySeatMaps
|
|
9
|
+
.description('Manage display-seat-maps');
|
|
10
|
+
|
|
11
|
+
display-seat-maps
|
|
12
|
+
.command('get')
|
|
13
|
+
.description('Returns all the seat maps of a given order.')
|
|
14
|
+
.option('--json', 'Output as JSON')
|
|
15
|
+
.option('-v, --verbose', 'Verbose output')
|
|
16
|
+
.action(async (options) => {
|
|
17
|
+
const spinner = ora('Returns all the seat maps of a given order....').start();
|
|
18
|
+
try {
|
|
19
|
+
const client = createClient();
|
|
20
|
+
const response = await client.get(`/shopping/seatmaps`);
|
|
21
|
+
const result = { success: true, status: response.status, data: response.data };
|
|
22
|
+
|
|
23
|
+
spinner.succeed('Success');
|
|
24
|
+
|
|
25
|
+
if (result.success) {
|
|
26
|
+
if (options.json) {
|
|
27
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
28
|
+
} else {
|
|
29
|
+
// Detail output
|
|
30
|
+
const item = result.data;
|
|
31
|
+
console.log(chalk.bold('Details:'));
|
|
32
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
33
|
+
Object.entries(item).slice(0, 10).forEach(([key, value]) => {
|
|
34
|
+
console.log(chalk.cyan(key + ':'), String(value).slice(0, 100));
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
process.exit(0);
|
|
38
|
+
} else {
|
|
39
|
+
spinner.fail(`Failed (${result.status})`);
|
|
40
|
+
console.error(chalk.red(result.message));
|
|
41
|
+
if (options.verbose && result.data) {
|
|
42
|
+
console.error(chalk.yellow('\nResponse data:'));
|
|
43
|
+
console.error(JSON.stringify(result.data, null, 2));
|
|
44
|
+
}
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
} catch (error) {
|
|
48
|
+
spinner.fail('Error occurred');
|
|
49
|
+
console.error(chalk.red('Error:'), error.message);
|
|
50
|
+
if (options.verbose) {
|
|
51
|
+
console.error(error.stack);
|
|
52
|
+
}
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
display-seat-maps
|
|
58
|
+
.command('get')
|
|
59
|
+
.description('Returns all the seat maps of a given flightOffer.')
|
|
60
|
+
.option('--json', 'Output as JSON')
|
|
61
|
+
.option('-v, --verbose', 'Verbose output')
|
|
62
|
+
.action(async (options) => {
|
|
63
|
+
const spinner = ora('Returns all the seat maps of a given flightOffer....').start();
|
|
64
|
+
try {
|
|
65
|
+
const client = createClient();
|
|
66
|
+
const response = await client.post(`/shopping/seatmaps`);
|
|
67
|
+
const result = { success: true, status: response.status, data: response.data };
|
|
68
|
+
|
|
69
|
+
spinner.succeed('Success');
|
|
70
|
+
|
|
71
|
+
if (result.success) {
|
|
72
|
+
if (options.json) {
|
|
73
|
+
console.log(JSON.stringify(result.data, null, 2));
|
|
74
|
+
} else {
|
|
75
|
+
// Detail output
|
|
76
|
+
const item = result.data;
|
|
77
|
+
console.log(chalk.bold('Details:'));
|
|
78
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
79
|
+
Object.entries(item).slice(0, 10).forEach(([key, value]) => {
|
|
80
|
+
console.log(chalk.cyan(key + ':'), String(value).slice(0, 100));
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
process.exit(0);
|
|
84
|
+
} else {
|
|
85
|
+
spinner.fail(`Failed (${result.status})`);
|
|
86
|
+
console.error(chalk.red(result.message));
|
|
87
|
+
if (options.verbose && result.data) {
|
|
88
|
+
console.error(chalk.yellow('\nResponse data:'));
|
|
89
|
+
console.error(JSON.stringify(result.data, null, 2));
|
|
90
|
+
}
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
} catch (error) {
|
|
94
|
+
spinner.fail('Error occurred');
|
|
95
|
+
console.error(chalk.red('Error:'), error.message);
|
|
96
|
+
if (options.verbose) {
|
|
97
|
+
console.error(error.stack);
|
|
98
|
+
}
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
export default displaySeatMaps;
|
package/src/lib/api.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { loadConfig } from './config.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Create axios instance with configuration
|
|
6
|
+
*/
|
|
7
|
+
function createClient(options = {}) {
|
|
8
|
+
const config = loadConfig();
|
|
9
|
+
const baseURL = options.baseUrl || config.baseUrl || 'https://api.example.com';
|
|
10
|
+
|
|
11
|
+
const instance = axios.create({
|
|
12
|
+
baseURL,
|
|
13
|
+
timeout: options.timeout || config.timeout || 30000,
|
|
14
|
+
headers: {
|
|
15
|
+
'User-Agent': '@ktmcp-cli/seatmap-display/1.0.0',
|
|
16
|
+
'Content-Type': 'application/json'
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Add authentication
|
|
21
|
+
instance.interceptors.request.use((config) => {
|
|
22
|
+
// No authentication configured
|
|
23
|
+
return config;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return instance;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Handle API errors consistently
|
|
31
|
+
*/
|
|
32
|
+
function handleError(error) {
|
|
33
|
+
if (error.response) {
|
|
34
|
+
return {
|
|
35
|
+
success: false,
|
|
36
|
+
status: error.response.status,
|
|
37
|
+
statusText: error.response.statusText,
|
|
38
|
+
message: error.response.data?.message ||
|
|
39
|
+
error.response.data?.error ||
|
|
40
|
+
'API request failed',
|
|
41
|
+
data: error.response.data
|
|
42
|
+
};
|
|
43
|
+
} else if (error.request) {
|
|
44
|
+
return {
|
|
45
|
+
success: false,
|
|
46
|
+
status: 0,
|
|
47
|
+
message: 'No response from server',
|
|
48
|
+
error: error.message
|
|
49
|
+
};
|
|
50
|
+
} else {
|
|
51
|
+
return {
|
|
52
|
+
success: false,
|
|
53
|
+
status: 0,
|
|
54
|
+
message: error.message
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export { createClient, handleError };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import dotenv from 'dotenv';
|
|
5
|
+
|
|
6
|
+
dotenv.config();
|
|
7
|
+
|
|
8
|
+
const CONFIG_DIR = join(homedir(), '.seatmap-display');
|
|
9
|
+
const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
10
|
+
|
|
11
|
+
const DEFAULT_CONFIG = {
|
|
12
|
+
baseUrl: process.env.API_BASE_URL || 'https://api.example.com',
|
|
13
|
+
apiKey: process.env.API_KEY || '',
|
|
14
|
+
timeout: parseInt(process.env.API_TIMEOUT || '30000', 10)
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function loadConfig() {
|
|
18
|
+
if (existsSync(CONFIG_FILE)) {
|
|
19
|
+
try {
|
|
20
|
+
const fileConfig = JSON.parse(readFileSync(CONFIG_FILE, 'utf8'));
|
|
21
|
+
return { ...DEFAULT_CONFIG, ...fileConfig };
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error('Error reading config file:', error.message);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return DEFAULT_CONFIG;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function saveConfig(config) {
|
|
30
|
+
try {
|
|
31
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
32
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
35
|
+
return true;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error('Error saving config:', error.message);
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function getConfig(key) {
|
|
43
|
+
const config = loadConfig();
|
|
44
|
+
return config[key];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function setConfig(key, value) {
|
|
48
|
+
const config = loadConfig();
|
|
49
|
+
config[key] = value;
|
|
50
|
+
return saveConfig(config);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export default {
|
|
54
|
+
loadConfig,
|
|
55
|
+
saveConfig,
|
|
56
|
+
getConfig,
|
|
57
|
+
setConfig
|
|
58
|
+
};
|