@moda-ai/cli 1.13.8 → 1.13.9
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/init/tenant.d.ts
CHANGED
|
@@ -4,6 +4,13 @@ interface BootstrapResult {
|
|
|
4
4
|
tenantName: string;
|
|
5
5
|
tenantSlug: string;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Classify a failed /api/cli/context (or bootstrap) response so moda init
|
|
9
|
+
* distinguishes retryable infra outages (Postgres pool exhaustion → 503
|
|
10
|
+
* `database_unavailable`) from auth failures. Auth itself can succeed from
|
|
11
|
+
* a cached moda_ct_ token even when this hydrate call 500s (MODA-742).
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatControlPlaneFetchError(action: string, status: number, body: string): string;
|
|
7
14
|
export interface TenantKeyResult extends BootstrapResult {
|
|
8
15
|
/**
|
|
9
16
|
* True when a previously stored key for the selected tenant passed the
|
package/dist/init/tenant.js
CHANGED
|
@@ -8,6 +8,37 @@ import { authFetch, getCachedLoginContext } from '../auth.js';
|
|
|
8
8
|
import { loadCliConfig, resolveIngestUrl, resolveModaBaseUrl, saveCliConfig, } from '../config.js';
|
|
9
9
|
import { getModaDir, resolveApiKeyFromActiveProfile, resolveTenantIdFromActiveProfile, writeSecretJsonFile, } from '../profiles.js';
|
|
10
10
|
import { CliAccessError, CliInputError, CliInputRequiredError } from '../errors.js';
|
|
11
|
+
/**
|
|
12
|
+
* Classify a failed /api/cli/context (or bootstrap) response so moda init
|
|
13
|
+
* distinguishes retryable infra outages (Postgres pool exhaustion → 503
|
|
14
|
+
* `database_unavailable`) from auth failures. Auth itself can succeed from
|
|
15
|
+
* a cached moda_ct_ token even when this hydrate call 500s (MODA-742).
|
|
16
|
+
*/
|
|
17
|
+
export function formatControlPlaneFetchError(action, status, body) {
|
|
18
|
+
let parsed;
|
|
19
|
+
try {
|
|
20
|
+
parsed = JSON.parse(body);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// Non-JSON body — fall through to generic formatting.
|
|
24
|
+
}
|
|
25
|
+
const isDbUnavailable = status === 503 &&
|
|
26
|
+
(parsed?.error === 'database_unavailable' ||
|
|
27
|
+
parsed?.retryable === true ||
|
|
28
|
+
/database_unavailable|too many database connections|rds_reserved|connection pool/i.test(body));
|
|
29
|
+
if (isDbUnavailable) {
|
|
30
|
+
return (`Failed to ${action} (${status}): Moda control-plane database is temporarily unavailable ` +
|
|
31
|
+
`(connection pool exhausted). This is not an authentication failure — your session token ` +
|
|
32
|
+
`is fine. Retry in a few seconds.` +
|
|
33
|
+
(parsed?.message ? ` (${parsed.message})` : ''));
|
|
34
|
+
}
|
|
35
|
+
if (status >= 500 &&
|
|
36
|
+
/too many database connections|rds_reserved|remaining connection slots/i.test(body)) {
|
|
37
|
+
return (`Failed to ${action} (${status}): Moda control-plane database ran out of connections. ` +
|
|
38
|
+
`This is a retryable infra outage, not an auth failure. Retry in a few seconds. Body: ${body}`);
|
|
39
|
+
}
|
|
40
|
+
return `Failed to ${action} (${status}): ${body}`;
|
|
41
|
+
}
|
|
11
42
|
// Mirrors the backend's checkAdminAccess: only the viewer role is denied.
|
|
12
43
|
const ADMIN_ACCESS_MESSAGE = 'You need admin or owner access to create API keys.';
|
|
13
44
|
const ADMIN_ACCESS_GUIDANCE = 'Ask your organization owner to upgrade your role.';
|
|
@@ -250,7 +281,7 @@ export async function selectTenantAndCreateKey(options = {}) {
|
|
|
250
281
|
const contextRes = await authFetch('/api/cli/context', {}, authOptions);
|
|
251
282
|
if (!contextRes.ok) {
|
|
252
283
|
const body = await contextRes.text();
|
|
253
|
-
throw new Error(
|
|
284
|
+
throw new Error(formatControlPlaneFetchError('fetch context', contextRes.status, body));
|
|
254
285
|
}
|
|
255
286
|
ctx = (await contextRes.json());
|
|
256
287
|
}
|
|
@@ -368,7 +399,7 @@ export async function selectTenantAndCreateKey(options = {}) {
|
|
|
368
399
|
}
|
|
369
400
|
if (!bootstrapRes.ok) {
|
|
370
401
|
const body = await bootstrapRes.text();
|
|
371
|
-
throw new Error(
|
|
402
|
+
throw new Error(formatControlPlaneFetchError('create API key', bootstrapRes.status, body));
|
|
372
403
|
}
|
|
373
404
|
result = (await bootstrapRes.json());
|
|
374
405
|
clearBootstrapIdempotencyKey(selected.id, authOptions);
|
package/package.json
CHANGED