@openma/cli 0.1.0-beta.3 → 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 +101 -25
- 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
|
}
|
|
@@ -195,21 +234,35 @@ async function authLogin(baseUrl, requestedTenant) {
|
|
|
195
234
|
});
|
|
196
235
|
const tempConfig = { baseUrl, apiKey: result.token, json: false, source: "stored" };
|
|
197
236
|
const me = await apiFetch(tempConfig, "/v1/me");
|
|
198
|
-
|
|
199
|
-
|
|
237
|
+
const existing = readCredentials();
|
|
238
|
+
const role = me.tenants.find((t) => t.id === me.tenant.id)?.role ?? "owner";
|
|
239
|
+
const updated = {
|
|
240
|
+
version: 2,
|
|
200
241
|
base_url: baseUrl,
|
|
201
242
|
user: me.user ?? { id: result.user, email: "", name: null },
|
|
202
|
-
|
|
203
|
-
tenants:
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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);
|
|
208
256
|
console.log(`\u2713 Signed in as ${me.user?.email ?? me.user?.id}`);
|
|
209
257
|
console.log(` Tenant : ${displayTenantName(me.tenant)} (${me.tenant.id})`);
|
|
210
258
|
console.log(` Stored : ${credentialsPath()}`);
|
|
211
|
-
|
|
212
|
-
|
|
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>`);
|
|
213
266
|
}
|
|
214
267
|
}
|
|
215
268
|
function displayTenantName(t) {
|
|
@@ -238,12 +291,13 @@ var commands = [
|
|
|
238
291
|
{
|
|
239
292
|
group: "Auth",
|
|
240
293
|
match: ["auth", "login"],
|
|
241
|
-
usage: "oma auth login [--base-url <url>]",
|
|
242
|
-
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",
|
|
243
296
|
http: "POST /v1/me/cli-tokens (browser handoff via /cli/login)",
|
|
244
297
|
async run(_config, args) {
|
|
245
298
|
const baseUrl = (flag(args, "--base-url") ?? process.env.OMA_BASE_URL ?? "https://openma.dev").replace(/\/+$/, "");
|
|
246
|
-
|
|
299
|
+
const tenant = flag(args, "--tenant");
|
|
300
|
+
await authLogin(baseUrl, tenant);
|
|
247
301
|
}
|
|
248
302
|
},
|
|
249
303
|
{
|
|
@@ -261,7 +315,7 @@ var commands = [
|
|
|
261
315
|
group: "Auth",
|
|
262
316
|
match: ["whoami"],
|
|
263
317
|
usage: "oma whoami",
|
|
264
|
-
desc: "Show current user, tenant, and base URL",
|
|
318
|
+
desc: "Show current user, active tenant, and base URL",
|
|
265
319
|
http: "GET /v1/me",
|
|
266
320
|
async run(config) {
|
|
267
321
|
try {
|
|
@@ -273,9 +327,12 @@ var commands = [
|
|
|
273
327
|
console.log(`Base URL : ${config.baseUrl}`);
|
|
274
328
|
console.log(`Source : ${config.source === "env" ? "OMA_API_KEY env var" : "stored credentials"}`);
|
|
275
329
|
console.log(`User : ${me.user?.email ?? me.user?.id ?? "(unknown \u2014 legacy key without user_id)"}`);
|
|
276
|
-
console.log(`Tenant : ${displayTenantName(me.tenant)} (${me.tenant.id})`);
|
|
277
330
|
if (me.tenants.length > 1) {
|
|
278
|
-
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
|
+
}
|
|
279
336
|
}
|
|
280
337
|
} catch (err) {
|
|
281
338
|
console.error(`whoami failed: ${err.message}`);
|
|
@@ -299,8 +356,20 @@ var commands = [
|
|
|
299
356
|
return;
|
|
300
357
|
}
|
|
301
358
|
const stored = readCredentials();
|
|
302
|
-
const
|
|
303
|
-
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>`);
|
|
304
373
|
}
|
|
305
374
|
},
|
|
306
375
|
{
|
|
@@ -308,9 +377,9 @@ var commands = [
|
|
|
308
377
|
match: ["auth", "tenant", "use"],
|
|
309
378
|
needsArg: true,
|
|
310
379
|
usage: "oma auth tenant use <tenant-id>",
|
|
311
|
-
desc: "Switch active tenant
|
|
312
|
-
http: "POST
|
|
313
|
-
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) {
|
|
314
383
|
const tenantId = args[0];
|
|
315
384
|
if (!tenantId) {
|
|
316
385
|
console.error("Usage: oma auth tenant use <tenant-id>");
|
|
@@ -321,7 +390,14 @@ var commands = [
|
|
|
321
390
|
console.error("No stored credentials. Run: oma auth login");
|
|
322
391
|
process.exit(1);
|
|
323
392
|
}
|
|
324
|
-
|
|
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`);
|
|
325
401
|
await authLogin(stored.base_url, tenantId);
|
|
326
402
|
}
|
|
327
403
|
},
|