@objectstack/cli 4.0.1 → 4.0.3
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 +33 -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 +19 -14
- 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,80 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import yaml from 'yaml';
|
|
4
|
+
/**
|
|
5
|
+
* Format and output data according to the specified format
|
|
6
|
+
*/
|
|
7
|
+
export function formatOutput(data, format = 'json') {
|
|
8
|
+
switch (format) {
|
|
9
|
+
case 'json':
|
|
10
|
+
console.log(JSON.stringify(data, null, 2));
|
|
11
|
+
break;
|
|
12
|
+
case 'yaml':
|
|
13
|
+
console.log(yaml.stringify(data));
|
|
14
|
+
break;
|
|
15
|
+
case 'table':
|
|
16
|
+
// For table format, handle different data structures
|
|
17
|
+
if (Array.isArray(data)) {
|
|
18
|
+
printTable(data);
|
|
19
|
+
}
|
|
20
|
+
else if (data && typeof data === 'object') {
|
|
21
|
+
// For single objects, print as key-value pairs
|
|
22
|
+
printKeyValue(data);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.log(String(data));
|
|
26
|
+
}
|
|
27
|
+
break;
|
|
28
|
+
default:
|
|
29
|
+
console.log(JSON.stringify(data, null, 2));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Print data as a table (for arrays of objects)
|
|
34
|
+
*/
|
|
35
|
+
function printTable(data) {
|
|
36
|
+
if (data.length === 0) {
|
|
37
|
+
console.log(chalk.dim('(no data)'));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Get all unique keys from all objects
|
|
41
|
+
const keys = Array.from(new Set(data.flatMap(item => Object.keys(item))));
|
|
42
|
+
// Print header
|
|
43
|
+
console.log(chalk.bold(keys.join(' | ')));
|
|
44
|
+
console.log(chalk.dim('─'.repeat(keys.join(' | ').length)));
|
|
45
|
+
// Print rows
|
|
46
|
+
for (const item of data) {
|
|
47
|
+
const values = keys.map(key => {
|
|
48
|
+
const value = item[key];
|
|
49
|
+
if (value === null || value === undefined)
|
|
50
|
+
return chalk.dim('-');
|
|
51
|
+
if (typeof value === 'object')
|
|
52
|
+
return chalk.dim('[object]');
|
|
53
|
+
return String(value);
|
|
54
|
+
});
|
|
55
|
+
console.log(values.join(' | '));
|
|
56
|
+
}
|
|
57
|
+
console.log(chalk.dim(`\n${data.length} row(s)`));
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Print object as key-value pairs
|
|
61
|
+
*/
|
|
62
|
+
function printKeyValue(data, indent = 0) {
|
|
63
|
+
const prefix = ' '.repeat(indent);
|
|
64
|
+
for (const [key, value] of Object.entries(data)) {
|
|
65
|
+
if (value === null || value === undefined) {
|
|
66
|
+
console.log(`${prefix}${chalk.dim(key + ':')} ${chalk.dim('null')}`);
|
|
67
|
+
}
|
|
68
|
+
else if (typeof value === 'object' && !Array.isArray(value)) {
|
|
69
|
+
console.log(`${prefix}${chalk.bold(key + ':')}`);
|
|
70
|
+
printKeyValue(value, indent + 1);
|
|
71
|
+
}
|
|
72
|
+
else if (Array.isArray(value)) {
|
|
73
|
+
console.log(`${prefix}${chalk.dim(key + ':')} ${chalk.dim(`[${value.length} items]`)}`);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
console.log(`${prefix}${chalk.dim(key + ':')} ${chalk.white(String(value))}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=output-formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output-formatter.js","sourceRoot":"","sources":["../../src/utils/output-formatter.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/cli",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.3",
|
|
4
4
|
"description": "Command Line Interface for ObjectStack Protocol",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -33,30 +33,35 @@
|
|
|
33
33
|
"topicSeparator": " "
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@
|
|
36
|
+
"@ai-sdk/gateway": "^3.0.95",
|
|
37
|
+
"@oclif/core": "^4.10.5",
|
|
37
38
|
"bundle-require": "^5.1.0",
|
|
38
39
|
"chalk": "^5.6.2",
|
|
39
40
|
"dotenv-flow": "^4.1.0",
|
|
40
41
|
"tsx": "^4.21.0",
|
|
42
|
+
"yaml": "^2.4.1",
|
|
41
43
|
"zod": "^4.3.6",
|
|
42
|
-
"@objectstack/
|
|
43
|
-
"@objectstack/
|
|
44
|
-
"@objectstack/
|
|
45
|
-
"@objectstack/
|
|
46
|
-
"@objectstack/
|
|
47
|
-
"@objectstack/
|
|
48
|
-
"@objectstack/
|
|
44
|
+
"@objectstack/client": "4.0.3",
|
|
45
|
+
"@objectstack/core": "4.0.3",
|
|
46
|
+
"@objectstack/driver-memory": "^4.0.3",
|
|
47
|
+
"@objectstack/objectql": "^4.0.3",
|
|
48
|
+
"@objectstack/plugin-hono-server": "4.0.3",
|
|
49
|
+
"@objectstack/plugin-setup": "4.0.3",
|
|
50
|
+
"@objectstack/rest": "4.0.3",
|
|
51
|
+
"@objectstack/runtime": "^4.0.3",
|
|
52
|
+
"@objectstack/service-ai": "4.0.3",
|
|
53
|
+
"@objectstack/spec": "4.0.3"
|
|
49
54
|
},
|
|
50
55
|
"peerDependencies": {
|
|
51
|
-
"@objectstack/core": "^4.0.
|
|
56
|
+
"@objectstack/core": "^4.0.3"
|
|
52
57
|
},
|
|
53
58
|
"devDependencies": {
|
|
54
|
-
"@oclif/plugin-help": "^6.2.
|
|
55
|
-
"@oclif/plugin-plugins": "^5.4.
|
|
56
|
-
"@types/node": "^25.
|
|
59
|
+
"@oclif/plugin-help": "^6.2.44",
|
|
60
|
+
"@oclif/plugin-plugins": "^5.4.60",
|
|
61
|
+
"@types/node": "^25.6.0",
|
|
57
62
|
"tsup": "^8.5.1",
|
|
58
63
|
"typescript": "^6.0.2",
|
|
59
|
-
"vitest": "^4.1.
|
|
64
|
+
"vitest": "^4.1.4"
|
|
60
65
|
},
|
|
61
66
|
"scripts": {
|
|
62
67
|
"build": "tsc -p tsconfig.build.json",
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
|
|
3
|
+
import { Command, Flags } from '@oclif/core';
|
|
4
|
+
import { printHeader, printSuccess, printError, printKV } from '../../utils/format.js';
|
|
5
|
+
import { writeAuthConfig } from '../../utils/auth-config.js';
|
|
6
|
+
import { ObjectStackClient } from '@objectstack/client';
|
|
7
|
+
import * as readline from 'node:readline/promises';
|
|
8
|
+
import { stdin as input, stdout as output } from 'node:process';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Prompt for a password with masked input (shows * per character).
|
|
12
|
+
* Falls back to plain readline.question() in non-TTY environments.
|
|
13
|
+
*/
|
|
14
|
+
async function promptPassword(promptText: string): Promise<string> {
|
|
15
|
+
if (!process.stdin.isTTY) {
|
|
16
|
+
const rl = readline.createInterface({ input, output });
|
|
17
|
+
const answer = await rl.question(promptText);
|
|
18
|
+
rl.close();
|
|
19
|
+
return answer;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
const chars: string[] = [];
|
|
24
|
+
process.stdout.write(promptText);
|
|
25
|
+
process.stdin.setRawMode(true);
|
|
26
|
+
process.stdin.resume();
|
|
27
|
+
process.stdin.setEncoding('utf8');
|
|
28
|
+
|
|
29
|
+
const cleanup = () => {
|
|
30
|
+
process.stdin.setRawMode(false);
|
|
31
|
+
process.stdin.pause();
|
|
32
|
+
process.stdin.removeListener('data', handler);
|
|
33
|
+
process.stdout.write('\n');
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const handler = (char: string) => {
|
|
37
|
+
switch (char) {
|
|
38
|
+
case '\u0003': // Ctrl+C
|
|
39
|
+
cleanup();
|
|
40
|
+
process.kill(process.pid, 'SIGINT');
|
|
41
|
+
break;
|
|
42
|
+
case '\r':
|
|
43
|
+
case '\n': // Enter
|
|
44
|
+
cleanup();
|
|
45
|
+
resolve(chars.join(''));
|
|
46
|
+
break;
|
|
47
|
+
case '\u007f': // Backspace
|
|
48
|
+
if (chars.length > 0) {
|
|
49
|
+
chars.pop();
|
|
50
|
+
process.stdout.clearLine(0);
|
|
51
|
+
process.stdout.cursorTo(0);
|
|
52
|
+
process.stdout.write(promptText + '*'.repeat(chars.length));
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
default:
|
|
56
|
+
chars.push(char);
|
|
57
|
+
process.stdout.write('*');
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
process.stdin.on('data', handler);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export default class AuthLogin extends Command {
|
|
67
|
+
static override description = 'Authenticate and store session credentials';
|
|
68
|
+
|
|
69
|
+
static override examples = [
|
|
70
|
+
'$ os auth login',
|
|
71
|
+
'$ os auth login --url https://api.example.com',
|
|
72
|
+
'$ os auth login --email user@example.com --password mypassword',
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
static override flags = {
|
|
76
|
+
url: Flags.string({
|
|
77
|
+
char: 'u',
|
|
78
|
+
description: 'Server URL',
|
|
79
|
+
default: 'http://localhost:3000',
|
|
80
|
+
env: 'OBJECTSTACK_URL',
|
|
81
|
+
}),
|
|
82
|
+
email: Flags.string({
|
|
83
|
+
char: 'e',
|
|
84
|
+
description: 'Email address',
|
|
85
|
+
}),
|
|
86
|
+
password: Flags.string({
|
|
87
|
+
char: 'p',
|
|
88
|
+
description: 'Password',
|
|
89
|
+
}),
|
|
90
|
+
json: Flags.boolean({
|
|
91
|
+
description: 'Output as JSON',
|
|
92
|
+
}),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
async run(): Promise<void> {
|
|
96
|
+
const { flags } = await this.parse(AuthLogin);
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
if (!flags.json) {
|
|
100
|
+
printHeader('ObjectStack Login');
|
|
101
|
+
printKV('Server', flags.url);
|
|
102
|
+
console.log('');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Prompt for credentials if not provided
|
|
106
|
+
let email = flags.email;
|
|
107
|
+
let password = flags.password;
|
|
108
|
+
|
|
109
|
+
if (!email || !password) {
|
|
110
|
+
const rl = readline.createInterface({ input, output });
|
|
111
|
+
|
|
112
|
+
if (!email) {
|
|
113
|
+
email = await rl.question('Email: ');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
rl.close();
|
|
117
|
+
|
|
118
|
+
if (!password) {
|
|
119
|
+
password = await promptPassword('Password: ');
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (!email || !password) {
|
|
124
|
+
throw new Error('Email and password are required');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Create client and authenticate
|
|
128
|
+
const client = new ObjectStackClient({
|
|
129
|
+
baseUrl: flags.url,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const response = await client.auth.login({
|
|
133
|
+
type: 'email',
|
|
134
|
+
email,
|
|
135
|
+
password,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Check if login was successful
|
|
139
|
+
if (!response.data?.token && !response.data?.user) {
|
|
140
|
+
throw new Error('Login failed: Invalid response from server');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Extract token - it might be in different locations depending on the auth system
|
|
144
|
+
const token = response.data?.token || (response as any).token;
|
|
145
|
+
const user = response.data?.user;
|
|
146
|
+
|
|
147
|
+
if (!token) {
|
|
148
|
+
throw new Error('Login failed: No token received from server');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Store credentials
|
|
152
|
+
await writeAuthConfig({
|
|
153
|
+
url: flags.url,
|
|
154
|
+
token,
|
|
155
|
+
email: user?.email || email,
|
|
156
|
+
userId: user?.id,
|
|
157
|
+
createdAt: new Date().toISOString(),
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
if (flags.json) {
|
|
161
|
+
console.log(JSON.stringify({
|
|
162
|
+
success: true,
|
|
163
|
+
email: user?.email || email,
|
|
164
|
+
userId: user?.id,
|
|
165
|
+
}, null, 2));
|
|
166
|
+
} else {
|
|
167
|
+
printSuccess('Authentication successful');
|
|
168
|
+
printKV('Email', user?.email || email);
|
|
169
|
+
if (user?.id) {
|
|
170
|
+
printKV('User ID', user.id);
|
|
171
|
+
}
|
|
172
|
+
console.log('');
|
|
173
|
+
console.log(' Credentials stored in ~/.objectstack/credentials.json');
|
|
174
|
+
console.log('');
|
|
175
|
+
}
|
|
176
|
+
} catch (error: any) {
|
|
177
|
+
if (flags.json) {
|
|
178
|
+
console.log(JSON.stringify({
|
|
179
|
+
success: false,
|
|
180
|
+
error: error.message,
|
|
181
|
+
}, null, 2));
|
|
182
|
+
this.exit(1);
|
|
183
|
+
}
|
|
184
|
+
printError(error.message || String(error));
|
|
185
|
+
this.exit(1);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
|
|
3
|
+
import { Command, Flags } from '@oclif/core';
|
|
4
|
+
import { printHeader, printSuccess, printError } from '../../utils/format.js';
|
|
5
|
+
import { deleteAuthConfig } from '../../utils/auth-config.js';
|
|
6
|
+
|
|
7
|
+
export default class AuthLogout extends Command {
|
|
8
|
+
static override description = 'Clear stored authentication credentials';
|
|
9
|
+
|
|
10
|
+
static override examples = [
|
|
11
|
+
'$ os auth logout',
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
static override flags = {
|
|
15
|
+
json: Flags.boolean({
|
|
16
|
+
description: 'Output as JSON',
|
|
17
|
+
}),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
async run(): Promise<void> {
|
|
21
|
+
const { flags } = await this.parse(AuthLogout);
|
|
22
|
+
|
|
23
|
+
try {
|
|
24
|
+
if (!flags.json) {
|
|
25
|
+
printHeader('ObjectStack Logout');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
await deleteAuthConfig();
|
|
29
|
+
|
|
30
|
+
if (flags.json) {
|
|
31
|
+
console.log(JSON.stringify({
|
|
32
|
+
success: true,
|
|
33
|
+
message: 'Credentials cleared',
|
|
34
|
+
}, null, 2));
|
|
35
|
+
} else {
|
|
36
|
+
printSuccess('Credentials cleared');
|
|
37
|
+
console.log('');
|
|
38
|
+
}
|
|
39
|
+
} catch (error: any) {
|
|
40
|
+
if (flags.json) {
|
|
41
|
+
console.log(JSON.stringify({
|
|
42
|
+
success: false,
|
|
43
|
+
error: error.message,
|
|
44
|
+
}, null, 2));
|
|
45
|
+
this.exit(1);
|
|
46
|
+
}
|
|
47
|
+
printError(error.message || String(error));
|
|
48
|
+
this.exit(1);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
|
+
|
|
3
|
+
import { Command, Flags } from '@oclif/core';
|
|
4
|
+
import { printHeader, printError, printKV } 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 AuthWhoami extends Command {
|
|
9
|
+
static override description = 'Show current session information';
|
|
10
|
+
|
|
11
|
+
static override examples = [
|
|
12
|
+
'$ os auth whoami',
|
|
13
|
+
'$ os auth whoami --format json',
|
|
14
|
+
'$ os auth whoami --url https://api.example.com --token <token>',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
static override flags = {
|
|
18
|
+
url: Flags.string({
|
|
19
|
+
char: 'u',
|
|
20
|
+
description: 'Server URL',
|
|
21
|
+
env: 'OBJECTSTACK_URL',
|
|
22
|
+
}),
|
|
23
|
+
token: Flags.string({
|
|
24
|
+
char: 't',
|
|
25
|
+
description: 'Authentication token',
|
|
26
|
+
env: 'OBJECTSTACK_TOKEN',
|
|
27
|
+
}),
|
|
28
|
+
format: Flags.string({
|
|
29
|
+
char: 'f',
|
|
30
|
+
description: 'Output format',
|
|
31
|
+
options: ['json', 'table', 'yaml'],
|
|
32
|
+
default: 'table',
|
|
33
|
+
}),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
async run(): Promise<void> {
|
|
37
|
+
const { flags } = await this.parse(AuthWhoami);
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
const { client, token } = await createApiClient({
|
|
41
|
+
url: flags.url,
|
|
42
|
+
token: flags.token,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
requireAuth(token);
|
|
46
|
+
|
|
47
|
+
// Check if we have a token
|
|
48
|
+
// Get current session info
|
|
49
|
+
const response = await client.auth.me();
|
|
50
|
+
|
|
51
|
+
const sessionData = response.data || response;
|
|
52
|
+
|
|
53
|
+
if (flags.format === 'json') {
|
|
54
|
+
formatOutput(sessionData, 'json');
|
|
55
|
+
} else if (flags.format === 'yaml') {
|
|
56
|
+
formatOutput(sessionData, 'yaml');
|
|
57
|
+
} else {
|
|
58
|
+
printHeader('Current Session');
|
|
59
|
+
|
|
60
|
+
if (sessionData.user) {
|
|
61
|
+
printKV('User ID', sessionData.user.id || '-');
|
|
62
|
+
printKV('Email', sessionData.user.email || '-');
|
|
63
|
+
printKV('Name', sessionData.user.name || '-');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (sessionData.session) {
|
|
67
|
+
printKV('Session ID', sessionData.session.id || '-');
|
|
68
|
+
printKV('Expires At', sessionData.session.expiresAt || '-');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log('');
|
|
72
|
+
}
|
|
73
|
+
} catch (error: any) {
|
|
74
|
+
if (flags.format === 'json') {
|
|
75
|
+
console.log(JSON.stringify({
|
|
76
|
+
success: false,
|
|
77
|
+
error: error.message,
|
|
78
|
+
}, null, 2));
|
|
79
|
+
this.exit(1);
|
|
80
|
+
}
|
|
81
|
+
printError(error.message || String(error));
|
|
82
|
+
this.exit(1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
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 DataCreate extends Command {
|
|
9
|
+
static override description = 'Create a new record';
|
|
10
|
+
|
|
11
|
+
static override examples = [
|
|
12
|
+
'$ os data create project_task \'{"name":"New Task","status":"open"}\'',
|
|
13
|
+
'$ os data create project_task --data task-data.json',
|
|
14
|
+
'$ os data create project_task --data task-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
|
+
data: Args.string({
|
|
23
|
+
description: 'Record data as JSON string (or use --data flag for file)',
|
|
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
|
+
data: Flags.string({
|
|
39
|
+
char: 'd',
|
|
40
|
+
description: 'Path to JSON file containing record data',
|
|
41
|
+
}),
|
|
42
|
+
format: Flags.string({
|
|
43
|
+
char: 'f',
|
|
44
|
+
description: 'Output format',
|
|
45
|
+
options: ['json', 'table', 'yaml'],
|
|
46
|
+
default: 'table',
|
|
47
|
+
}),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
async run(): Promise<void> {
|
|
51
|
+
const { args, flags } = await this.parse(DataCreate);
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const { client, token } = await createApiClient({
|
|
55
|
+
url: flags.url,
|
|
56
|
+
token: flags.token,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
requireAuth(token);
|
|
60
|
+
|
|
61
|
+
// Parse record data
|
|
62
|
+
let recordData: any;
|
|
63
|
+
|
|
64
|
+
if (flags.data) {
|
|
65
|
+
// Read from file
|
|
66
|
+
const { readFile } = await import('node:fs/promises');
|
|
67
|
+
const fileContent = await readFile(flags.data, 'utf-8');
|
|
68
|
+
try {
|
|
69
|
+
recordData = JSON.parse(fileContent);
|
|
70
|
+
} catch (e) {
|
|
71
|
+
throw new Error(`Invalid JSON in file: ${(e as Error).message}`);
|
|
72
|
+
}
|
|
73
|
+
} else if (args.data) {
|
|
74
|
+
// Parse from argument
|
|
75
|
+
try {
|
|
76
|
+
recordData = JSON.parse(args.data);
|
|
77
|
+
} catch (e) {
|
|
78
|
+
throw new Error(`Invalid JSON: ${(e as Error).message}`);
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
throw new Error('Record data is required (provide JSON string or use --data flag)');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Create the record
|
|
85
|
+
const result = await client.data.create(args.object, recordData);
|
|
86
|
+
|
|
87
|
+
if (flags.format === 'json') {
|
|
88
|
+
formatOutput(result, 'json');
|
|
89
|
+
} else if (flags.format === 'yaml') {
|
|
90
|
+
formatOutput(result, 'yaml');
|
|
91
|
+
} else {
|
|
92
|
+
printSuccess(`Record created: ${result.id}`);
|
|
93
|
+
if (result.record) {
|
|
94
|
+
console.log('');
|
|
95
|
+
formatOutput(result.record, 'table');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
} catch (error: any) {
|
|
99
|
+
if (flags.format === 'json') {
|
|
100
|
+
console.log(JSON.stringify({
|
|
101
|
+
success: false,
|
|
102
|
+
error: error.message,
|
|
103
|
+
}, null, 2));
|
|
104
|
+
this.exit(1);
|
|
105
|
+
}
|
|
106
|
+
printError(error.message || String(error));
|
|
107
|
+
this.exit(1);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -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, 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 DataDelete extends Command {
|
|
9
|
+
static override description = 'Delete a record';
|
|
10
|
+
|
|
11
|
+
static override examples = [
|
|
12
|
+
'$ os data delete project_task abc123',
|
|
13
|
+
'$ os data delete 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(DataDelete);
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const { client, token } = await createApiClient({
|
|
51
|
+
url: flags.url,
|
|
52
|
+
token: flags.token,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
requireAuth(token);
|
|
56
|
+
|
|
57
|
+
// Delete the record
|
|
58
|
+
const result = await client.data.delete(args.object, args.id);
|
|
59
|
+
|
|
60
|
+
if (flags.format === 'json') {
|
|
61
|
+
console.log(JSON.stringify({
|
|
62
|
+
success: true,
|
|
63
|
+
object: result.object,
|
|
64
|
+
id: result.id,
|
|
65
|
+
deleted: result.deleted,
|
|
66
|
+
}, null, 2));
|
|
67
|
+
} else if (flags.format === 'yaml') {
|
|
68
|
+
formatOutput({ success: true, object: result.object, id: result.id, deleted: result.deleted }, 'yaml');
|
|
69
|
+
} else {
|
|
70
|
+
printSuccess(`Record deleted: ${result.id}`);
|
|
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
|
+
}
|