@openma/cli 0.1.0-beta.2 → 0.1.0-beta.4
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/index.js +110 -26
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,12 +12,39 @@ function credentialsPath() {
|
|
|
12
12
|
const base = xdg && xdg.length > 0 ? xdg : join(homedir(), ".config");
|
|
13
13
|
return join(base, "oma", "credentials.json");
|
|
14
14
|
}
|
|
15
|
+
function migrateV1ToV2(v1) {
|
|
16
|
+
return {
|
|
17
|
+
version: 2,
|
|
18
|
+
base_url: v1.base_url,
|
|
19
|
+
user: v1.user,
|
|
20
|
+
active_tenant_id: v1.tenant.id,
|
|
21
|
+
tenants: {
|
|
22
|
+
[v1.tenant.id]: {
|
|
23
|
+
name: v1.tenant.name,
|
|
24
|
+
role: v1.tenants.find((t) => t.id === v1.tenant.id)?.role ?? "owner",
|
|
25
|
+
token: v1.token,
|
|
26
|
+
key_id: v1.key_id,
|
|
27
|
+
created_at: v1.created_at
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
15
32
|
function readCredentials() {
|
|
16
33
|
const path = credentialsPath();
|
|
17
34
|
try {
|
|
18
35
|
if (!existsSync(path)) return null;
|
|
19
36
|
const raw = readFileSync(path, "utf8");
|
|
20
|
-
|
|
37
|
+
const parsed = JSON.parse(raw);
|
|
38
|
+
if (parsed.version === 2) return parsed;
|
|
39
|
+
if (parsed.version === 1) {
|
|
40
|
+
const v2 = migrateV1ToV2(parsed);
|
|
41
|
+
try {
|
|
42
|
+
writeCredentials(v2);
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
return v2;
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
21
48
|
} catch {
|
|
22
49
|
return null;
|
|
23
50
|
}
|
|
@@ -40,6 +67,7 @@ function clearCredentials() {
|
|
|
40
67
|
function loadConfig() {
|
|
41
68
|
const envBase = process.env.OMA_BASE_URL;
|
|
42
69
|
const envKey = process.env.OMA_API_KEY;
|
|
70
|
+
const envTenant = process.env.OMA_TENANT_ID;
|
|
43
71
|
const stored = readCredentials();
|
|
44
72
|
if (envKey) {
|
|
45
73
|
return {
|
|
@@ -50,9 +78,15 @@ function loadConfig() {
|
|
|
50
78
|
};
|
|
51
79
|
}
|
|
52
80
|
if (stored) {
|
|
81
|
+
const activeId = envTenant || stored.active_tenant_id;
|
|
82
|
+
const profile = stored.tenants[activeId];
|
|
83
|
+
if (!profile) {
|
|
84
|
+
console.error(`Error: tenant ${activeId} not in credentials. Run: oma auth tenant ls`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
53
87
|
return {
|
|
54
88
|
baseUrl: envBase || stored.base_url,
|
|
55
|
-
apiKey:
|
|
89
|
+
apiKey: profile.token,
|
|
56
90
|
json: false,
|
|
57
91
|
source: "stored"
|
|
58
92
|
};
|
|
@@ -65,12 +99,17 @@ function loadConfig() {
|
|
|
65
99
|
function loadConfigOptional() {
|
|
66
100
|
const envBase = process.env.OMA_BASE_URL;
|
|
67
101
|
const envKey = process.env.OMA_API_KEY;
|
|
102
|
+
const envTenant = process.env.OMA_TENANT_ID;
|
|
68
103
|
const stored = readCredentials();
|
|
69
104
|
if (envKey) {
|
|
70
105
|
return { baseUrl: envBase || stored?.base_url || "https://openma.dev", apiKey: envKey, json: false, source: "env" };
|
|
71
106
|
}
|
|
72
107
|
if (stored) {
|
|
73
|
-
|
|
108
|
+
const activeId = envTenant || stored.active_tenant_id;
|
|
109
|
+
const profile = stored.tenants[activeId];
|
|
110
|
+
if (profile) {
|
|
111
|
+
return { baseUrl: envBase || stored.base_url, apiKey: profile.token, json: false, source: "stored" };
|
|
112
|
+
}
|
|
74
113
|
}
|
|
75
114
|
return { baseUrl: envBase || "https://openma.dev", apiKey: "", json: false, source: "missing" };
|
|
76
115
|
}
|
|
@@ -175,6 +214,9 @@ async function authLogin(baseUrl, requestedTenant) {
|
|
|
175
214
|
res.writeHead(200, { "Content-Type": "text/html" }).end(approvalPage("Signed in", "You can close this tab and return to your terminal."));
|
|
176
215
|
clearTimeout(timeout);
|
|
177
216
|
server.close();
|
|
217
|
+
if (typeof server.closeAllConnections === "function") {
|
|
218
|
+
server.closeAllConnections();
|
|
219
|
+
}
|
|
178
220
|
resolve({ token, tenant, user, key_id });
|
|
179
221
|
} catch (err) {
|
|
180
222
|
res.writeHead(500).end();
|
|
@@ -192,23 +234,42 @@ async function authLogin(baseUrl, requestedTenant) {
|
|
|
192
234
|
});
|
|
193
235
|
const tempConfig = { baseUrl, apiKey: result.token, json: false, source: "stored" };
|
|
194
236
|
const me = await apiFetch(tempConfig, "/v1/me");
|
|
195
|
-
|
|
196
|
-
|
|
237
|
+
const existing = readCredentials();
|
|
238
|
+
const role = me.tenants.find((t) => t.id === me.tenant.id)?.role ?? "owner";
|
|
239
|
+
const updated = {
|
|
240
|
+
version: 2,
|
|
197
241
|
base_url: baseUrl,
|
|
198
242
|
user: me.user ?? { id: result.user, email: "", name: null },
|
|
199
|
-
|
|
200
|
-
tenants:
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
243
|
+
active_tenant_id: me.tenant.id,
|
|
244
|
+
tenants: {
|
|
245
|
+
...existing && existing.user.id === (me.user?.id ?? result.user) ? existing.tenants : {},
|
|
246
|
+
[me.tenant.id]: {
|
|
247
|
+
name: me.tenant.name,
|
|
248
|
+
role,
|
|
249
|
+
token: result.token,
|
|
250
|
+
key_id: result.key_id,
|
|
251
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
writeCredentials(updated);
|
|
205
256
|
console.log(`\u2713 Signed in as ${me.user?.email ?? me.user?.id}`);
|
|
206
|
-
console.log(` Tenant : ${me.tenant
|
|
257
|
+
console.log(` Tenant : ${displayTenantName(me.tenant)} (${me.tenant.id})`);
|
|
207
258
|
console.log(` Stored : ${credentialsPath()}`);
|
|
208
|
-
|
|
209
|
-
|
|
259
|
+
const knownCount = Object.keys(updated.tenants).length;
|
|
260
|
+
const totalAvailable = me.tenants.length;
|
|
261
|
+
if (totalAvailable > knownCount) {
|
|
262
|
+
const missing = totalAvailable - knownCount;
|
|
263
|
+
console.log(` ${missing} more tenant${missing === 1 ? "" : "s"} available \u2014 add with: oma auth login --tenant <id>`);
|
|
264
|
+
} else if (knownCount > 1) {
|
|
265
|
+
console.log(` ${knownCount} tenants stored \u2014 switch with: oma auth tenant use <id>`);
|
|
210
266
|
}
|
|
211
267
|
}
|
|
268
|
+
function displayTenantName(t) {
|
|
269
|
+
const trimmed = (t.name ?? "").trim();
|
|
270
|
+
if (!trimmed || trimmed === "'s workspace" || trimmed.startsWith("'s ")) return t.id;
|
|
271
|
+
return trimmed;
|
|
272
|
+
}
|
|
212
273
|
function openBrowser(url) {
|
|
213
274
|
try {
|
|
214
275
|
const p = process.platform;
|
|
@@ -230,12 +291,13 @@ var commands = [
|
|
|
230
291
|
{
|
|
231
292
|
group: "Auth",
|
|
232
293
|
match: ["auth", "login"],
|
|
233
|
-
usage: "oma auth login [--base-url <url>]",
|
|
234
|
-
desc: "Open browser to authenticate;
|
|
294
|
+
usage: "oma auth login [--base-url <url>] [--tenant <id>]",
|
|
295
|
+
desc: "Open browser to authenticate; --tenant pre-picks a workspace",
|
|
235
296
|
http: "POST /v1/me/cli-tokens (browser handoff via /cli/login)",
|
|
236
297
|
async run(_config, args) {
|
|
237
298
|
const baseUrl = (flag(args, "--base-url") ?? process.env.OMA_BASE_URL ?? "https://openma.dev").replace(/\/+$/, "");
|
|
238
|
-
|
|
299
|
+
const tenant = flag(args, "--tenant");
|
|
300
|
+
await authLogin(baseUrl, tenant);
|
|
239
301
|
}
|
|
240
302
|
},
|
|
241
303
|
{
|
|
@@ -253,7 +315,7 @@ var commands = [
|
|
|
253
315
|
group: "Auth",
|
|
254
316
|
match: ["whoami"],
|
|
255
317
|
usage: "oma whoami",
|
|
256
|
-
desc: "Show current user, tenant, and base URL",
|
|
318
|
+
desc: "Show current user, active tenant, and base URL",
|
|
257
319
|
http: "GET /v1/me",
|
|
258
320
|
async run(config) {
|
|
259
321
|
try {
|
|
@@ -265,9 +327,12 @@ var commands = [
|
|
|
265
327
|
console.log(`Base URL : ${config.baseUrl}`);
|
|
266
328
|
console.log(`Source : ${config.source === "env" ? "OMA_API_KEY env var" : "stored credentials"}`);
|
|
267
329
|
console.log(`User : ${me.user?.email ?? me.user?.id ?? "(unknown \u2014 legacy key without user_id)"}`);
|
|
268
|
-
console.log(`Tenant : ${me.tenant.name || me.tenant.id} (${me.tenant.id})`);
|
|
269
330
|
if (me.tenants.length > 1) {
|
|
270
|
-
console.log(`
|
|
331
|
+
console.log(`Tenant : ${displayTenantName(me.tenant)} (${me.tenant.id})`);
|
|
332
|
+
const others = me.tenants.filter((t) => t.id !== me.tenant.id);
|
|
333
|
+
if (others.length) {
|
|
334
|
+
console.log(`Available: ${others.map((t) => t.id).join(", ")} \u2014 switch with: oma auth tenant use <id>`);
|
|
335
|
+
}
|
|
271
336
|
}
|
|
272
337
|
} catch (err) {
|
|
273
338
|
console.error(`whoami failed: ${err.message}`);
|
|
@@ -291,8 +356,20 @@ var commands = [
|
|
|
291
356
|
return;
|
|
292
357
|
}
|
|
293
358
|
const stored = readCredentials();
|
|
294
|
-
const
|
|
295
|
-
table([
|
|
359
|
+
const active = stored?.active_tenant_id;
|
|
360
|
+
table([
|
|
361
|
+
["", "ID", "NAME", "ROLE", "TOKEN"],
|
|
362
|
+
...data.map((t) => [
|
|
363
|
+
t.id === active ? "*" : " ",
|
|
364
|
+
t.id,
|
|
365
|
+
t.name || "\u2014",
|
|
366
|
+
t.role,
|
|
367
|
+
stored?.tenants[t.id] ? "stored" : "\u2014"
|
|
368
|
+
])
|
|
369
|
+
]);
|
|
370
|
+
console.log(`
|
|
371
|
+
* = active. "stored" = local token cached. To switch active: oma auth tenant use <id>`);
|
|
372
|
+
console.log(`To add a tenant the CLI hasn't seen yet: oma auth login --tenant <id>`);
|
|
296
373
|
}
|
|
297
374
|
},
|
|
298
375
|
{
|
|
@@ -300,9 +377,9 @@ var commands = [
|
|
|
300
377
|
match: ["auth", "tenant", "use"],
|
|
301
378
|
needsArg: true,
|
|
302
379
|
usage: "oma auth tenant use <tenant-id>",
|
|
303
|
-
desc: "Switch active tenant
|
|
304
|
-
http: "POST
|
|
305
|
-
async run(
|
|
380
|
+
desc: "Switch active tenant; if not yet authenticated for it, opens browser to mint",
|
|
381
|
+
http: "(local file update \u2014 or POST /v1/me/cli-tokens via browser if no cached token)",
|
|
382
|
+
async run(_config, args) {
|
|
306
383
|
const tenantId = args[0];
|
|
307
384
|
if (!tenantId) {
|
|
308
385
|
console.error("Usage: oma auth tenant use <tenant-id>");
|
|
@@ -313,7 +390,14 @@ var commands = [
|
|
|
313
390
|
console.error("No stored credentials. Run: oma auth login");
|
|
314
391
|
process.exit(1);
|
|
315
392
|
}
|
|
316
|
-
|
|
393
|
+
if (stored.tenants[tenantId]) {
|
|
394
|
+
const updated = { ...stored, active_tenant_id: tenantId };
|
|
395
|
+
writeCredentials(updated);
|
|
396
|
+
const profile = stored.tenants[tenantId];
|
|
397
|
+
console.log(`\u2713 Active tenant: ${profile.name || tenantId} (${tenantId})`);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
console.log(`No cached token for ${tenantId}. Opening browser to authorize\u2026`);
|
|
317
401
|
await authLogin(stored.base_url, tenantId);
|
|
318
402
|
}
|
|
319
403
|
},
|