@terminal3/t3n-sdk 2.10.1 → 2.11.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.
@@ -9,6 +9,7 @@ import { type ContractResponseSchema } from "./contract-response";
9
9
  import { SessionId, Did, SessionStatus, AuthInput, HandshakeResult } from "../types";
10
10
  import { KycPollOptions, KycStatus } from "../types/kyc";
11
11
  import { OtpChannel, OtpRequestInput, OtpRequestResult, OtpVerifyInput, OtpVerifyResult, SubmitUserInputArgs, SubmitUserInputResult } from "../types/user";
12
+ import { GetUsageOptions, UsagePage } from "../types/token";
12
13
  /**
13
14
  * Main T3n SDK Client
14
15
  */
@@ -101,6 +102,22 @@ export declare class T3nClient {
101
102
  * optionally validates it with a schema.
102
103
  */
103
104
  execute(payload: unknown): Promise<string>;
105
+ /**
106
+ * Fetch the caller's usage feed — balance plus a bounded slice of
107
+ * recent token-ledger entries (charges, mints, transfers), newest
108
+ * first. T3-TS-030 Phase 1D step A (`token.get-usage`).
109
+ *
110
+ * `limit` defaults to 50 server-side and clamps silently to
111
+ * `1..=200`. `afterSeq` is the inclusive upper-bound `seq_no`
112
+ * passed back from a previous page's `next_cursor` to walk older
113
+ * entries. `kinds` filters by `TokenTxKind`; an empty array is
114
+ * treated as "no filter".
115
+ *
116
+ * Unlike {@link execute}, the body of this RPC is plaintext —
117
+ * `token.get-usage` is a session-authed read endpoint and the
118
+ * server-side handler does not run the encryption layer.
119
+ */
120
+ getUsage(opts?: GetUsageOptions): Promise<UsagePage>;
104
121
  /**
105
122
  * Execute an action with an attached binary blob using multipart RPC.
106
123
  */
@@ -445,6 +462,41 @@ export declare class T3nClient {
445
462
  * Send an RPC request with automatic encryption/decryption
446
463
  */
447
464
  private sendRpcRequest;
465
+ /**
466
+ * Send a session-authenticated JSON-RPC request with plaintext
467
+ * params/result (no SessionEncryption layer). Used for tenant-facing
468
+ * read endpoints (`token.get-balance`, `token.get-usage`) where the
469
+ * server-side handler reads the JSON envelope directly.
470
+ *
471
+ * Auto-attaches the `Session-Id` header; surfaces JSON-RPC errors
472
+ * the same way as {@link sendRpcRequest} (typed
473
+ * `InsufficientCreditError` when applicable, `RpcError` otherwise).
474
+ * Returns the parsed `result` field — typically a JSON object the
475
+ * caller will narrow to the endpoint's response type.
476
+ */
477
+ private sendUnencryptedSessionRpc;
478
+ /**
479
+ * Inspect a JSON-RPC response for an `error` field and throw the
480
+ * appropriate typed exception. No-op when `response.error` is
481
+ * absent. Shared by every RPC path so wire-shape changes in the
482
+ * server's error envelope (typed-error subclasses, request-id
483
+ * placement, detail formatting) only need to land in one place.
484
+ *
485
+ * JSON-RPC `error.message` is the generic category string
486
+ * ("Invalid params", "Internal error", …). The node attaches the
487
+ * actionable text and per-request correlation id in `error.data`
488
+ * — see `node/api/src/responses/rpc.rs::from_service_error`.
489
+ * Extract both so callers (and toasts that only render `.message`)
490
+ * get the real reason plus an id an operator can grep in
491
+ * `api::error` logs.
492
+ *
493
+ * T3-TS-030 chargepoint denials surface as a typed
494
+ * `InsufficientCreditError` so frontends can branch on
495
+ * `instanceof` to render an "out of credit" UI without
496
+ * prefix-matching the message themselves. Wire format is pinned
497
+ * by `api/src/error.rs::service_insufficient_credit_wire_format_is_stable`.
498
+ */
499
+ private throwIfRpcError;
448
500
  private sendMultipartRpcRequest;
449
501
  /**
450
502
  * Capture the server-minted `Session-Id` from the last handshake
@@ -38,7 +38,9 @@ export interface Transport {
38
38
  */
39
39
  send(request: JsonRpcRequest, headers: Record<string, string>): Promise<JsonRpcResponse>;
40
40
  /**
41
- * Optionally send a JSON-RPC request with an attached binary blob.
41
+ * Send a JSON-RPC request with an attached binary blob (multipart/form-data).
42
+ * Part 1 (name=jsonrpc): JSON-RPC envelope.
43
+ * Part 2 (name=blob): raw binary bytes (e.g. WASM bytecode).
42
44
  */
43
45
  sendMultipart?(request: JsonRpcRequest, headers: Record<string, string>, blob: Blob): Promise<JsonRpcResponse>;
44
46
  /**
@@ -42,3 +42,4 @@ export * from "./session";
42
42
  export * from "./auth";
43
43
  export * from "./user";
44
44
  export * from "./org-data";
45
+ export * from "./token";
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Token-metering types — T3-TS-030 wire shapes.
3
+ *
4
+ * Mirrors `node/primitives/src/token.rs`. `u128` fields land on the
5
+ * wire as JSON numbers (same convention as the existing
6
+ * `token.get-balance` response) — JS clients with histories that
7
+ * exceed 2⁵³ tokens should switch to a streaming JSON parser; the
8
+ * common case fits in `number` losslessly.
9
+ */
10
+ /**
11
+ * `primitives::token::BalanceRow` — caller's credit row.
12
+ *
13
+ * `available` and `reserved` are `u128` on the server; the wire
14
+ * format is a JSON number. Callers should not assume bigint until
15
+ * the SDK migrates to a streaming parser (tracked separately).
16
+ */
17
+ export interface BalanceRow {
18
+ available: number;
19
+ reserved: number;
20
+ last_settled_seq_no: number;
21
+ version: number;
22
+ credit_exhausted: boolean;
23
+ }
24
+ /**
25
+ * `primitives::token::TokenTxKind` snake_case wire alphabet. Every
26
+ * value listed here is accepted by the server-side
27
+ * `token.get-usage` `kinds` filter.
28
+ */
29
+ export type TokenTxKind = "mint" | "burn" | "charge" | "transfer" | "bridge_mint_attest" | "bridge_burn_attest";
30
+ /**
31
+ * Per-caller view direction. `"in"` = caller's balance went up;
32
+ * `"out"` = caller's balance went down. Derived host-side from
33
+ * `(caller_did, tx.src, tx.dst)`; the same `seq_no` appears in both
34
+ * parties' usage feeds with opposite directions on a transfer.
35
+ */
36
+ export type Direction = "in" | "out";
37
+ /**
38
+ * Discriminated union mirroring `primitives::token::ChargeReason`.
39
+ * Present only when the row's `kind === "charge"`.
40
+ */
41
+ export type ChargeReason = {
42
+ kind: "contract_register";
43
+ script_name: string;
44
+ version: string;
45
+ } | {
46
+ kind: "invocation";
47
+ script_name: string;
48
+ function: string;
49
+ fuel_consumed: number;
50
+ fuel_tokens: number;
51
+ host_call_count: number;
52
+ host_call_tokens: number;
53
+ } | {
54
+ kind: "kv_bytes";
55
+ map: string;
56
+ } | {
57
+ kind: "cas_bytes";
58
+ backend: string;
59
+ } | {
60
+ kind: "outbox_egress";
61
+ upstream: string;
62
+ };
63
+ /**
64
+ * One row in the caller's usage feed — a per-caller projection of
65
+ * the underlying `TokenTx`. `counterparty` is the other party from
66
+ * the caller's perspective: `tx.dst` on outbound entries, `tx.src`
67
+ * on inbound. `null` when the underlying tx has no counterparty
68
+ * (mints have no `src`; burns and charges have no `dst`).
69
+ */
70
+ export interface UsageEntry {
71
+ seq_no: number;
72
+ kind: TokenTxKind;
73
+ amount: number;
74
+ timestamp_ms: number;
75
+ direction: Direction;
76
+ counterparty?: string | null;
77
+ reason?: ChargeReason | null;
78
+ note?: string | null;
79
+ }
80
+ /**
81
+ * Response shape of `token.get-usage` — caller's balance plus a
82
+ * paginated slice of their most-recent `token:tx_log` entries.
83
+ *
84
+ * `next_cursor` is the inclusive upper-bound `seq_no` to pass back
85
+ * as `after_seq` to fetch the next page. `null` (or absent) means
86
+ * the caller's history is fully drained.
87
+ */
88
+ export interface UsagePage {
89
+ balance: BalanceRow;
90
+ entries: UsageEntry[];
91
+ next_cursor?: number | null;
92
+ }
93
+ /**
94
+ * Request shape — all fields optional. `limit` clamps to
95
+ * `1..=200` server-side; out-of-range values snap silently to the
96
+ * bounds. `kinds: []` is treated as "no filter".
97
+ */
98
+ export interface GetUsageOptions {
99
+ limit?: number;
100
+ after_seq?: number;
101
+ kinds?: TokenTxKind[];
102
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@terminal3/t3n-sdk",
3
- "version": "2.10.1",
3
+ "version": "2.11.0",
4
4
  "type": "module",
5
5
  "description": "T3n TypeScript SDK - A minimal SDK that mirrors the server's RPC handler approach",
6
6
  "main": "dist/index.js",
@@ -41,6 +41,10 @@
41
41
  "demo": "pnpm build && tsx demo.ts",
42
42
  "demo:dev": "tsx demo.ts",
43
43
  "demo:real-wasm": "tsx demo.ts",
44
+ "demo:tenant:admit": "tsx --tsconfig tsconfig.demo.json tenant-demo.ts --cmd admit",
45
+ "demo:tenant:setup": "tsx --tsconfig tsconfig.demo.json tenant-demo.ts --cmd setup",
46
+ "demo:tenant:search": "tsx --tsconfig tsconfig.demo.json tenant-demo.ts --cmd search",
47
+ "demo:tenant:book": "tsx --tsconfig tsconfig.demo.json tenant-demo.ts --cmd book",
44
48
  "verify:pack": "node scripts/verify-pack.js",
45
49
  "prepublishOnly": "pnpm run build:public && pnpm run verify:pack",
46
50
  "release": "node scripts/release.js release",