@objectstack/cli 4.0.1 → 4.0.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +17 -0
- package/dist/commands/auth/login.d.ts +13 -0
- package/dist/commands/auth/login.d.ts.map +1 -0
- package/dist/commands/auth/login.js +167 -0
- package/dist/commands/auth/login.js.map +1 -0
- package/dist/commands/auth/logout.d.ts +10 -0
- package/dist/commands/auth/logout.d.ts.map +1 -0
- package/dist/commands/auth/logout.js +46 -0
- package/dist/commands/auth/logout.js.map +1 -0
- package/dist/commands/auth/whoami.d.ts +12 -0
- package/dist/commands/auth/whoami.d.ts.map +1 -0
- package/dist/commands/auth/whoami.js +76 -0
- package/dist/commands/auth/whoami.js.map +1 -0
- package/dist/commands/data/create.d.ts +17 -0
- package/dist/commands/data/create.d.ts.map +1 -0
- package/dist/commands/data/create.js +106 -0
- package/dist/commands/data/create.js.map +1 -0
- package/dist/commands/data/delete.d.ts +16 -0
- package/dist/commands/data/delete.d.ts.map +1 -0
- package/dist/commands/data/delete.js +78 -0
- package/dist/commands/data/delete.js.map +1 -0
- package/dist/commands/data/get.d.ts +16 -0
- package/dist/commands/data/get.d.ts.map +1 -0
- package/dist/commands/data/get.js +79 -0
- package/dist/commands/data/get.js.map +1 -0
- package/dist/commands/data/query.d.ts +20 -0
- package/dist/commands/data/query.d.ts.map +1 -0
- package/dist/commands/data/query.js +118 -0
- package/dist/commands/data/query.js.map +1 -0
- package/dist/commands/data/update.d.ts +18 -0
- package/dist/commands/data/update.d.ts.map +1 -0
- package/dist/commands/data/update.js +110 -0
- package/dist/commands/data/update.js.map +1 -0
- package/dist/commands/meta/delete.d.ts +16 -0
- package/dist/commands/meta/delete.d.ts.map +1 -0
- package/dist/commands/meta/delete.js +73 -0
- package/dist/commands/meta/delete.js.map +1 -0
- package/dist/commands/meta/get.d.ts +16 -0
- package/dist/commands/meta/get.d.ts.map +1 -0
- package/dist/commands/meta/get.js +65 -0
- package/dist/commands/meta/get.js.map +1 -0
- package/dist/commands/meta/list.d.ts +15 -0
- package/dist/commands/meta/list.d.ts.map +1 -0
- package/dist/commands/meta/list.js +103 -0
- package/dist/commands/meta/list.js.map +1 -0
- package/dist/commands/meta/register.d.ts +16 -0
- package/dist/commands/meta/register.d.ts.map +1 -0
- package/dist/commands/meta/register.js +89 -0
- package/dist/commands/meta/register.js.map +1 -0
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +33 -0
- package/dist/commands/serve.js.map +1 -1
- package/dist/utils/api-client.d.ts +42 -0
- package/dist/utils/api-client.d.ts.map +1 -0
- package/dist/utils/api-client.js +53 -0
- package/dist/utils/api-client.js.map +1 -0
- package/dist/utils/auth-config.d.ts +50 -0
- package/dist/utils/auth-config.d.ts.map +1 -0
- package/dist/utils/auth-config.js +73 -0
- package/dist/utils/auth-config.js.map +1 -0
- package/dist/utils/output-formatter.d.ts +9 -0
- package/dist/utils/output-formatter.d.ts.map +1 -0
- package/dist/utils/output-formatter.js +80 -0
- package/dist/utils/output-formatter.js.map +1 -0
- package/package.json +17 -12
- package/src/commands/auth/login.ts +188 -0
- package/src/commands/auth/logout.ts +51 -0
- package/src/commands/auth/whoami.ts +85 -0
- package/src/commands/data/create.ts +110 -0
- package/src/commands/data/delete.ts +84 -0
- package/src/commands/data/get.ts +84 -0
- package/src/commands/data/query.ts +127 -0
- package/src/commands/data/update.ts +114 -0
- package/src/commands/meta/delete.ts +79 -0
- package/src/commands/meta/get.ts +73 -0
- package/src/commands/meta/list.ts +105 -0
- package/src/commands/meta/register.ts +97 -0
- package/src/commands/serve.ts +38 -0
- package/src/utils/api-client.ts +88 -0
- package/src/utils/auth-config.ts +107 -0
- package/src/utils/output-formatter.ts +91 -0
- package/test/remote-api-commands.test.ts +188 -0
- package/test/remote-api-utils.test.ts +196 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
|
+
import { printError } from '../../utils/format.js';
|
|
5
|
+
import { createApiClient, requireAuth } from '../../utils/api-client.js';
|
|
6
|
+
import { formatOutput } from '../../utils/output-formatter.js';
|
|
7
|
+
|
|
8
|
+
export default class DataGet extends Command {
|
|
9
|
+
static override description = 'Get a single record by ID';
|
|
10
|
+
|
|
11
|
+
static override examples = [
|
|
12
|
+
'$ os data get project_task abc123',
|
|
13
|
+
'$ os data get project_task abc123 --format json',
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
static override args = {
|
|
17
|
+
object: Args.string({
|
|
18
|
+
description: 'Object name (snake_case)',
|
|
19
|
+
required: true,
|
|
20
|
+
}),
|
|
21
|
+
id: Args.string({
|
|
22
|
+
description: 'Record ID',
|
|
23
|
+
required: true,
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
static override flags = {
|
|
28
|
+
url: Flags.string({
|
|
29
|
+
char: 'u',
|
|
30
|
+
description: 'Server URL',
|
|
31
|
+
env: 'OBJECTSTACK_URL',
|
|
32
|
+
}),
|
|
33
|
+
token: Flags.string({
|
|
34
|
+
char: 't',
|
|
35
|
+
description: 'Authentication token',
|
|
36
|
+
env: 'OBJECTSTACK_TOKEN',
|
|
37
|
+
}),
|
|
38
|
+
format: Flags.string({
|
|
39
|
+
char: 'f',
|
|
40
|
+
description: 'Output format',
|
|
41
|
+
options: ['json', 'table', 'yaml'],
|
|
42
|
+
default: 'table',
|
|
43
|
+
}),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
async run(): Promise<void> {
|
|
47
|
+
const { args, flags } = await this.parse(DataGet);
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const { client, token } = await createApiClient({
|
|
51
|
+
url: flags.url,
|
|
52
|
+
token: flags.token,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
requireAuth(token);
|
|
56
|
+
|
|
57
|
+
// Get the record
|
|
58
|
+
const result = await client.data.get(args.object, args.id);
|
|
59
|
+
|
|
60
|
+
if (flags.format === 'json') {
|
|
61
|
+
formatOutput(result, 'json');
|
|
62
|
+
} else if (flags.format === 'yaml') {
|
|
63
|
+
formatOutput(result, 'yaml');
|
|
64
|
+
} else {
|
|
65
|
+
// Table format - show the record
|
|
66
|
+
if (result.record) {
|
|
67
|
+
formatOutput(result.record, 'table');
|
|
68
|
+
} else {
|
|
69
|
+
console.log('Record not found.');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} catch (error: any) {
|
|
73
|
+
if (flags.format === 'json') {
|
|
74
|
+
console.log(JSON.stringify({
|
|
75
|
+
success: false,
|
|
76
|
+
error: error.message,
|
|
77
|
+
}, null, 2));
|
|
78
|
+
this.exit(1);
|
|
79
|
+
}
|
|
80
|
+
printError(error.message || String(error));
|
|
81
|
+
this.exit(1);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
|
+
import { printError } from '../../utils/format.js';
|
|
5
|
+
import { createApiClient, requireAuth } from '../../utils/api-client.js';
|
|
6
|
+
import { formatOutput } from '../../utils/output-formatter.js';
|
|
7
|
+
|
|
8
|
+
export default class DataQuery extends Command {
|
|
9
|
+
static override description = 'Query records from an object';
|
|
10
|
+
|
|
11
|
+
static override examples = [
|
|
12
|
+
'$ os data query project_task',
|
|
13
|
+
'$ os data query project_task --filter \'{"status":"open"}\'',
|
|
14
|
+
'$ os data query project_task --limit 10 --offset 0',
|
|
15
|
+
'$ os data query project_task --fields name,status,created_at',
|
|
16
|
+
'$ os data query project_task --sort -created_at',
|
|
17
|
+
'$ os data query project_task --format json',
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
static override args = {
|
|
21
|
+
object: Args.string({
|
|
22
|
+
description: 'Object name (snake_case)',
|
|
23
|
+
required: true,
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
static override flags = {
|
|
28
|
+
url: Flags.string({
|
|
29
|
+
char: 'u',
|
|
30
|
+
description: 'Server URL',
|
|
31
|
+
env: 'OBJECTSTACK_URL',
|
|
32
|
+
}),
|
|
33
|
+
token: Flags.string({
|
|
34
|
+
char: 't',
|
|
35
|
+
description: 'Authentication token',
|
|
36
|
+
env: 'OBJECTSTACK_TOKEN',
|
|
37
|
+
}),
|
|
38
|
+
filter: Flags.string({
|
|
39
|
+
description: 'Filter criteria as JSON object',
|
|
40
|
+
}),
|
|
41
|
+
fields: Flags.string({
|
|
42
|
+
description: 'Comma-separated list of fields to retrieve',
|
|
43
|
+
}),
|
|
44
|
+
sort: Flags.string({
|
|
45
|
+
description: 'Sort field (prefix with - for descending)',
|
|
46
|
+
}),
|
|
47
|
+
limit: Flags.integer({
|
|
48
|
+
description: 'Maximum number of records to return',
|
|
49
|
+
default: 50,
|
|
50
|
+
}),
|
|
51
|
+
offset: Flags.integer({
|
|
52
|
+
description: 'Number of records to skip',
|
|
53
|
+
default: 0,
|
|
54
|
+
}),
|
|
55
|
+
format: Flags.string({
|
|
56
|
+
char: 'f',
|
|
57
|
+
description: 'Output format',
|
|
58
|
+
options: ['json', 'table', 'yaml'],
|
|
59
|
+
default: 'table',
|
|
60
|
+
}),
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
async run(): Promise<void> {
|
|
64
|
+
const { args, flags } = await this.parse(DataQuery);
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const { client, token } = await createApiClient({
|
|
68
|
+
url: flags.url,
|
|
69
|
+
token: flags.token,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
requireAuth(token);
|
|
73
|
+
|
|
74
|
+
// Build query options
|
|
75
|
+
const queryOptions: any = {
|
|
76
|
+
limit: flags.limit,
|
|
77
|
+
offset: flags.offset,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
if (flags.filter) {
|
|
81
|
+
try {
|
|
82
|
+
queryOptions.where = JSON.parse(flags.filter);
|
|
83
|
+
} catch (e) {
|
|
84
|
+
throw new Error(`Invalid filter JSON: ${(e as Error).message}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (flags.fields) {
|
|
89
|
+
queryOptions.fields = flags.fields.split(',').map(f => f.trim());
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (flags.sort) {
|
|
93
|
+
queryOptions.orderBy = flags.sort;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Execute query
|
|
97
|
+
const result = await client.data.query(args.object, queryOptions);
|
|
98
|
+
|
|
99
|
+
if (flags.format === 'json') {
|
|
100
|
+
formatOutput(result, 'json');
|
|
101
|
+
} else if (flags.format === 'yaml') {
|
|
102
|
+
formatOutput(result, 'yaml');
|
|
103
|
+
} else {
|
|
104
|
+
// Table format
|
|
105
|
+
if (result.records && result.records.length > 0) {
|
|
106
|
+
formatOutput(result.records, 'table');
|
|
107
|
+
} else {
|
|
108
|
+
console.log('No records found.');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (result.total !== undefined) {
|
|
112
|
+
console.log(`\nTotal: ${result.total} record(s)`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
} catch (error: any) {
|
|
116
|
+
if (flags.format === 'json') {
|
|
117
|
+
console.log(JSON.stringify({
|
|
118
|
+
success: false,
|
|
119
|
+
error: error.message,
|
|
120
|
+
}, null, 2));
|
|
121
|
+
this.exit(1);
|
|
122
|
+
}
|
|
123
|
+
printError(error.message || String(error));
|
|
124
|
+
this.exit(1);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
|
+
import { printError, printSuccess } from '../../utils/format.js';
|
|
5
|
+
import { createApiClient, requireAuth } from '../../utils/api-client.js';
|
|
6
|
+
import { formatOutput } from '../../utils/output-formatter.js';
|
|
7
|
+
|
|
8
|
+
export default class DataUpdate extends Command {
|
|
9
|
+
static override description = 'Update an existing record';
|
|
10
|
+
|
|
11
|
+
static override examples = [
|
|
12
|
+
'$ os data update project_task abc123 \'{"status":"completed"}\'',
|
|
13
|
+
'$ os data update project_task abc123 --data update-data.json',
|
|
14
|
+
'$ os data update project_task abc123 --data update-data.json --format json',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
static override args = {
|
|
18
|
+
object: Args.string({
|
|
19
|
+
description: 'Object name (snake_case)',
|
|
20
|
+
required: true,
|
|
21
|
+
}),
|
|
22
|
+
id: Args.string({
|
|
23
|
+
description: 'Record ID',
|
|
24
|
+
required: true,
|
|
25
|
+
}),
|
|
26
|
+
data: Args.string({
|
|
27
|
+
description: 'Update data as JSON string (or use --data flag for file)',
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
static override flags = {
|
|
32
|
+
url: Flags.string({
|
|
33
|
+
char: 'u',
|
|
34
|
+
description: 'Server URL',
|
|
35
|
+
env: 'OBJECTSTACK_URL',
|
|
36
|
+
}),
|
|
37
|
+
token: Flags.string({
|
|
38
|
+
char: 't',
|
|
39
|
+
description: 'Authentication token',
|
|
40
|
+
env: 'OBJECTSTACK_TOKEN',
|
|
41
|
+
}),
|
|
42
|
+
data: Flags.string({
|
|
43
|
+
char: 'd',
|
|
44
|
+
description: 'Path to JSON file containing update data',
|
|
45
|
+
}),
|
|
46
|
+
format: Flags.string({
|
|
47
|
+
char: 'f',
|
|
48
|
+
description: 'Output format',
|
|
49
|
+
options: ['json', 'table', 'yaml'],
|
|
50
|
+
default: 'table',
|
|
51
|
+
}),
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
async run(): Promise<void> {
|
|
55
|
+
const { args, flags } = await this.parse(DataUpdate);
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const { client, token } = await createApiClient({
|
|
59
|
+
url: flags.url,
|
|
60
|
+
token: flags.token,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
requireAuth(token);
|
|
64
|
+
|
|
65
|
+
// Parse update data
|
|
66
|
+
let updateData: any;
|
|
67
|
+
|
|
68
|
+
if (flags.data) {
|
|
69
|
+
// Read from file
|
|
70
|
+
const { readFile } = await import('node:fs/promises');
|
|
71
|
+
const fileContent = await readFile(flags.data, 'utf-8');
|
|
72
|
+
try {
|
|
73
|
+
updateData = JSON.parse(fileContent);
|
|
74
|
+
} catch (e) {
|
|
75
|
+
throw new Error(`Invalid JSON in file: ${(e as Error).message}`);
|
|
76
|
+
}
|
|
77
|
+
} else if (args.data) {
|
|
78
|
+
// Parse from argument
|
|
79
|
+
try {
|
|
80
|
+
updateData = JSON.parse(args.data);
|
|
81
|
+
} catch (e) {
|
|
82
|
+
throw new Error(`Invalid JSON: ${(e as Error).message}`);
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
throw new Error('Update data is required (provide JSON string or use --data flag)');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Update the record
|
|
89
|
+
const result = await client.data.update(args.object, args.id, updateData);
|
|
90
|
+
|
|
91
|
+
if (flags.format === 'json') {
|
|
92
|
+
formatOutput(result, 'json');
|
|
93
|
+
} else if (flags.format === 'yaml') {
|
|
94
|
+
formatOutput(result, 'yaml');
|
|
95
|
+
} else {
|
|
96
|
+
printSuccess(`Record updated: ${result.id}`);
|
|
97
|
+
if (result.record) {
|
|
98
|
+
console.log('');
|
|
99
|
+
formatOutput(result.record, 'table');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
} catch (error: any) {
|
|
103
|
+
if (flags.format === 'json') {
|
|
104
|
+
console.log(JSON.stringify({
|
|
105
|
+
success: false,
|
|
106
|
+
error: error.message,
|
|
107
|
+
}, null, 2));
|
|
108
|
+
this.exit(1);
|
|
109
|
+
}
|
|
110
|
+
printError(error.message || String(error));
|
|
111
|
+
this.exit(1);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
|
+
import { printError, printSuccess } from '../../utils/format.js';
|
|
5
|
+
import { createApiClient, requireAuth } from '../../utils/api-client.js';
|
|
6
|
+
import { formatOutput } from '../../utils/output-formatter.js';
|
|
7
|
+
|
|
8
|
+
export default class MetaDelete extends Command {
|
|
9
|
+
static override description = 'Delete a metadata item';
|
|
10
|
+
|
|
11
|
+
static override examples = [
|
|
12
|
+
'$ os meta delete object my_custom_object',
|
|
13
|
+
'$ os meta delete plugin my-plugin',
|
|
14
|
+
'$ os meta delete object my_custom_object --format json',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
static override args = {
|
|
18
|
+
type: Args.string({
|
|
19
|
+
description: 'Metadata type',
|
|
20
|
+
required: true,
|
|
21
|
+
}),
|
|
22
|
+
name: Args.string({
|
|
23
|
+
description: 'Item name (snake_case)',
|
|
24
|
+
required: true,
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
static override flags = {
|
|
29
|
+
url: Flags.string({
|
|
30
|
+
char: 'u',
|
|
31
|
+
description: 'Server URL',
|
|
32
|
+
env: 'OBJECTSTACK_URL',
|
|
33
|
+
}),
|
|
34
|
+
token: Flags.string({
|
|
35
|
+
char: 't',
|
|
36
|
+
description: 'Authentication token',
|
|
37
|
+
env: 'OBJECTSTACK_TOKEN',
|
|
38
|
+
}),
|
|
39
|
+
format: Flags.string({
|
|
40
|
+
char: 'f',
|
|
41
|
+
description: 'Output format',
|
|
42
|
+
options: ['json', 'table', 'yaml'],
|
|
43
|
+
default: 'table',
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
async run(): Promise<void> {
|
|
48
|
+
const { args, flags } = await this.parse(MetaDelete);
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const { client, token } = await createApiClient({
|
|
52
|
+
url: flags.url,
|
|
53
|
+
token: flags.token,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
requireAuth(token);
|
|
57
|
+
|
|
58
|
+
const result = await client.meta.deleteItem(args.type, args.name);
|
|
59
|
+
|
|
60
|
+
if (flags.format === 'json') {
|
|
61
|
+
formatOutput({ success: true, type: args.type, name: args.name, deleted: result.deleted }, 'json');
|
|
62
|
+
} else if (flags.format === 'yaml') {
|
|
63
|
+
formatOutput({ success: true, type: args.type, name: args.name, deleted: result.deleted }, 'yaml');
|
|
64
|
+
} else {
|
|
65
|
+
printSuccess(`Metadata deleted: ${args.type}/${args.name}`);
|
|
66
|
+
}
|
|
67
|
+
} catch (error: any) {
|
|
68
|
+
if (flags.format === 'json') {
|
|
69
|
+
console.log(JSON.stringify({
|
|
70
|
+
success: false,
|
|
71
|
+
error: error.message,
|
|
72
|
+
}, null, 2));
|
|
73
|
+
this.exit(1);
|
|
74
|
+
}
|
|
75
|
+
printError(error.message || String(error));
|
|
76
|
+
this.exit(1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
|
+
import { printError } from '../../utils/format.js';
|
|
5
|
+
import { createApiClient, requireAuth } from '../../utils/api-client.js';
|
|
6
|
+
import { formatOutput } from '../../utils/output-formatter.js';
|
|
7
|
+
|
|
8
|
+
export default class MetaGet extends Command {
|
|
9
|
+
static override description = 'Get a metadata item';
|
|
10
|
+
|
|
11
|
+
static override examples = [
|
|
12
|
+
'$ os meta get object project_task',
|
|
13
|
+
'$ os meta get plugin my-plugin --format json',
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
static override args = {
|
|
17
|
+
type: Args.string({
|
|
18
|
+
description: 'Metadata type',
|
|
19
|
+
required: true,
|
|
20
|
+
}),
|
|
21
|
+
name: Args.string({
|
|
22
|
+
description: 'Item name (snake_case)',
|
|
23
|
+
required: true,
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
static override flags = {
|
|
28
|
+
url: Flags.string({
|
|
29
|
+
char: 'u',
|
|
30
|
+
description: 'Server URL',
|
|
31
|
+
env: 'OBJECTSTACK_URL',
|
|
32
|
+
}),
|
|
33
|
+
token: Flags.string({
|
|
34
|
+
char: 't',
|
|
35
|
+
description: 'Authentication token',
|
|
36
|
+
env: 'OBJECTSTACK_TOKEN',
|
|
37
|
+
}),
|
|
38
|
+
format: Flags.string({
|
|
39
|
+
char: 'f',
|
|
40
|
+
description: 'Output format',
|
|
41
|
+
options: ['json', 'table', 'yaml'],
|
|
42
|
+
default: 'json',
|
|
43
|
+
}),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
async run(): Promise<void> {
|
|
47
|
+
const { args, flags } = await this.parse(MetaGet);
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const { client, token } = await createApiClient({
|
|
51
|
+
url: flags.url,
|
|
52
|
+
token: flags.token,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
requireAuth(token);
|
|
56
|
+
|
|
57
|
+
// Get the metadata item
|
|
58
|
+
const item = await client.meta.getItem(args.type, args.name);
|
|
59
|
+
|
|
60
|
+
formatOutput(item, flags.format as any);
|
|
61
|
+
} catch (error: any) {
|
|
62
|
+
if (flags.format === 'json') {
|
|
63
|
+
console.log(JSON.stringify({
|
|
64
|
+
success: false,
|
|
65
|
+
error: error.message,
|
|
66
|
+
}, null, 2));
|
|
67
|
+
this.exit(1);
|
|
68
|
+
}
|
|
69
|
+
printError(error.message || String(error));
|
|
70
|
+
this.exit(1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
|
+
import { printError } from '../../utils/format.js';
|
|
5
|
+
import { createApiClient, requireAuth } from '../../utils/api-client.js';
|
|
6
|
+
import { formatOutput } from '../../utils/output-formatter.js';
|
|
7
|
+
|
|
8
|
+
export default class MetaList extends Command {
|
|
9
|
+
static override description = 'List metadata types or items';
|
|
10
|
+
|
|
11
|
+
static override examples = [
|
|
12
|
+
'$ os meta list',
|
|
13
|
+
'$ os meta list object',
|
|
14
|
+
'$ os meta list plugin --format json',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
static override args = {
|
|
18
|
+
type: Args.string({
|
|
19
|
+
description: 'Metadata type (object, plugin, view, etc.)',
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
static override flags = {
|
|
24
|
+
url: Flags.string({
|
|
25
|
+
char: 'u',
|
|
26
|
+
description: 'Server URL',
|
|
27
|
+
env: 'OBJECTSTACK_URL',
|
|
28
|
+
}),
|
|
29
|
+
token: Flags.string({
|
|
30
|
+
char: 't',
|
|
31
|
+
description: 'Authentication token',
|
|
32
|
+
env: 'OBJECTSTACK_TOKEN',
|
|
33
|
+
}),
|
|
34
|
+
format: Flags.string({
|
|
35
|
+
char: 'f',
|
|
36
|
+
description: 'Output format',
|
|
37
|
+
options: ['json', 'table', 'yaml'],
|
|
38
|
+
default: 'table',
|
|
39
|
+
}),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
async run(): Promise<void> {
|
|
43
|
+
const { args, flags } = await this.parse(MetaList);
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const { client, token } = await createApiClient({
|
|
47
|
+
url: flags.url,
|
|
48
|
+
token: flags.token,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
requireAuth(token);
|
|
52
|
+
|
|
53
|
+
if (!args.type) {
|
|
54
|
+
// List all metadata types
|
|
55
|
+
const types = await client.meta.getTypes();
|
|
56
|
+
|
|
57
|
+
if (flags.format === 'json') {
|
|
58
|
+
formatOutput(types, 'json');
|
|
59
|
+
} else if (flags.format === 'yaml') {
|
|
60
|
+
formatOutput(types, 'yaml');
|
|
61
|
+
} else {
|
|
62
|
+
console.log('\nAvailable metadata types:\n');
|
|
63
|
+
if (Array.isArray(types)) {
|
|
64
|
+
types.forEach(type => console.log(` • ${type}`));
|
|
65
|
+
} else {
|
|
66
|
+
console.log('No types available');
|
|
67
|
+
}
|
|
68
|
+
console.log('');
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
// List items of a specific type
|
|
72
|
+
const items = await client.meta.getItems(args.type);
|
|
73
|
+
|
|
74
|
+
if (flags.format === 'json') {
|
|
75
|
+
formatOutput(items, 'json');
|
|
76
|
+
} else if (flags.format === 'yaml') {
|
|
77
|
+
formatOutput(items, 'yaml');
|
|
78
|
+
} else {
|
|
79
|
+
console.log(`\n${args.type} items:\n`);
|
|
80
|
+
if (Array.isArray(items)) {
|
|
81
|
+
if (items.length === 0) {
|
|
82
|
+
console.log(' (no items)');
|
|
83
|
+
} else {
|
|
84
|
+
items.forEach(item => {
|
|
85
|
+
const name = item.name || item.id || JSON.stringify(item);
|
|
86
|
+
console.log(` • ${name}`);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
console.log('');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
} catch (error: any) {
|
|
94
|
+
if (flags.format === 'json') {
|
|
95
|
+
console.log(JSON.stringify({
|
|
96
|
+
success: false,
|
|
97
|
+
error: error.message,
|
|
98
|
+
}, null, 2));
|
|
99
|
+
this.exit(1);
|
|
100
|
+
}
|
|
101
|
+
printError(error.message || String(error));
|
|
102
|
+
this.exit(1);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
|
+
import { printError, printSuccess } from '../../utils/format.js';
|
|
5
|
+
import { createApiClient, requireAuth } from '../../utils/api-client.js';
|
|
6
|
+
import { formatOutput } from '../../utils/output-formatter.js';
|
|
7
|
+
|
|
8
|
+
export default class MetaRegister extends Command {
|
|
9
|
+
static override description = 'Register metadata (create or update)';
|
|
10
|
+
|
|
11
|
+
static override examples = [
|
|
12
|
+
'$ os meta register object --data object-def.json',
|
|
13
|
+
'$ os meta register plugin --data plugin-manifest.json',
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
static override args = {
|
|
17
|
+
type: Args.string({
|
|
18
|
+
description: 'Metadata type',
|
|
19
|
+
required: true,
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
static override flags = {
|
|
24
|
+
url: Flags.string({
|
|
25
|
+
char: 'u',
|
|
26
|
+
description: 'Server URL',
|
|
27
|
+
env: 'OBJECTSTACK_URL',
|
|
28
|
+
}),
|
|
29
|
+
token: Flags.string({
|
|
30
|
+
char: 't',
|
|
31
|
+
description: 'Authentication token',
|
|
32
|
+
env: 'OBJECTSTACK_TOKEN',
|
|
33
|
+
}),
|
|
34
|
+
data: Flags.string({
|
|
35
|
+
char: 'd',
|
|
36
|
+
description: 'Path to JSON file containing metadata definition',
|
|
37
|
+
required: true,
|
|
38
|
+
}),
|
|
39
|
+
format: Flags.string({
|
|
40
|
+
char: 'f',
|
|
41
|
+
description: 'Output format',
|
|
42
|
+
options: ['json', 'table', 'yaml'],
|
|
43
|
+
default: 'table',
|
|
44
|
+
}),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
async run(): Promise<void> {
|
|
48
|
+
const { args, flags } = await this.parse(MetaRegister);
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const { client, token } = await createApiClient({
|
|
52
|
+
url: flags.url,
|
|
53
|
+
token: flags.token,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
requireAuth(token);
|
|
57
|
+
|
|
58
|
+
// Read metadata from file
|
|
59
|
+
const { readFile } = await import('node:fs/promises');
|
|
60
|
+
const fileContent = await readFile(flags.data, 'utf-8');
|
|
61
|
+
let metadata: any;
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
metadata = JSON.parse(fileContent);
|
|
65
|
+
} catch (e) {
|
|
66
|
+
throw new Error(`Invalid JSON in file: ${(e as Error).message}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Extract name from metadata
|
|
70
|
+
const name = metadata.name;
|
|
71
|
+
if (!name) {
|
|
72
|
+
throw new Error('Metadata definition must include a "name" field');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Register the metadata
|
|
76
|
+
const result = await client.meta.saveItem(args.type, name, metadata);
|
|
77
|
+
|
|
78
|
+
if (flags.format === 'json') {
|
|
79
|
+
formatOutput(result, 'json');
|
|
80
|
+
} else if (flags.format === 'yaml') {
|
|
81
|
+
formatOutput(result, 'yaml');
|
|
82
|
+
} else {
|
|
83
|
+
printSuccess(`Metadata registered: ${args.type}/${name}`);
|
|
84
|
+
}
|
|
85
|
+
} catch (error: any) {
|
|
86
|
+
if (flags.format === 'json') {
|
|
87
|
+
console.log(JSON.stringify({
|
|
88
|
+
success: false,
|
|
89
|
+
error: error.message,
|
|
90
|
+
}, null, 2));
|
|
91
|
+
this.exit(1);
|
|
92
|
+
}
|
|
93
|
+
printError(error.message || String(error));
|
|
94
|
+
this.exit(1);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|