@pouchy_ai/admin-sdk 0.36.0 → 0.39.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,45 @@
2
2
 
3
3
  All notable changes to `@pouchy_ai/admin-sdk` are documented here.
4
4
 
5
+ ## 0.39.0 — 2026-09-26
6
+
7
+ - **`getUserWallet()` now types the figures, and a failed read throws.**
8
+ Admin API 1.18.0 returns `balances` (`{ currency, amount }[]`, decimal
9
+ strings) and `totalUsd` beside the prose `balance`, typed here as the new
10
+ exported `UserWallet`. Both fields are optional because an older server does
11
+ not send them. Before 1.18.0, a wallet service that could not be read
12
+ answered 200 `{ hasWallet: true, balance: "Could not fetch the wallet balance
13
+ right now." }`, which looked like a balance. The server now answers 503, so
14
+ the call throws an `AdminApiError` with `status: 503`; retry it.
15
+ `balance` is unchanged, so code that displays it keeps working.
16
+
17
+ ## 0.38.0 — 2026-09-25
18
+
19
+ - **`ADMIN_ERROR_CODES` gains `subscription_exists`** (409). `POST
20
+ /v1/projects/{id}/billing/checkout` now refuses when the account already pays
21
+ through a live Stripe subscription. Before, a second checkout opened a SECOND
22
+ subscription: both billed, and each one's lifecycle events rewrote the
23
+ account's plan. Upgrade through `POST /v1/projects/{id}/billing/upgrade`
24
+ instead, which moves the existing subscription to the new price and charges
25
+ the prorated difference. Additive: the `AdminErrorCode` type was
26
+ already open to codes newer than the build.
27
+
28
+ ## 0.37.0 — 2026-09-24
29
+
30
+ - **`getUsage()` now types the `credits` block** the server has returned since
31
+ admin API 1.14.0: `{ project, account, limit, scope: 'account', enforcement:
32
+ { armed, plan, verdict, effect } }` (new exported types `UsageCredits` and
33
+ `UsageCreditEnforcement`). Additive: `usage` is unchanged, and `credits` is
34
+ optional because a server older than 1.14.0 does not send it.
35
+
36
+ `usage.credits / usage.creditLimit` is NOT a headroom ratio — `usage.credits`
37
+ is this project's slice and `creditLimit` is the ACCOUNT's pooled allowance,
38
+ so on a multi-project account it understates consumption. Until now the typed
39
+ client offered only that ratio (reading `res.credits` did not compile), and
40
+ this README's quickstart printed it. Read `credits.account / credits.limit`
41
+ instead; `account` is `null` when the pool could not be read, which means
42
+ unknown, never zero.
43
+
5
44
  ## 0.36.0 — 2026-09-12
6
45
 
7
46
  - **`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
@@ -458,7 +465,7 @@ Reads (`GET`) are not covered by that bucket. `retryAfter` is available from
458
465
  | Agent versions | `listAgentVersions` · `getAgentVersion` · `diffAgentVersions({ from?, to? })` · `rollbackAgent` · `getAgentPromotion` · `promoteAgent` (staging→prod) |
459
466
  | Voices | `listVoices({ gender?, age?, locale? })` — catalog for programmatic voice selection (each `CatalogVoice` carries `age`) |
460
467
  | Secret keys | `listKeys` · `createKey` · `revokeKey` · `rotateKey` (24 h grace) |
461
- | End users | `listUsers({ limit?, cursor? })` (cursor-paginated — the response's `nextCursor` feeds the next page; filter variants: `external_user_id` / `external_user_prefix`) · `setUserSuspended` · `deleteUser` · `getUserWallet` · `getUserTraces` · `importUsers` · `exportUser` · `getUserSessions` · `getUserTurns` |
468
+ | End users | `listUsers({ limit?, cursor? })` (cursor-paginated — the response's `nextCursor` feeds the next page; filter variants: `external_user_id` / `external_user_prefix`) · `setUserSuspended` · `deleteUser` · `getUserWallet` (`balances` / `totalUsd` for the figures; `balance` is prose) · `getUserTraces` · `importUsers` · `exportUser` · `getUserSessions` · `getUserTurns` |
462
469
  | Knowledge | `listKnowledge` · `ingestKnowledge` · `ingestKnowledgeFile` (PDF/audio/video/image) · `ingestKnowledgeUrl` (web page) · `searchKnowledge` (recall probe) · `deleteKnowledge` |
463
470
  | Skills | `listSkills` · `installSkill` · `updateSkill` · `setSkillRate` · `setSkillDailyCap` · `grantSkill` (free-HTTP) · `setSkillAutoRunTools` (免确认工具 — required to arm an MCP skill on an instance) · `compileSkill` (prose→tools) · `uninstallSkill` · `importAgentPlugin` / `exportAgentPlugin` (Agent Plugins 1.0.0 interop) |
464
471
  | Credentials | `listCredentials` · `putCredentials` · `deleteCredentials` |
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.39.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,52 @@ 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
+ /** One end user's wallet, as `getUserWallet` returns it. */
329
+ export interface UserWallet {
330
+ hasWallet: boolean;
331
+ /** Human-readable prose, or null when there is no wallet. NOT a number. */
332
+ balance: string | null;
333
+ /** Nonzero per-currency balances; `amount` is a decimal string such as
334
+ * "5.83", never atomic units. Admin API 1.18.0+, present when
335
+ * `hasWallet` is true. */
336
+ balances?: {
337
+ currency: string;
338
+ amount: string;
339
+ }[];
340
+ /** USD total (the allowed stablecoins are USD-pegged 1:1). Admin API
341
+ * 1.18.0+, present when `hasWallet` is true. */
342
+ totalUsd?: number;
343
+ }
344
+ /** The credit meter with both scopes named (admin API 1.14.0+). Read this, not
345
+ * `usage.credits / usage.creditLimit`: that divides THIS project's figure by
346
+ * the ACCOUNT's allowance and understates consumption on any multi-project
347
+ * account. */
348
+ export interface UsageCredits {
349
+ /** THIS project's consumption — the same number `usage.credits` carries. */
350
+ project: number;
351
+ /** The whole ACCOUNT's consumption: the numerator the gate compares to
352
+ * `limit`. `null` means it could not be read — never treat it as zero. */
353
+ account: number | null;
354
+ /** The ACCOUNT allowance (same value as `usage.creditLimit`). */
355
+ limit: number;
356
+ /** Which pool `limit` governs. Credits pool across the owner's projects, so
357
+ * a second project does NOT isolate a workload — a second account does. */
358
+ scope: 'account';
359
+ enforcement: UsageCreditEnforcement;
360
+ }
315
361
  /** One month of the usage-history series. Unlike `MonthUsage` (the current
316
362
  * month's full meter incl. day buckets and the cap), history rows are the
317
363
  * compact per-month rollup the server keeps for every past month. */
@@ -625,11 +671,10 @@ export interface AdminClient {
625
671
  }>;
626
672
  /** The instance companion's wallet. `balance` is a human-readable prose
627
673
  * string (e.g. "Wallet balance: … (~$X total)."), or null when the instance
628
- * has no wallet — NOT a number, and there is no address field. */
629
- getUserWallet(instanceId: string): Promise<{
630
- hasWallet: boolean;
631
- balance: string | null;
632
- }>;
674
+ * has no wallet — NOT a number, and there is no address field. Read
675
+ * `balances` / `totalUsd` for the figures (admin API 1.18.0; absent from an
676
+ * older server). A wallet service that cannot be read throws a 503. */
677
+ getUserWallet(instanceId: string): Promise<UserWallet>;
633
678
  getUserTraces(instanceId: string): Promise<{
634
679
  traces: unknown[];
635
680
  }>;
@@ -1362,8 +1407,12 @@ export interface AdminClient {
1362
1407
  testWebhook(webhookId: string): Promise<DeliveryOutcome>;
1363
1408
  /** Manually re-send a recorded delivery's original body, re-signed. */
1364
1409
  redeliverWebhook(deliveryId: string): Promise<DeliveryOutcome>;
1410
+ /** Current-month usage. `credits` (admin API 1.14.0+; absent from an older
1411
+ * server) is the block to read for headroom — `account / limit` is the
1412
+ * ratio the gate enforces. */
1365
1413
  getUsage(): Promise<{
1366
1414
  usage: MonthUsage;
1415
+ credits?: UsageCredits;
1367
1416
  }>;
1368
1417
  /** Month-over-month usage series, oldest first; quiet months zero-fill
1369
1418
  * 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.39.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.39.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",