dexto 1.11.0 → 1.12.0

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.
@@ -30,17 +30,13 @@ export type DeviceCodePollResponse = {
30
30
  apiKey: DeviceCodeApiKeyResponse;
31
31
  };
32
32
  export interface UsageSummaryResponse {
33
- credits_usd: number;
34
- mtd_usage: {
33
+ balance_usd: number;
34
+ last_30_days: {
35
+ since: string;
35
36
  total_cost_usd: number;
36
- total_requests: number;
37
- by_model: Record<string, {
38
- requests: number;
39
- cost_usd: number;
40
- tokens: number;
41
- }>;
37
+ total_usage_events: number;
42
38
  };
43
- recent: Array<{
39
+ recent_model_usage: Array<{
44
40
  timestamp: string;
45
41
  model: string;
46
42
  cost_usd: number;
@@ -63,13 +59,16 @@ interface RequestOptions {
63
59
  */
64
60
  export declare class DextoApiClient {
65
61
  private readonly platformBaseUrl;
62
+ private readonly publicApiBaseUrl;
66
63
  private readonly timeoutMs;
67
64
  constructor(baseUrl?: string | {
68
65
  gatewayBaseUrl?: string | undefined;
69
66
  platformBaseUrl?: string | undefined;
67
+ publicApiBaseUrl?: string | undefined;
70
68
  });
71
69
  private createRequestSignal;
72
70
  private getPlatformUrl;
71
+ private getPublicApiUrl;
73
72
  private listPlatformApiKeys;
74
73
  private createPlatformApiKey;
75
74
  private deletePlatformApiKey;
@@ -86,7 +85,7 @@ export declare class DextoApiClient {
86
85
  keyId: string;
87
86
  }>;
88
87
  /**
89
- * Get usage summary (balance + MTD usage + recent history)
88
+ * Get usage summary (balance + last 30 days + recent model activity)
90
89
  */
91
90
  getUsageSummary(apiKey: string): Promise<UsageSummaryResponse>;
92
91
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../../src/cli/auth/api-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../../../src/cli/auth/api-client.ts"],"names":[],"mappings":"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"}
@@ -7,13 +7,10 @@
7
7
  // 3. Use tRPC if we want full-stack type safety
8
8
  // Currently using plain fetch() with runtime response validation.
9
9
  import { logger } from '@dexto/core';
10
- import { DEXTO_PLATFORM_URL, SUPABASE_ANON_KEY, SUPABASE_URL } from './constants.js';
10
+ import { DEXTO_PLATFORM_URL, DEXTO_PUBLIC_API_URL, SUPABASE_ANON_KEY, SUPABASE_URL, } from './constants.js';
11
11
  function parseString(value) {
12
12
  return typeof value === 'string' && value.trim().length > 0 ? value : null;
13
13
  }
14
- function parseBoolean(value) {
15
- return typeof value === 'boolean' ? value : null;
16
- }
17
14
  function parseNumber(value) {
18
15
  if (typeof value === 'number' && Number.isFinite(value)) {
19
16
  return value;
@@ -110,37 +107,14 @@ function parseSupabaseUser(payload) {
110
107
  name: fullName ?? email,
111
108
  };
112
109
  }
113
- function parseUsageByModel(payload) {
114
- if (typeof payload !== 'object' || payload === null) {
115
- return {};
116
- }
117
- const byModel = {};
118
- for (const [model, value] of Object.entries(payload)) {
119
- if (typeof value !== 'object' || value === null) {
120
- continue;
121
- }
122
- const requests = parseNumber(Reflect.get(value, 'requests'));
123
- const costUsd = parseNumber(Reflect.get(value, 'cost_usd'));
124
- const tokens = parseNumber(Reflect.get(value, 'tokens'));
125
- if (requests === null || costUsd === null || tokens === null) {
126
- continue;
127
- }
128
- byModel[model] = {
129
- requests,
130
- cost_usd: costUsd,
131
- tokens,
132
- };
133
- }
134
- return byModel;
135
- }
136
110
  function parseRecentUsage(payload) {
137
111
  if (!Array.isArray(payload)) {
138
- return [];
112
+ throw new Error('Invalid response from API');
139
113
  }
140
114
  const entries = [];
141
115
  for (const entry of payload) {
142
116
  if (typeof entry !== 'object' || entry === null) {
143
- continue;
117
+ throw new Error('Invalid response from API');
144
118
  }
145
119
  const timestamp = parseString(Reflect.get(entry, 'timestamp'));
146
120
  const model = parseString(Reflect.get(entry, 'model'));
@@ -152,7 +126,7 @@ function parseRecentUsage(payload) {
152
126
  costUsd === null ||
153
127
  inputTokens === null ||
154
128
  outputTokens === null) {
155
- continue;
129
+ throw new Error('Invalid response from API');
156
130
  }
157
131
  entries.push({
158
132
  timestamp,
@@ -168,26 +142,26 @@ function parseUsageSummaryResponse(payload) {
168
142
  if (typeof payload !== 'object' || payload === null) {
169
143
  throw new Error('Invalid response from API');
170
144
  }
171
- const creditsUsd = parseNumber(Reflect.get(payload, 'credits_usd'));
172
- const mtdUsage = Reflect.get(payload, 'mtd_usage');
173
- if (creditsUsd === null || typeof mtdUsage !== 'object' || mtdUsage === null) {
145
+ const balanceUsd = parseNumber(Reflect.get(payload, 'balance_usd'));
146
+ const last30Days = Reflect.get(payload, 'last_30_days');
147
+ if (balanceUsd === null || typeof last30Days !== 'object' || last30Days === null) {
174
148
  throw new Error('Invalid response from API');
175
149
  }
176
- const totalCostUsd = parseNumber(Reflect.get(mtdUsage, 'total_cost_usd'));
177
- const totalRequests = parseNumber(Reflect.get(mtdUsage, 'total_requests'));
178
- if (totalCostUsd === null || totalRequests === null) {
150
+ const since = parseString(Reflect.get(last30Days, 'since'));
151
+ const totalCostUsd = parseNumber(Reflect.get(last30Days, 'total_cost_usd'));
152
+ const totalUsageEvents = parseNumber(Reflect.get(last30Days, 'total_usage_events'));
153
+ if (!since || totalCostUsd === null || totalUsageEvents === null) {
179
154
  throw new Error('Invalid response from API');
180
155
  }
181
- const byModel = parseUsageByModel(Reflect.get(mtdUsage, 'by_model'));
182
- const recent = parseRecentUsage(Reflect.get(payload, 'recent'));
156
+ const recent = parseRecentUsage(Reflect.get(payload, 'recent_model_usage'));
183
157
  return {
184
- credits_usd: creditsUsd,
185
- mtd_usage: {
158
+ balance_usd: balanceUsd,
159
+ last_30_days: {
160
+ since,
186
161
  total_cost_usd: totalCostUsd,
187
- total_requests: totalRequests,
188
- by_model: byModel,
162
+ total_usage_events: totalUsageEvents,
189
163
  },
190
- recent,
164
+ recent_model_usage: recent,
191
165
  };
192
166
  }
193
167
  function parseBillingBalanceResponse(payload) {
@@ -217,23 +191,11 @@ function parseBillingCheckoutSessionResponse(payload) {
217
191
  checkoutSessionId,
218
192
  };
219
193
  }
220
- function parseValidateResponse(payload) {
221
- if (typeof payload !== 'object' || payload === null) {
222
- return false;
223
- }
224
- const valid = parseBoolean(Reflect.get(payload, 'valid'));
225
- return valid ?? false;
226
- }
227
194
  function parsePlatformKeyListResponse(payload) {
228
195
  if (typeof payload !== 'object' || payload === null) {
229
196
  throw new Error('Invalid response from API');
230
197
  }
231
- const success = parseBoolean(Reflect.get(payload, 'success'));
232
- if (success !== true) {
233
- const error = parseString(Reflect.get(payload, 'error'));
234
- throw new Error(error || 'Failed to fetch API keys');
235
- }
236
- const data = Reflect.get(payload, 'data');
198
+ const data = Reflect.get(payload, 'apiKeys');
237
199
  if (!Array.isArray(data)) {
238
200
  throw new Error('Invalid response from API');
239
201
  }
@@ -245,35 +207,29 @@ function parsePlatformKeyListResponse(payload) {
245
207
  const id = parseString(Reflect.get(entry, 'id'));
246
208
  const name = parseString(Reflect.get(entry, 'name'));
247
209
  const status = parseString(Reflect.get(entry, 'status'));
248
- const isActive = parseBoolean(Reflect.get(entry, 'isActive'));
249
- if (!id || !status || isActive === null) {
210
+ if (!id || !name || !status) {
250
211
  continue;
251
212
  }
252
- keys.push({ id, name, status, isActive });
213
+ keys.push({ id, name, status });
253
214
  }
254
- return { success: true, data: keys };
215
+ return { apiKeys: keys };
255
216
  }
256
217
  function parsePlatformCreateKeyResponse(payload) {
257
218
  if (typeof payload !== 'object' || payload === null) {
258
219
  throw new Error('Invalid response from API');
259
220
  }
260
- const success = parseBoolean(Reflect.get(payload, 'success'));
261
- if (success !== true) {
262
- const error = parseString(Reflect.get(payload, 'error'));
263
- return { success: false, error: error || 'Failed to create API key' };
264
- }
265
- const data = Reflect.get(payload, 'data');
221
+ const data = Reflect.get(payload, 'apiKey');
266
222
  if (typeof data !== 'object' || data === null) {
267
223
  throw new Error('Invalid response from API');
268
224
  }
269
225
  const id = parseString(Reflect.get(data, 'id'));
270
- const fullKey = parseString(Reflect.get(data, 'fullKey'));
226
+ const fullKey = parseString(Reflect.get(payload, 'fullKey'));
271
227
  if (!id || !fullKey) {
272
228
  throw new Error('Invalid response from API');
273
229
  }
274
230
  return {
275
- success: true,
276
- data: { id, fullKey },
231
+ apiKey: { id },
232
+ fullKey,
277
233
  };
278
234
  }
279
235
  function formatHttpFailure(status, payload, rawText) {
@@ -285,21 +241,33 @@ function formatHttpFailure(status, payload, rawText) {
285
241
  }
286
242
  return `${status}`;
287
243
  }
244
+ function normalizePublicApiBaseUrl(value) {
245
+ const normalized = value.replace(/\/+$/, '');
246
+ const url = new URL(normalized);
247
+ const isLoopback = ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname);
248
+ if (url.protocol !== 'https:' && !(url.protocol === 'http:' && isLoopback)) {
249
+ throw new Error('publicApiBaseUrl must use HTTPS unless it targets a loopback host');
250
+ }
251
+ return normalized;
252
+ }
288
253
  /**
289
254
  * Dexto API client for key management
290
255
  */
291
256
  export class DextoApiClient {
292
257
  platformBaseUrl;
258
+ publicApiBaseUrl;
293
259
  timeoutMs = 10_000;
294
260
  constructor(baseUrl = {}) {
295
261
  if (typeof baseUrl === 'string') {
296
262
  const normalized = baseUrl.replace(/\/+$/, '');
297
263
  this.platformBaseUrl = normalized;
264
+ this.publicApiBaseUrl = normalizePublicApiBaseUrl(normalized);
298
265
  return;
299
266
  }
300
267
  this.platformBaseUrl = (baseUrl.platformBaseUrl ??
301
268
  baseUrl.gatewayBaseUrl ??
302
269
  DEXTO_PLATFORM_URL).replace(/\/+$/, '');
270
+ this.publicApiBaseUrl = normalizePublicApiBaseUrl(baseUrl.publicApiBaseUrl ?? DEXTO_PUBLIC_API_URL);
303
271
  }
304
272
  createRequestSignal(signal) {
305
273
  const timeoutSignal = AbortSignal.timeout(this.timeoutMs);
@@ -311,8 +279,11 @@ export class DextoApiClient {
311
279
  getPlatformUrl(path) {
312
280
  return `${this.platformBaseUrl}${path}`;
313
281
  }
282
+ getPublicApiUrl(path) {
283
+ return `${this.publicApiBaseUrl}${path}`;
284
+ }
314
285
  async listPlatformApiKeys(authToken) {
315
- const response = await fetch(this.getPlatformUrl('/api/keys'), {
286
+ const response = await fetch(this.getPlatformUrl('/api/api-keys'), {
316
287
  method: 'GET',
317
288
  headers: {
318
289
  Authorization: `Bearer ${authToken}`,
@@ -324,10 +295,10 @@ export class DextoApiClient {
324
295
  throw new Error(`API request failed: ${formatHttpFailure(response.status, null, rawText)}`);
325
296
  }
326
297
  const payload = await response.json();
327
- return parsePlatformKeyListResponse(payload).data;
298
+ return parsePlatformKeyListResponse(payload).apiKeys;
328
299
  }
329
300
  async createPlatformApiKey(authToken, name) {
330
- const response = await fetch(this.getPlatformUrl('/api/keys'), {
301
+ const response = await fetch(this.getPlatformUrl('/api/api-keys'), {
331
302
  method: 'POST',
332
303
  headers: {
333
304
  Authorization: `Bearer ${authToken}`,
@@ -342,16 +313,13 @@ export class DextoApiClient {
342
313
  }
343
314
  const payload = await response.json();
344
315
  const result = parsePlatformCreateKeyResponse(payload);
345
- if (!result.success || !result.data) {
346
- throw new Error(result.error || 'Failed to create Dexto API key');
347
- }
348
316
  return {
349
- dextoApiKey: result.data.fullKey,
350
- keyId: result.data.id,
317
+ dextoApiKey: result.fullKey,
318
+ keyId: result.apiKey.id,
351
319
  };
352
320
  }
353
321
  async deletePlatformApiKey(authToken, keyId) {
354
- const response = await fetch(this.getPlatformUrl(`/api/keys/${encodeURIComponent(keyId)}`), {
322
+ const response = await fetch(this.getPlatformUrl(`/api/api-keys/${encodeURIComponent(keyId)}`), {
355
323
  method: 'DELETE',
356
324
  headers: {
357
325
  Authorization: `Bearer ${authToken}`,
@@ -367,25 +335,21 @@ export class DextoApiClient {
367
335
  * Validate if a Dexto API key is valid
368
336
  */
369
337
  async validateDextoApiKey(apiKey) {
370
- try {
371
- logger.debug('Validating DEXTO_API_KEY');
372
- const response = await fetch(this.getPlatformUrl('/api/keys/validate'), {
373
- method: 'GET',
374
- headers: {
375
- Authorization: `Bearer ${apiKey}`,
376
- },
377
- signal: this.createRequestSignal(undefined),
378
- });
379
- if (!response.ok) {
380
- return false;
381
- }
382
- const payload = await response.json();
383
- return parseValidateResponse(payload);
384
- }
385
- catch (error) {
386
- logger.error(`Error validating Dexto API key: ${error}`);
338
+ logger.debug('Validating DEXTO_API_KEY');
339
+ const response = await fetch(this.getPublicApiUrl('/v1/models'), {
340
+ method: 'GET',
341
+ headers: {
342
+ Authorization: `Bearer ${apiKey}`,
343
+ },
344
+ signal: this.createRequestSignal(undefined),
345
+ });
346
+ if (response.status === 401) {
387
347
  return false;
388
348
  }
349
+ if (!response.ok) {
350
+ throw new Error(`Unable to validate Dexto API key: HTTP ${response.status}`);
351
+ }
352
+ return true;
389
353
  }
390
354
  /**
391
355
  * Provision Dexto API key and always return a usable secret key value.
@@ -394,7 +358,7 @@ export class DextoApiClient {
394
358
  async provisionDextoApiKey(authToken, name = 'Dexto CLI Key', regenerate = false) {
395
359
  try {
396
360
  logger.debug(`Provisioning DEXTO_API_KEY with name: ${name}, regenerate: ${regenerate}`);
397
- const matchingKeys = (await this.listPlatformApiKeys(authToken)).filter((key) => key.isActive && key.name === name);
361
+ const matchingKeys = (await this.listPlatformApiKeys(authToken)).filter((key) => key.status === 'active' && key.name === name);
398
362
  if (matchingKeys.length > 0) {
399
363
  if (!regenerate) {
400
364
  logger.debug(`Active key exists (${matchingKeys[0]?.id ?? 'unknown'}); rotating to obtain key value`);
@@ -416,12 +380,12 @@ export class DextoApiClient {
416
380
  }
417
381
  }
418
382
  /**
419
- * Get usage summary (balance + MTD usage + recent history)
383
+ * Get usage summary (balance + last 30 days + recent model activity)
420
384
  */
421
385
  async getUsageSummary(apiKey) {
422
386
  try {
423
387
  logger.debug('Fetching usage summary');
424
- const response = await fetch(this.getPlatformUrl('/api/account/usage'), {
388
+ const response = await fetch(this.getPublicApiUrl('/v1/billing/summary'), {
425
389
  method: 'GET',
426
390
  headers: {
427
391
  Authorization: `Bearer ${apiKey}`,
@@ -14,6 +14,7 @@
14
14
  * - SUPABASE_ANON_KEY: Override anon key (from `supabase start` output)
15
15
  * - DEXTO_API_URL: Override Dexto gateway URL for data-plane calls (e.g., http://localhost:3001)
16
16
  * - DEXTO_PLATFORM_URL: Override Dexto app URL for auth/key/account control-plane calls (e.g., http://localhost:3002)
17
+ * - DEXTO_PUBLIC_API_URL: Override versioned public API URL (e.g., http://localhost:3002)
17
18
  */
18
19
  export declare const SUPABASE_URL: string;
19
20
  export declare const SUPABASE_ANON_KEY: string;
@@ -25,6 +26,7 @@ export declare const DEXTO_API_URL: string;
25
26
  * Dexto app URL for auth/key/account control-plane endpoints.
26
27
  */
27
28
  export declare const DEXTO_PLATFORM_URL: string;
29
+ export declare const DEXTO_PUBLIC_API_URL: string;
28
30
  /**
29
31
  * Dexto Nova credits purchase URL
30
32
  */
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/cli/auth/constants.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,YAAY,QAAyE,CAAC;AACnG,eAAO,MAAM,iBAAiB,QAEwL,CAAC;AAEvN;;GAEG;AACH,eAAO,MAAM,aAAa,QAAsD,CAAC;AAEjF;;GAEG;AACH,eAAO,MAAM,kBAAkB,QAA2D,CAAC;AAE3F;;GAEG;AACH,eAAO,MAAM,iBAAiB,QACwD,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/cli/auth/constants.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,YAAY,QAAyE,CAAC;AACnG,eAAO,MAAM,iBAAiB,QAEwL,CAAC;AAEvN;;GAEG;AACH,eAAO,MAAM,aAAa,QAAsD,CAAC;AAEjF;;GAEG;AACH,eAAO,MAAM,kBAAkB,QAA2D,CAAC;AAE3F,eAAO,MAAM,oBAAoB,QAA6D,CAAC;AAE/F;;GAEG;AACH,eAAO,MAAM,iBAAiB,QACwD,CAAC"}
@@ -15,6 +15,7 @@
15
15
  * - SUPABASE_ANON_KEY: Override anon key (from `supabase start` output)
16
16
  * - DEXTO_API_URL: Override Dexto gateway URL for data-plane calls (e.g., http://localhost:3001)
17
17
  * - DEXTO_PLATFORM_URL: Override Dexto app URL for auth/key/account control-plane calls (e.g., http://localhost:3002)
18
+ * - DEXTO_PUBLIC_API_URL: Override versioned public API URL (e.g., http://localhost:3002)
18
19
  */
19
20
  export const SUPABASE_URL = process.env.SUPABASE_URL || 'https://gdfbxznhnnsamvsrtwjq.supabase.co';
20
21
  export const SUPABASE_ANON_KEY = process.env.SUPABASE_ANON_KEY ||
@@ -27,6 +28,7 @@ export const DEXTO_API_URL = process.env.DEXTO_API_URL || 'https://app.dexto.ai'
27
28
  * Dexto app URL for auth/key/account control-plane endpoints.
28
29
  */
29
30
  export const DEXTO_PLATFORM_URL = process.env.DEXTO_PLATFORM_URL || 'https://app.dexto.ai';
31
+ export const DEXTO_PUBLIC_API_URL = process.env.DEXTO_PUBLIC_API_URL || 'https://api.dexto.ai';
30
32
  /**
31
33
  * Dexto Nova credits purchase URL
32
34
  */
@@ -4,7 +4,7 @@ export { type DeviceApiKeyLoginResult } from './types.js';
4
4
  export { type DeviceLoginPrompt, performDeviceCodeLogin } from './device.js';
5
5
  export { type PersistOAuthLoginOptions, type PersistedLoginResult, persistDeviceApiKeyLoginResult, persistOAuthLoginResult, } from './login-persistence.js';
6
6
  export { type UsageSummaryResponse, DextoApiClient, getDextoApiClient } from './api-client.js';
7
- export { SUPABASE_URL, SUPABASE_ANON_KEY, DEXTO_API_URL, DEXTO_PLATFORM_URL } from './constants.js';
7
+ export { SUPABASE_URL, SUPABASE_ANON_KEY, DEXTO_API_URL, DEXTO_PLATFORM_URL, DEXTO_PUBLIC_API_URL, } from './constants.js';
8
8
  export { buildDextoBillingUrl, getBillingBalanceForCurrentLogin, createBillingCheckoutForCurrentLogin, openDextoBillingPage, } from './billing.js';
9
9
  export { type DextoApiKeyProvisionStatus, type DextoApiKeyProvisionStatusLevel, type EnsureDextoApiKeyOptions, ensureDextoApiKeyForAuthToken, saveDextoApiKeyToEnv, removeDextoApiKeyFromEnv, } from './dexto-api-key.js';
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/auth/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,KAAK,UAAU,EACf,SAAS,EACT,QAAQ,EACR,UAAU,EACV,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,eAAe,GAClB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,KAAK,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,EACH,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,8BAA8B,EAC9B,uBAAuB,GAC1B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,KAAK,oBAAoB,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE/F,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpG,OAAO,EACH,oBAAoB,EACpB,gCAAgC,EAChC,oCAAoC,EACpC,oBAAoB,GACvB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACH,KAAK,0BAA0B,EAC/B,KAAK,+BAA+B,EACpC,KAAK,wBAAwB,EAC7B,6BAA6B,EAC7B,oBAAoB,EACpB,wBAAwB,GAC3B,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/auth/index.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,KAAK,UAAU,EACf,SAAS,EACT,QAAQ,EACR,UAAU,EACV,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,eAAe,GAClB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAC1D,OAAO,EAAE,KAAK,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAE7E,OAAO,EACH,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EACzB,8BAA8B,EAC9B,uBAAuB,GAC1B,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,KAAK,oBAAoB,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE/F,OAAO,EACH,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,kBAAkB,EAClB,oBAAoB,GACvB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACH,oBAAoB,EACpB,gCAAgC,EAChC,oCAAoC,EACpC,oBAAoB,GACvB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACH,KAAK,0BAA0B,EAC/B,KAAK,+BAA+B,EACpC,KAAK,wBAAwB,EAC7B,6BAA6B,EAC7B,oBAAoB,EACpB,wBAAwB,GAC3B,MAAM,oBAAoB,CAAC"}
@@ -4,6 +4,6 @@ export { storeAuth, loadAuth, removeAuth, isAuthenticated, getAuthToken, getAuth
4
4
  export { performDeviceCodeLogin } from './device.js';
5
5
  export { persistDeviceApiKeyLoginResult, persistOAuthLoginResult, } from './login-persistence.js';
6
6
  export { DextoApiClient, getDextoApiClient } from './api-client.js';
7
- export { SUPABASE_URL, SUPABASE_ANON_KEY, DEXTO_API_URL, DEXTO_PLATFORM_URL } from './constants.js';
7
+ export { SUPABASE_URL, SUPABASE_ANON_KEY, DEXTO_API_URL, DEXTO_PLATFORM_URL, DEXTO_PUBLIC_API_URL, } from './constants.js';
8
8
  export { buildDextoBillingUrl, getBillingBalanceForCurrentLogin, createBillingCheckoutForCurrentLogin, openDextoBillingPage, } from './billing.js';
9
9
  export { ensureDextoApiKeyForAuthToken, saveDextoApiKeyToEnv, removeDextoApiKeyFromEnv, } from './dexto-api-key.js';
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/billing/status.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,wBAAsB,0BAA0B,CAAC,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA4E/F"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/billing/status.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,wBAAsB,0BAA0B,CAAC,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAmE/F"}
@@ -34,27 +34,17 @@ export async function handleBillingStatusCommand(options = {}) {
34
34
  const usage = await apiClient.getUsageSummary(auth.dextoApiKey);
35
35
  // Display balance
36
36
  console.log(chalk.cyan('💰 Balance'));
37
- console.log(` ${chalk.bold('$' + usage.credits_usd.toFixed(2))} remaining`);
37
+ console.log(` ${chalk.bold('$' + usage.balance_usd.toFixed(2))} remaining`);
38
38
  console.log(chalk.dim(` Buy more credits: run ${chalk.cyan('dexto billing --buy')}`));
39
39
  console.log();
40
- // Display month-to-date usage
41
- console.log(chalk.cyan('📊 This Month'));
42
- console.log(` Spent: ${chalk.yellow('$' + usage.mtd_usage.total_cost_usd.toFixed(4))}`);
43
- console.log(` Requests: ${chalk.yellow(usage.mtd_usage.total_requests.toString())}`);
44
- // Show usage by model if there's any
45
- const modelEntries = Object.entries(usage.mtd_usage.by_model);
46
- if (modelEntries.length > 0) {
47
- console.log();
48
- console.log(chalk.cyan('📈 Usage by Model'));
49
- for (const [model, stats] of modelEntries) {
50
- console.log(` ${chalk.dim(model)}: $${stats.cost_usd.toFixed(4)} (${stats.requests} requests)`);
51
- }
52
- }
40
+ console.log(chalk.cyan('📊 Last 30 Days'));
41
+ console.log(` Spent: ${chalk.yellow('$' + usage.last_30_days.total_cost_usd.toFixed(4))}`);
42
+ console.log(` Usage events: ${chalk.yellow(usage.last_30_days.total_usage_events.toString())}`);
53
43
  // Show recent usage if any
54
- if (usage.recent.length > 0) {
44
+ if (usage.recent_model_usage.length > 0) {
55
45
  console.log();
56
46
  console.log(chalk.cyan('🕐 Recent Activity'));
57
- for (const entry of usage.recent.slice(0, 5)) {
47
+ for (const entry of usage.recent_model_usage.slice(0, 5)) {
58
48
  const date = new Date(entry.timestamp).toLocaleString();
59
49
  console.log(` ${chalk.dim(date)} - ${entry.model}: $${entry.cost_usd.toFixed(4)}`);
60
50
  }
@@ -63,7 +53,7 @@ export async function handleBillingStatusCommand(options = {}) {
63
53
  catch (error) {
64
54
  const errorMessage = error instanceof Error ? error.message : String(error);
65
55
  console.log(chalk.red(`❌ Failed to fetch billing info: ${errorMessage}`));
66
- console.log(chalk.dim('Your API key may be invalid. Try `dexto login` to refresh.'));
56
+ console.log(chalk.dim('Try again shortly. If your API key is invalid, run `dexto login`.'));
67
57
  }
68
58
  if (options.buy) {
69
59
  await openCreditsPage();