@codejeet/oadm 0.0.1
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/dist/cli.js +95 -0
- package/dist/config.js +29 -0
- package/dist/http.js +31 -0
- package/package.json +24 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { readConfig, writeConfig } from './config.js';
|
|
5
|
+
import { getJson, postJson } from './http.js';
|
|
6
|
+
const program = new Command();
|
|
7
|
+
program.name('oadm').description('OADM Inbox CLI').version('0.0.1');
|
|
8
|
+
program
|
|
9
|
+
.option('--api <url>', 'API base URL (or set OADM_API_URL)', '')
|
|
10
|
+
.hook('preAction', (thisCommand) => {
|
|
11
|
+
const opts = thisCommand.opts();
|
|
12
|
+
if (opts.api) {
|
|
13
|
+
const cfg = readConfig();
|
|
14
|
+
cfg.apiUrl = opts.api;
|
|
15
|
+
writeConfig(cfg);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
program
|
|
19
|
+
.command('register')
|
|
20
|
+
.requiredOption('--name <name>')
|
|
21
|
+
.requiredOption('--password <password>')
|
|
22
|
+
.action(async (opts) => {
|
|
23
|
+
const cfg = readConfig();
|
|
24
|
+
await postJson(`${cfg.apiUrl}/v1/register`, { name: opts.name, password: opts.password, inviteCode: process.env.OADM_INVITE_CODE });
|
|
25
|
+
console.log(chalk.green('✓ registered'));
|
|
26
|
+
console.log('Next: oadm login --name <name> --password <pw>');
|
|
27
|
+
});
|
|
28
|
+
program
|
|
29
|
+
.command('login')
|
|
30
|
+
.requiredOption('--name <name>')
|
|
31
|
+
.requiredOption('--password <password>')
|
|
32
|
+
.action(async (opts) => {
|
|
33
|
+
const cfg = readConfig();
|
|
34
|
+
const data = await postJson(`${cfg.apiUrl}/v1/login`, { name: opts.name, password: opts.password });
|
|
35
|
+
cfg.name = opts.name;
|
|
36
|
+
cfg.token = data.token;
|
|
37
|
+
writeConfig(cfg);
|
|
38
|
+
console.log(chalk.green('✓ logged in'));
|
|
39
|
+
});
|
|
40
|
+
program
|
|
41
|
+
.command('send')
|
|
42
|
+
.requiredOption('--to <recipientName>')
|
|
43
|
+
.requiredOption('--text <text>')
|
|
44
|
+
.action(async (opts) => {
|
|
45
|
+
const cfg = readConfig();
|
|
46
|
+
if (!cfg.token)
|
|
47
|
+
throw new Error('not_logged_in');
|
|
48
|
+
const data = await postJson(`${cfg.apiUrl}/v1/messages/send`, { toName: opts.to, text: opts.text }, cfg.token);
|
|
49
|
+
console.log(chalk.green('✓ sent'), data.id);
|
|
50
|
+
});
|
|
51
|
+
program
|
|
52
|
+
.command('inbox')
|
|
53
|
+
.option('--unread', 'Only unread', false)
|
|
54
|
+
.option('--json', 'JSON output', false)
|
|
55
|
+
.option('--ack', 'Ack returned messages', false)
|
|
56
|
+
.action(async (opts) => {
|
|
57
|
+
const cfg = readConfig();
|
|
58
|
+
if (!cfg.token)
|
|
59
|
+
throw new Error('not_logged_in');
|
|
60
|
+
const q = new URLSearchParams();
|
|
61
|
+
if (opts.unread)
|
|
62
|
+
q.set('unread', '1');
|
|
63
|
+
const data = await getJson(`${cfg.apiUrl}/v1/messages/inbox?${q.toString()}`, cfg.token);
|
|
64
|
+
if (opts.json) {
|
|
65
|
+
console.log(JSON.stringify(data, null, 2));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
for (const m of data.messages) {
|
|
69
|
+
console.log(`${m.id} from:${m.fromName} ${new Date(m.createdAt).toLocaleString()}`);
|
|
70
|
+
console.log(m.text);
|
|
71
|
+
console.log('---');
|
|
72
|
+
}
|
|
73
|
+
if (!data.messages.length)
|
|
74
|
+
console.log('(empty)');
|
|
75
|
+
}
|
|
76
|
+
if (opts.ack) {
|
|
77
|
+
for (const m of data.messages) {
|
|
78
|
+
await postJson(`${cfg.apiUrl}/v1/messages/ack/${m.id}`, {}, cfg.token);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
program
|
|
83
|
+
.command('ack')
|
|
84
|
+
.argument('<msgId>')
|
|
85
|
+
.action(async (msgId) => {
|
|
86
|
+
const cfg = readConfig();
|
|
87
|
+
if (!cfg.token)
|
|
88
|
+
throw new Error('not_logged_in');
|
|
89
|
+
await postJson(`${cfg.apiUrl}/v1/messages/ack/${msgId}`, {}, cfg.token);
|
|
90
|
+
console.log(chalk.green('✓ acked'), msgId);
|
|
91
|
+
});
|
|
92
|
+
program.parseAsync(process.argv).catch((e) => {
|
|
93
|
+
console.error(chalk.red('error:'), e?.message ?? String(e));
|
|
94
|
+
process.exit(1);
|
|
95
|
+
});
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
export function configDir() {
|
|
5
|
+
return path.join(os.homedir(), '.oadm');
|
|
6
|
+
}
|
|
7
|
+
export function configPath() {
|
|
8
|
+
return path.join(configDir(), 'config.json');
|
|
9
|
+
}
|
|
10
|
+
export function readConfig() {
|
|
11
|
+
const p = configPath();
|
|
12
|
+
if (!fs.existsSync(p)) {
|
|
13
|
+
return { apiUrl: process.env.OADM_API_URL ?? 'http://localhost:3000' };
|
|
14
|
+
}
|
|
15
|
+
const raw = fs.readFileSync(p, 'utf8');
|
|
16
|
+
const cfg = JSON.parse(raw);
|
|
17
|
+
cfg.apiUrl = cfg.apiUrl ?? process.env.OADM_API_URL ?? 'http://localhost:3000';
|
|
18
|
+
return cfg;
|
|
19
|
+
}
|
|
20
|
+
export function writeConfig(cfg) {
|
|
21
|
+
fs.mkdirSync(configDir(), { recursive: true });
|
|
22
|
+
fs.writeFileSync(configPath(), JSON.stringify(cfg, null, 2));
|
|
23
|
+
try {
|
|
24
|
+
fs.chmodSync(configPath(), 0o600);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// ignore on platforms that don't support chmod
|
|
28
|
+
}
|
|
29
|
+
}
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export async function postJson(url, body, token) {
|
|
2
|
+
const r = await fetch(url, {
|
|
3
|
+
method: 'POST',
|
|
4
|
+
headers: {
|
|
5
|
+
'content-type': 'application/json',
|
|
6
|
+
...(token ? { authorization: `Bearer ${token}` } : {}),
|
|
7
|
+
},
|
|
8
|
+
body: JSON.stringify(body),
|
|
9
|
+
});
|
|
10
|
+
const text = await r.text();
|
|
11
|
+
const data = text ? JSON.parse(text) : null;
|
|
12
|
+
if (!r.ok) {
|
|
13
|
+
const msg = data?.error ? `${data.error}` : `http_${r.status}`;
|
|
14
|
+
throw new Error(msg);
|
|
15
|
+
}
|
|
16
|
+
return data;
|
|
17
|
+
}
|
|
18
|
+
export async function getJson(url, token) {
|
|
19
|
+
const r = await fetch(url, {
|
|
20
|
+
headers: {
|
|
21
|
+
...(token ? { authorization: `Bearer ${token}` } : {}),
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
const text = await r.text();
|
|
25
|
+
const data = text ? JSON.parse(text) : null;
|
|
26
|
+
if (!r.ok) {
|
|
27
|
+
const msg = data?.error ? `${data.error}` : `http_${r.status}`;
|
|
28
|
+
throw new Error(msg);
|
|
29
|
+
}
|
|
30
|
+
return data;
|
|
31
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@codejeet/oadm",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"oadm": "dist/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"files": ["dist"],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "tsx src/cli.ts",
|
|
11
|
+
"build": "tsc -p tsconfig.json",
|
|
12
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"chalk": "^5.3.0",
|
|
16
|
+
"commander": "^12.1.0",
|
|
17
|
+
"node-fetch": "^3.3.2"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^20.19.32",
|
|
21
|
+
"tsx": "^4.19.2",
|
|
22
|
+
"typescript": "^5.7.3"
|
|
23
|
+
}
|
|
24
|
+
}
|