@pouchy_ai/admin-sdk 0.36.0 → 0.38.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,33 @@
2
2
 
3
3
  All notable changes to `@pouchy_ai/admin-sdk` are documented here.
4
4
 
5
+ ## 0.38.0 — 2026-09-25
6
+
7
+ - **`ADMIN_ERROR_CODES` gains `subscription_exists`** (409). `POST
8
+ /v1/projects/{id}/billing/checkout` now refuses when the account already pays
9
+ through a live Stripe subscription. Before, a second checkout opened a SECOND
10
+ subscription: both billed, and each one's lifecycle events rewrote the
11
+ account's plan. Upgrade through `POST /v1/projects/{id}/billing/upgrade`
12
+ instead, which moves the existing subscription to the new price and charges
13
+ the prorated difference. Additive: the `AdminErrorCode` type was
14
+ already open to codes newer than the build.
15
+
16
+ ## 0.37.0 — 2026-09-24
17
+
18
+ - **`getUsage()` now types the `credits` block** the server has returned since
19
+ admin API 1.14.0: `{ project, account, limit, scope: 'account', enforcement:
20
+ { armed, plan, verdict, effect } }` (new exported types `UsageCredits` and
21
+ `UsageCreditEnforcement`). Additive: `usage` is unchanged, and `credits` is
22
+ optional because a server older than 1.14.0 does not send it.
23
+
24
+ `usage.credits / usage.creditLimit` is NOT a headroom ratio — `usage.credits`
25
+ is this project's slice and `creditLimit` is the ACCOUNT's pooled allowance,
26
+ so on a multi-project account it understates consumption. Until now the typed
27
+ client offered only that ratio (reading `res.credits` did not compile), and
28
+ this README's quickstart printed it. Read `credits.account / credits.limit`
29
+ instead; `account` is `null` when the pool could not be read, which means
30
+ unknown, never zero.
31
+
5
32
  ## 0.36.0 — 2026-09-12
6
33
 
7
34
  - **`deleteChannel` reports what happened to the PROVIDER registration**, and
package/README.md CHANGED
@@ -38,9 +38,15 @@ const { key } = await admin.createKey({ label: 'prod-backend', env: 'live' });
38
38
  console.log(key); // the plaintext token — shown ONCE
39
39
 
40
40
  // Read this month's usage — MAU, tokens, and the credit meter (all typed)
41
- const { usage } = await admin.getUsage();
41
+ const { usage, credits } = await admin.getUsage();
42
42
  console.log(usage.mau, '/', usage.mauLimit, 'MAU');
43
- console.log(usage.credits, '/', usage.creditLimit, 'credits');
43
+ // Credits pool across the ACCOUNT's projects: `usage.credits` is only this
44
+ // project's slice, so divide the ACCOUNT figure by the limit, never the slice.
45
+ // `account` is null when the pool could not be read — unknown, not zero.
46
+ if (credits) {
47
+ console.log(credits.project, 'credits here;', credits.account ?? '?', '/', credits.limit, 'account-wide');
48
+ console.log('next turn:', credits.enforcement.verdict ?? 'unknown', '—', credits.enforcement.effect);
49
+ }
44
50
  // Voice is the priciest metered unit — watch its slice, not just the total
45
51
  console.log(usage.creditsVoice, 'of those credits were', usage.voiceCalls, 'voice calls');
46
52
 
@@ -417,6 +423,7 @@ type), and is append-only:
417
423
  | `event_mismatch` | `signalRun` | the run wants a different key; your event is early or wrong |
418
424
  | `one_shot_spent` | `updateSchedule` | the one-shot already fired — create a new schedule instead of re-enabling |
419
425
  | `ghost_row` | `updateSchedule` | a legacy fieldless row that can never run — delete it, create a new schedule |
426
+ | `subscription_exists` | `POST /v1/projects/{id}/billing/checkout` (console) | the account already pays through a live subscription — upgrade it with `POST …/billing/upgrade` |
420
427
 
421
428
  `code` is `undefined` on every failure the server did not tag (400s, 404s, the
422
429
  429, transport errors), so always keep a `default` branch. The type has a
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare const ADMIN_SDK_VERSION = "0.36.0";
1
+ export declare const ADMIN_SDK_VERSION = "0.38.0";
2
2
  export declare const DEFAULT_BASE_URL = "https://pouchy.ai/v1/admin";
3
3
  /** Deadline for the routes whose server handler declares `maxDuration: 300` —
4
4
  * the server's own ceiling plus headroom, so a client abort can only ever mean
@@ -60,7 +60,7 @@ export interface AdminClientOptions {
60
60
  * published: on this plane the status line never disambiguates, so two of the
61
61
  * durable-run routes answer 409 for two entirely different reasons each, with
62
62
  * different recoveries. `code` is the only thing that tells them apart. */
63
- export declare const ADMIN_ERROR_CODES: readonly ["story_contract_v2_write_disabled", "story_contract_v3_write_disabled", "story_contract_v4_write_disabled", "has_pins", "pins_unknown", "story_package_limit", "story_package_documents_limit", "episode_history_incomplete", "episode_ended", "idempotency_key_reused", "stale_deliberation", "deliberation_disabled", "deliberation_uncalibrated", "deliberation_not_enabled", "deliberation_candidates_exceeded", "schedule_limit_reached", "one_shot_spent", "ghost_row", "channel_limit_reached", "webhook_limit_reached", "run_limit_reached", "reembed_required", "run_terminal", "run_not_parked", "stale_token", "run_not_waiting", "event_mismatch"];
63
+ export declare const ADMIN_ERROR_CODES: readonly ["story_contract_v2_write_disabled", "story_contract_v3_write_disabled", "story_contract_v4_write_disabled", "has_pins", "pins_unknown", "story_package_limit", "story_package_documents_limit", "episode_history_incomplete", "episode_ended", "idempotency_key_reused", "stale_deliberation", "deliberation_disabled", "deliberation_uncalibrated", "deliberation_not_enabled", "deliberation_candidates_exceeded", "schedule_limit_reached", "one_shot_spent", "ghost_row", "channel_limit_reached", "webhook_limit_reached", "run_limit_reached", "reembed_required", "run_terminal", "run_not_parked", "stale_token", "run_not_waiting", "event_mismatch", "subscription_exists"];
64
64
  /** `AdminApiError.code` values. The `(string & {})` arm keeps the type open for
65
65
  * codes newer than this SDK build while preserving autocomplete — same
66
66
  * doctrine as the companion SDK's `CompanionErrorCodeValue`. */
@@ -312,6 +312,36 @@ export interface MonthUsage {
312
312
  creditLimit?: number;
313
313
  [k: string]: unknown;
314
314
  }
315
+ /** What the credit gate would do on the NEXT turn of this account. */
316
+ export interface UsageCreditEnforcement {
317
+ /** Whether this deployment has the credit gate switched on at all. While
318
+ * false nothing is refused or downgraded at the ceiling. */
319
+ armed: boolean;
320
+ plan: string;
321
+ /** Computed on the ACCOUNT total, exactly as the gate does. `null` when the
322
+ * pool could not be read — unknown, not `allow`. */
323
+ verdict: 'allow' | 'downgrade' | 'deny' | null;
324
+ /** One line saying what `verdict` does (a paid-plan `downgrade` keeps turns
325
+ * running on `standard`; a free-plan ceiling refuses NEW sessions). */
326
+ effect: string;
327
+ }
328
+ /** The credit meter with both scopes named (admin API 1.14.0+). Read this, not
329
+ * `usage.credits / usage.creditLimit`: that divides THIS project's figure by
330
+ * the ACCOUNT's allowance and understates consumption on any multi-project
331
+ * account. */
332
+ export interface UsageCredits {
333
+ /** THIS project's consumption — the same number `usage.credits` carries. */
334
+ project: number;
335
+ /** The whole ACCOUNT's consumption: the numerator the gate compares to
336
+ * `limit`. `null` means it could not be read — never treat it as zero. */
337
+ account: number | null;
338
+ /** The ACCOUNT allowance (same value as `usage.creditLimit`). */
339
+ limit: number;
340
+ /** Which pool `limit` governs. Credits pool across the owner's projects, so
341
+ * a second project does NOT isolate a workload — a second account does. */
342
+ scope: 'account';
343
+ enforcement: UsageCreditEnforcement;
344
+ }
315
345
  /** One month of the usage-history series. Unlike `MonthUsage` (the current
316
346
  * month's full meter incl. day buckets and the cap), history rows are the
317
347
  * compact per-month rollup the server keeps for every past month. */
@@ -1362,8 +1392,12 @@ export interface AdminClient {
1362
1392
  testWebhook(webhookId: string): Promise<DeliveryOutcome>;
1363
1393
  /** Manually re-send a recorded delivery's original body, re-signed. */
1364
1394
  redeliverWebhook(deliveryId: string): Promise<DeliveryOutcome>;
1395
+ /** Current-month usage. `credits` (admin API 1.14.0+; absent from an older
1396
+ * server) is the block to read for headroom — `account / limit` is the
1397
+ * ratio the gate enforces. */
1365
1398
  getUsage(): Promise<{
1366
1399
  usage: MonthUsage;
1400
+ credits?: UsageCredits;
1367
1401
  }>;
1368
1402
  /** Month-over-month usage series, oldest first; quiet months zero-fill
1369
1403
  * rather than drop. `scope: 'account'` means the pooled account series —
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@
8
8
  // import { createAdminClient } from '@pouchy_ai/admin-sdk';
9
9
  // const admin = createAdminClient({ adminKey: process.env.POUCHY_ADMIN_KEY! });
10
10
  // const { agents } = await admin.listAgents();
11
- export const ADMIN_SDK_VERSION = '0.36.0';
11
+ export const ADMIN_SDK_VERSION = '0.38.0';
12
12
  export const DEFAULT_BASE_URL = 'https://pouchy.ai/v1/admin';
13
13
  /** Default per-request timeout (ms). A hung upstream otherwise never rejects. */
14
14
  const DEFAULT_TIMEOUT_MS = 30_000;
@@ -96,7 +96,11 @@ export const ADMIN_ERROR_CODES = [
96
96
  'run_not_parked',
97
97
  'stale_token',
98
98
  'run_not_waiting',
99
- 'event_mismatch'
99
+ 'event_mismatch',
100
+ // 0.38.0 — checkout on an account that already pays through a live
101
+ // subscription. Recovery: POST /v1/projects/{id}/billing/upgrade, which moves
102
+ // that subscription to the new price instead of opening a second one.
103
+ 'subscription_exists'
100
104
  ];
101
105
  /** Thrown on any non-2xx response AND on a transport failure that never reached
102
106
  * the server (network / DNS / timeout), which carries `status: 0`. `status` is
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pouchy_ai/admin-sdk",
3
- "version": "0.36.0",
3
+ "version": "0.38.0",
4
4
  "description": "Typed TypeScript client for the Pouchy Admin API \u2014 manage agents, keys, end users, knowledge, skills, channels, schedules, webhooks and credentials headlessly, with a project Admin key.",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE",