mage-remote-run 0.3.0 → 0.5.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.
@@ -24,21 +24,63 @@ import { registerCustomersCommands } from '../lib/commands/customers.js';
24
24
  import { registerOrdersCommands } from '../lib/commands/orders.js';
25
25
  import { registerEavCommands } from '../lib/commands/eav.js';
26
26
  import { registerProductsCommands } from '../lib/commands/products.js';
27
+ import { registerCompanyCommands } from '../lib/commands/company.js';
27
28
  import { registerTaxCommands } from '../lib/commands/tax.js';
28
29
  import { registerInventoryCommands } from '../lib/commands/inventory.js';
30
+ import { registerAdobeIoEventsCommands } from '../lib/commands/adobe-io-events.js';
31
+ import { getActiveProfile } from '../lib/config.js';
29
32
 
30
33
  registerConnectionCommands(program);
31
- registerWebsitesCommands(program);
32
- registerStoresCommands(program);
33
- registerCustomersCommands(program);
34
- registerOrdersCommands(program);
35
- registerEavCommands(program);
36
- registerProductsCommands(program);
37
- registerTaxCommands(program);
38
- registerInventoryCommands(program);
34
+
35
+ const profile = await getActiveProfile();
36
+
37
+ if (profile) {
38
+ registerWebsitesCommands(program);
39
+ registerStoresCommands(program);
40
+ registerCustomersCommands(program);
41
+ registerOrdersCommands(program);
42
+ registerEavCommands(program);
43
+ registerProductsCommands(program);
44
+ registerTaxCommands(program);
45
+ registerInventoryCommands(program);
46
+
47
+ if (profile.type === 'ac-cloud-paas' || profile.type === 'ac-saas') {
48
+ registerAdobeIoEventsCommands(program);
49
+ registerCompanyCommands(program);
50
+ }
51
+ }
52
+
53
+ program.hook('preAction', async (thisCommand, actionCommand) => {
54
+ // Check if we have an active profile and if format is not json/xml
55
+ // Note: 'options' are available on the command that has them defined.
56
+ // actionCommand is the command actually being executed.
57
+ if (profile) {
58
+ const config = await loadConfig();
59
+ if (config.showActiveConnectionHeader !== false) {
60
+ const opts = actionCommand.opts();
61
+ if (opts.format !== 'json' && opts.format !== 'xml') {
62
+ console.log(chalk.cyan(`Active Connection: ${chalk.bold(profile.name)} (${profile.type})`));
63
+ console.log(chalk.gray('━'.repeat(60)) + '\n');
64
+ }
65
+ }
66
+ }
67
+ });
39
68
 
40
69
  function resolveCommandMatch(parent, token) {
41
70
  const tokenLower = token.toLowerCase();
71
+
72
+ // Check for exact match first
73
+ const exactMatch = parent.commands.find((cmd) => {
74
+ return cmd.name().toLowerCase() === tokenLower;
75
+ });
76
+
77
+ if (exactMatch) {
78
+ return {
79
+ match: exactMatch,
80
+ matches: [exactMatch]
81
+ };
82
+ }
83
+
42
84
  const matches = parent.commands.filter((cmd) => {
43
85
  const name = cmd.name().toLowerCase();
44
86
  if (name.startsWith(tokenLower)) return true;
@@ -0,0 +1,61 @@
1
+ import { createClient } from '../api/factory.js';
2
+ import { printTable, handleError } from '../utils.js';
3
+ import chalk from 'chalk';
4
+
5
+ export function registerAdobeIoEventsCommands(program) {
6
+ const adobeIoEvents = program.command('adobe-io-event').description('Manage Adobe I/O Events');
7
+
8
+ adobeIoEvents.command('check-configuration')
9
+ .description('Check Adobe I/O Event configuration')
10
+ .option('-f, --format <type>', 'Output format (text, json, xml)', 'text')
11
+ .action(async (options) => {
12
+ try {
13
+ const client = await createClient();
14
+ const headers = {};
15
+ if (options.format === 'json') headers['Accept'] = 'application/json';
16
+ else if (options.format === 'xml') headers['Accept'] = 'application/xml';
17
+
18
+ // The endpoint is likely returning a simple boolean/string or a small object.
19
+ // Based on standard Magento APIs, let's assume it returns a boolean or object.
20
+ // We'll inspect the data structure.
21
+ const data = await client.get('V1/adobe_io_events/check_configuration', {}, { headers });
22
+
23
+ if (options.format === 'json') {
24
+ console.log(JSON.stringify(data, null, 2));
25
+ return;
26
+ }
27
+ if (options.format === 'xml') {
28
+ console.log(data);
29
+ return;
30
+ }
31
+
32
+ console.log(chalk.bold.blue('\nšŸ” Configuration Check Result'));
33
+ console.log(chalk.gray('━'.repeat(60)));
34
+
35
+ if (typeof data === 'object' && data !== null) {
36
+ if (Array.isArray(data)) {
37
+ console.log(JSON.stringify(data, null, 2));
38
+ } else {
39
+ Object.entries(data).forEach(([key, value]) => {
40
+ const label = key.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
41
+
42
+ let displayValue = value;
43
+ if (typeof value === 'boolean') {
44
+ displayValue = value ? chalk.green('Yes') : chalk.red('No');
45
+ } else if (value === null) {
46
+ displayValue = chalk.gray('null');
47
+ } else if (typeof value === 'object') {
48
+ displayValue = JSON.stringify(value);
49
+ }
50
+
51
+ console.log(` ${chalk.bold(label + ':').padEnd(35)} ${displayValue}`);
52
+ });
53
+ }
54
+ } else {
55
+ console.log(` ${data}`);
56
+ }
57
+ console.log('');
58
+
59
+ } catch (e) { handleError(e); }
60
+ });
61
+ }
@@ -0,0 +1,115 @@
1
+ import { createClient } from '../api/factory.js';
2
+ import { printTable, handleError } from '../utils.js';
3
+ import chalk from 'chalk';
4
+
5
+ export function registerCompanyCommands(program) {
6
+ const company = program.command('company').description('Manage companies');
7
+
8
+ company.command('list')
9
+ .description('List companies')
10
+ .option('-p, --page <number>', 'Page number', '1')
11
+ .option('-s, --size <number>', 'Page size', '20')
12
+ .option('--sort-by <field>', 'Field to sort by', 'entity_id')
13
+ .option('--sort-order <order>', 'Sort order (ASC, DESC)', 'ASC')
14
+ .option('-f, --format <type>', 'Output format (text, json, xml)', 'text')
15
+ .action(async (options) => {
16
+ try {
17
+ const client = await createClient();
18
+ const headers = {};
19
+ if (options.format === 'json') headers['Accept'] = 'application/json';
20
+ else if (options.format === 'xml') headers['Accept'] = 'application/xml';
21
+
22
+ const params = {
23
+ 'searchCriteria[currentPage]': options.page,
24
+ 'searchCriteria[pageSize]': options.size,
25
+ 'searchCriteria[sortOrders][0][field]': options.sortBy,
26
+ 'searchCriteria[sortOrders][0][direction]': options.sortOrder
27
+ };
28
+ const data = await client.get('V1/company', params, { headers });
29
+
30
+ if (options.format === 'json') {
31
+ console.log(JSON.stringify(data, null, 2));
32
+ return;
33
+ }
34
+ if (options.format === 'xml') {
35
+ console.log(data);
36
+ return;
37
+ }
38
+
39
+ // ID, Name, Email, Status, Rejected Reason
40
+ const rows = (data.items || []).map(c => [
41
+ c.id,
42
+ c.company_name,
43
+ c.company_email,
44
+ c.status,
45
+ c.sales_representative_id || '-'
46
+ ]);
47
+ console.log(chalk.bold(`Total: ${data.total_count}, Page: ${options.page}, Size: ${options.size}`));
48
+ printTable(['ID', 'Name', 'Email', 'Status', 'Sales Rep ID'], rows);
49
+ } catch (e) { handleError(e); }
50
+ });
51
+
52
+ company.command('show <companyId>')
53
+ .description('Show company details')
54
+ .option('-f, --format <type>', 'Output format (text, json, xml)', 'text')
55
+ .action(async (companyId, options) => {
56
+ try {
57
+ const client = await createClient();
58
+ let headers = {};
59
+ if (options.format === 'json') headers['Accept'] = 'application/json';
60
+ else if (options.format === 'xml') headers['Accept'] = 'application/xml';
61
+
62
+ let data;
63
+ try {
64
+ data = await client.get(`V1/company/${encodeURIComponent(companyId)}`, {}, { headers });
65
+ } catch (e) {
66
+ throw new Error(`Company '${companyId}' not found.`);
67
+ }
68
+
69
+ if (options.format === 'json') {
70
+ console.log(JSON.stringify(data, null, 2));
71
+ return;
72
+ }
73
+ if (options.format === 'xml') {
74
+ console.log(data);
75
+ return;
76
+ }
77
+
78
+ console.log(chalk.bold.blue('\nšŸ¢ Company Information'));
79
+ console.log(chalk.gray('━'.repeat(60)));
80
+
81
+ // General
82
+ console.log(chalk.bold('\nā„¹ļø General Information'));
83
+ console.log(` ${chalk.bold('ID:')} ${data.id}`);
84
+ console.log(` ${chalk.bold('Name:')} ${data.company_name}`);
85
+ console.log(` ${chalk.bold('Email:')} ${data.company_email}`);
86
+ console.log(` ${chalk.bold('Status:')} ${data.status}`);
87
+ console.log(` ${chalk.bold('Rejected Reason:')} ${data.reject_reason || '-'}`);
88
+ console.log(` ${chalk.bold('Sales Rep ID:')} ${data.sales_representative_id || '-'}`);
89
+
90
+ // Address
91
+ // Usually address info is nested or separate, but V1/company might return it directly
92
+ if (data.street) {
93
+ console.log(chalk.bold('\nšŸ“ Address'));
94
+ console.log(` ${chalk.bold('Street:')} ${data.street}`);
95
+ console.log(` ${chalk.bold('City:')} ${data.city}`);
96
+ console.log(` ${chalk.bold('Region:')} ${data.region}`);
97
+ console.log(` ${chalk.bold('Postcode:')} ${data.postcode}`);
98
+ console.log(` ${chalk.bold('Country:')} ${data.country_id}`);
99
+ console.log(` ${chalk.bold('Phone:')} ${data.telephone}`);
100
+ }
101
+
102
+ // Extension Attributes
103
+ if (data.extension_attributes && data.extension_attributes.applicable_payment_method) {
104
+ console.log(chalk.bold('\nšŸ’³ Payment Methods'));
105
+ const methods = data.extension_attributes.applicable_payment_method.length > 0
106
+ ? data.extension_attributes.applicable_payment_method.join(', ')
107
+ : 'None';
108
+ console.log(` ${methods}`);
109
+ }
110
+
111
+ console.log(chalk.gray('━'.repeat(60)));
112
+
113
+ } catch (e) { handleError(e); }
114
+ });
115
+ }
@@ -220,4 +220,19 @@ export function registerConnectionCommands(program) {
220
220
  console.log(chalk.green('Token cache cleared.'));
221
221
  } catch (e) { handleError(e); }
222
222
  });
223
+
224
+ connections.command('status-header <state>')
225
+ .description('Enable or disable the active connection header (on|off)')
226
+ .action(async (state) => {
227
+ try {
228
+ if (state !== 'on' && state !== 'off') {
229
+ console.error(chalk.red('Invalid state. Use "on" or "off".'));
230
+ return;
231
+ }
232
+ const config = await loadConfig();
233
+ config.showActiveConnectionHeader = state === 'on';
234
+ await saveConfig(config);
235
+ console.log(chalk.green(`Active connection header is now ${state === 'on' ? 'enabled' : 'disabled'}.`));
236
+ } catch (e) { handleError(e); }
237
+ });
223
238
  }
@@ -7,19 +7,35 @@ export function registerCustomersCommands(program) {
7
7
  const customers = program.command('customer').description('Manage customers');
8
8
 
9
9
  customers.command('list')
10
+ .description('List customers')
10
11
  .option('-p, --page <number>', 'Page number', '1')
11
12
  .option('-s, --size <number>', 'Page size', '20')
13
+ .option('-f, --format <type>', 'Output format (text, json, xml)', 'text')
12
14
  .action(async (options) => {
13
15
  try {
14
16
  const client = await createClient();
17
+ const headers = {};
18
+ if (options.format === 'json') headers['Accept'] = 'application/json';
19
+ else if (options.format === 'xml') headers['Accept'] = 'application/xml';
20
+
15
21
  const params = {
16
22
  'searchCriteria[currentPage]': options.page,
17
23
  'searchCriteria[pageSize]': options.size
18
24
  };
19
- const data = await client.get('V1/customers/search', params);
25
+ const data = await client.get('V1/customers/search', params, { headers });
26
+
27
+ if (options.format === 'json') {
28
+ console.log(JSON.stringify(data, null, 2));
29
+ return;
30
+ }
31
+ if (options.format === 'xml') {
32
+ console.log(data);
33
+ return;
34
+ }
35
+
20
36
  const rows = (data.items || []).map(c => [c.id, c.email, c.firstname, c.lastname, c.group_id]);
21
37
  console.log(chalk.bold(`Total: ${data.total_count}, Page: ${options.page}, Size: ${options.size}`));
22
- printTable(['ID', 'Email', 'First Name', 'Last Name', 'Group'], rows);
38
+ printTable(['ID', 'Email', 'First Name', 'Last Name', 'Group ID'], rows);
23
39
  } catch (e) { handleError(e); }
24
40
  });
25
41
 
@@ -12,14 +12,29 @@ export function registerEavCommands(program) {
12
12
  .description('List all attribute sets')
13
13
  .option('-p, --page <number>', 'Page number', '1')
14
14
  .option('-s, --size <number>', 'Page size', '20')
15
+ .option('-f, --format <type>', 'Output format (text, json, xml)', 'text')
15
16
  .action(async (options) => {
16
17
  try {
17
18
  const client = await createClient();
19
+ const headers = {};
20
+ if (options.format === 'json') headers['Accept'] = 'application/json';
21
+ else if (options.format === 'xml') headers['Accept'] = 'application/xml';
22
+
18
23
  const params = {
19
24
  'searchCriteria[currentPage]': options.page,
20
25
  'searchCriteria[pageSize]': options.size
21
26
  };
22
- const data = await client.get('V1/eav/attribute-sets/list', params);
27
+ const data = await client.get('V1/eav/attribute-sets/list', params, { headers });
28
+
29
+ if (options.format === 'json') {
30
+ console.log(JSON.stringify(data, null, 2));
31
+ return;
32
+ }
33
+ if (options.format === 'xml') {
34
+ console.log(data);
35
+ return;
36
+ }
37
+
23
38
  const rows = (data.items || []).map(set => [
24
39
  set.attribute_set_id,
25
40
  set.attribute_set_name,
@@ -60,16 +60,30 @@ export function registerInventoryCommands(program) {
60
60
  .description('List inventory sources')
61
61
  .option('-p, --page <number>', 'Page number', '1')
62
62
  .option('-s, --size <number>', 'Page size', '20')
63
+ .option('-f, --format <type>', 'Output format (text, json, xml)', 'text')
63
64
  .action(async (options) => {
64
65
  try {
65
66
  const client = await createClient();
67
+ const headers = {};
68
+ if (options.format === 'json') headers['Accept'] = 'application/json';
69
+ else if (options.format === 'xml') headers['Accept'] = 'application/xml';
70
+
66
71
  const params = {
67
72
  'searchCriteria[currentPage]': options.page,
68
73
  'searchCriteria[pageSize]': options.size
69
74
  };
70
- const data = await client.get('V1/inventory/sources', params);
71
- const items = data.items ? data.items : [];
72
- const rows = (Array.isArray(items) ? items : []).map(s => [s.source_code, s.name, s.enabled ? 'Yes' : 'No', s.postcode]);
75
+ const data = await client.get('V1/inventory/sources', params, { headers });
76
+
77
+ if (options.format === 'json') {
78
+ console.log(JSON.stringify(data, null, 2));
79
+ return;
80
+ }
81
+ if (options.format === 'xml') {
82
+ console.log(data);
83
+ return;
84
+ }
85
+
86
+ const rows = (data.items || []).map(s => [s.source_code, s.name, s.enabled ? 'Yes' : 'No', s.postcode]);
73
87
  console.log(chalk.bold(`Total: ${data.total_count}, Page: ${options.page}, Size: ${options.size}`));
74
88
  printTable(['Code', 'Name', 'Enabled', 'Postcode'], rows);
75
89
  } catch (e) { handleError(e); }
@@ -9,14 +9,29 @@ export function registerOrdersCommands(program) {
9
9
  orders.command('list')
10
10
  .option('-p, --page <number>', 'Page number', '1')
11
11
  .option('-s, --size <number>', 'Page size', '20')
12
+ .option('-f, --format <type>', 'Output format (text, json, xml)', 'text')
12
13
  .action(async (options) => {
13
14
  try {
14
15
  const client = await createClient();
16
+ const headers = {};
17
+ if (options.format === 'json') headers['Accept'] = 'application/json';
18
+ else if (options.format === 'xml') headers['Accept'] = 'application/xml';
19
+
15
20
  const params = {
16
21
  'searchCriteria[currentPage]': options.page,
17
22
  'searchCriteria[pageSize]': options.size
18
23
  };
19
- const data = await client.get('V1/orders', params);
24
+ const data = await client.get('V1/orders', params, { headers });
25
+
26
+ if (options.format === 'json') {
27
+ console.log(JSON.stringify(data, null, 2));
28
+ return;
29
+ }
30
+ if (options.format === 'xml') {
31
+ console.log(data);
32
+ return;
33
+ }
34
+
20
35
  const rows = (data.items || []).map(o => [o.entity_id, o.increment_id, o.status, o.grand_total, o.customer_email]);
21
36
  console.log(chalk.bold(`Total: ${data.total_count}, Page: ${options.page}, Size: ${options.size}`));
22
37
  printTable(['ID', 'Increment ID', 'Status', 'Total', 'Email'], rows);
@@ -9,18 +9,33 @@ export function registerProductsCommands(program) {
9
9
  .description('List products')
10
10
  .option('-p, --page <number>', 'Page number', '1')
11
11
  .option('-s, --size <number>', 'Page size', '20')
12
- .option('--sort-by <attribute>', 'Attribute to sort by', 'id')
13
- .option('--sort-order <order>', 'Sort order (ASC or DESC)', 'ASC')
12
+ .option('--sort-by <field>', 'Field to sort by', 'entity_id')
13
+ .option('--sort-order <order>', 'Sort order (ASC, DESC)', 'ASC')
14
+ .option('-f, --format <type>', 'Output format (text, json, xml)', 'text')
14
15
  .action(async (options) => {
15
16
  try {
16
17
  const client = await createClient();
18
+ const headers = {};
19
+ if (options.format === 'json') headers['Accept'] = 'application/json';
20
+ else if (options.format === 'xml') headers['Accept'] = 'application/xml';
21
+
17
22
  const params = {
18
23
  'searchCriteria[currentPage]': options.page,
19
24
  'searchCriteria[pageSize]': options.size,
20
25
  'searchCriteria[sortOrders][0][field]': options.sortBy,
21
26
  'searchCriteria[sortOrders][0][direction]': options.sortOrder
22
27
  };
23
- const data = await client.get('V1/products', params);
28
+ const data = await client.get('V1/products', params, { headers });
29
+
30
+ if (options.format === 'json') {
31
+ console.log(JSON.stringify(data, null, 2));
32
+ return;
33
+ }
34
+ if (options.format === 'xml') {
35
+ console.log(data);
36
+ return;
37
+ }
38
+
24
39
  const rows = (data.items || []).map(p => [p.id, p.sku, p.name, p.type_id, p.price]);
25
40
  console.log(chalk.bold(`Total: ${data.total_count}, Page: ${options.page}, Size: ${options.size}`));
26
41
  printTable(['ID', 'SKU', 'Name', 'Type', 'Price'], rows);
@@ -11,14 +11,29 @@ export function registerTaxCommands(program) {
11
11
  .description('List tax classes')
12
12
  .option('-p, --page <number>', 'Page number', '1')
13
13
  .option('-s, --size <number>', 'Page size', '20')
14
+ .option('-f, --format <type>', 'Output format (text, json, xml)', 'text')
14
15
  .action(async (options) => {
15
16
  try {
16
17
  const client = await createClient();
18
+ const headers = {};
19
+ if (options.format === 'json') headers['Accept'] = 'application/json';
20
+ else if (options.format === 'xml') headers['Accept'] = 'application/xml';
21
+
17
22
  const params = {
18
23
  'searchCriteria[currentPage]': options.page,
19
24
  'searchCriteria[pageSize]': options.size
20
25
  };
21
- const data = await client.get('V1/taxClasses/search', params);
26
+ const data = await client.get('V1/taxClasses/search', params, { headers });
27
+
28
+ if (options.format === 'json') {
29
+ console.log(JSON.stringify(data, null, 2));
30
+ return;
31
+ }
32
+ if (options.format === 'xml') {
33
+ console.log(data);
34
+ return;
35
+ }
36
+
22
37
  const rows = (data.items || []).map(tc => [
23
38
  tc.class_id,
24
39
  tc.class_name,
package/lib/config.js CHANGED
@@ -48,7 +48,8 @@ export async function getActiveProfile() {
48
48
  if (!config.activeProfile || !config.profiles[config.activeProfile]) {
49
49
  return null;
50
50
  }
51
- return config.profiles[config.activeProfile];
51
+ const profile = config.profiles[config.activeProfile];
52
+ return { ...profile, name: config.activeProfile };
52
53
  }
53
54
 
54
55
  export function getConfigPath() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mage-remote-run",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "The remote swiss army knife for Magento Open Source, Mage-OS, Adobe Commerce",
5
5
  "main": "index.js",
6
6
  "scripts": {