@terminal3/t3n-sdk 2.7.0 → 2.10.1

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.
@@ -4,7 +4,7 @@
4
4
  * Creates the initial action payloads for WASM state machines.
5
5
  * These are JSON-serialized and passed to the WASM component to start flows.
6
6
  */
7
- import { AuthInput } from "../types";
7
+ import type { AuthInput } from "../types";
8
8
  /**
9
9
  * Create the initial handshake request
10
10
  * This kicks off the handshake state machine in WASM
@@ -85,12 +85,41 @@ export interface PayrollRunRequest {
85
85
  batch_cap_cents: bigint;
86
86
  /** `employee_id` → previous-cycle baseline net disbursement, cents (decimal string). */
87
87
  historical_baselines: Record<string, string>;
88
+ /**
89
+ * Per-employee disbursement flag threshold, in cents. Mirrors
90
+ * `PayrollRunRequest::individual_disbursement_threshold_cents` on the Rust
91
+ * side. When absent the Rust contract applies its own default (SGD 15,000;
92
+ * `DEFAULT_INDIVIDUAL_THRESHOLD_CENTS`). When present, the value is
93
+ * included in the wire shape and participates in the request hash.
94
+ */
95
+ individual_disbursement_threshold_cents?: bigint;
88
96
  }
89
- /** Convenience wrapper paired with the matching delegation envelope. */
90
- export interface PayrollInvocation {
97
+ /** Default for `individual_disbursement_threshold_cents` SGD 15,000. */
98
+ export declare const DEFAULT_INDIVIDUAL_THRESHOLD_CENTS = 1500000n;
99
+ /** Delegated invocation: the agent acts on behalf of a user. */
100
+ export interface PayrollInvocationDelegated {
91
101
  envelope: DelegationEnvelope;
92
102
  request: PayrollRunRequest;
93
103
  }
104
+ /**
105
+ * Direct invocation: the agent acts on its own behalf. No delegation
106
+ * envelope is included. The principal DID is resolved by the service layer
107
+ * from `DynamicContext.authenticated_did`; authorisation falls through to
108
+ * `OrgContractGrants[org || "tee:payroll"]` for the agent's own DID.
109
+ *
110
+ * Wire shape is `{ request }` — no `envelope` field and no
111
+ * `authenticated_did` field. The contract's entry-point handler injects
112
+ * `authenticated_did` from `GenericInput.context` before calling `verify`.
113
+ */
114
+ export interface PayrollInvocationDirect {
115
+ request: PayrollRunRequest;
116
+ }
117
+ /**
118
+ * Union of the two invocation variants. The serde-untagged enum on the
119
+ * contract side disambiguates by presence of `envelope` — delegated calls
120
+ * carry `{ envelope, request }`, direct calls carry `{ request }` only.
121
+ */
122
+ export type PayrollInvocation = PayrollInvocationDelegated | PayrollInvocationDirect;
94
123
  /** Response from `tee:delegation.sign`. */
95
124
  export interface SignDelegationResponse {
96
125
  credential_jcs: Uint8Array;
@@ -264,10 +293,33 @@ export interface BuildPayrollInvocationOpts {
264
293
  agentSecret: Uint8Array;
265
294
  }
266
295
  /**
267
- * Assemble a complete {@link PayrollInvocation} (envelope + request)
268
- * given a user-signed credential and a per-call agent secret. Computes
269
- * `request_hash` from the canonical request bytes and produces an
296
+ * Assemble a delegated {@link PayrollInvocationDelegated} (envelope +
297
+ * request) given a user-signed credential and a per-call agent secret.
298
+ * Computes `request_hash` from the canonical request bytes and produces an
270
299
  * `agent_sig` over `sha256(invocation_preimage)`.
300
+ *
301
+ * When `request.individual_disbursement_threshold_cents` is undefined this
302
+ * function fills in {@link DEFAULT_INDIVIDUAL_THRESHOLD_CENTS} before
303
+ * hashing so the SDK's hash matches the Rust contract's hash (the contract
304
+ * applies the same default via `#[serde(default)]`).
305
+ */
306
+ export declare function buildPayrollInvocation(opts: BuildPayrollInvocationOpts): PayrollInvocationDelegated;
307
+ /** Options for {@link buildPayrollDirectInvocation}. */
308
+ export interface BuildPayrollDirectInvocationOpts {
309
+ request: PayrollRunRequest;
310
+ }
311
+ /**
312
+ * Assemble a direct {@link PayrollInvocationDirect} — no delegation
313
+ * envelope. The caller supplies only the request body; the contract
314
+ * entry-point resolves the principal DID from
315
+ * `DynamicContext.authenticated_did` at runtime.
316
+ *
317
+ * Callers in direct mode must hold a grant in
318
+ * `OrgContractGrants[org || "tee:payroll"]` under their own DID.
319
+ *
320
+ * When `request.individual_disbursement_threshold_cents` is undefined this
321
+ * function fills in {@link DEFAULT_INDIVIDUAL_THRESHOLD_CENTS} so the wire
322
+ * shape matches the Rust contract's `#[serde(default)]` canonicalisation.
271
323
  */
272
- export declare function buildPayrollInvocation(opts: BuildPayrollInvocationOpts): PayrollInvocation;
324
+ export declare function buildPayrollDirectInvocation(opts: BuildPayrollDirectInvocationOpts): PayrollInvocationDirect;
273
325
  export {};
@@ -19,7 +19,6 @@ import { T3nClient } from "./t3n-client";
19
19
  import type { WasmComponent } from "../wasm";
20
20
  import { type GuestToHostHandlers } from "../types";
21
21
  import type { OrgContractGrants, OrgPolicyMeta, OrgWriters, DataListResponse, DataGetResponse, MutationResponse, UserGrant } from "../types/org-data";
22
- declare function executeOrgDataAction(client: T3nClient, baseUrl: string, functionName: string, args: Record<string, unknown>): Promise<unknown>;
23
22
  export interface CreatePolicyInput {
24
23
  orgDid: string;
25
24
  initialAdminDid: string;
@@ -192,4 +191,79 @@ export declare class OrgDataClient {
192
191
  /** Retrieve a single data entry by entry ID (admin-only). */
193
192
  dataGet(input: DataGetInput): Promise<DataGetResponse>;
194
193
  }
195
- export { executeOrgDataAction };
194
+ /**
195
+ * Session-authenticated variant of {@link OrgDataClient}.
196
+ *
197
+ * Where `OrgDataClient` owns its own ETH-secret-driven session lifecycle,
198
+ * `SessionOrgDataClient` accepts a caller-owned {@link T3nClient}. The
199
+ * caller is responsible for completing `handshake()` and `authenticate()`
200
+ * on that client (e.g. via the SIWE flow used by the orgs admin UI)
201
+ * BEFORE invoking any method on this class — the constructor performs no
202
+ * auth lifecycle of its own.
203
+ *
204
+ * Dispatches through `action.execute` against `tee:org-data/contracts`,
205
+ * relying on the caller-owned `T3nClient` for the preceding
206
+ * `auth.handshake` / `auth.authenticate` steps, so callers get the
207
+ * identical method surface as `OrgDataClient` without needing a raw ETH
208
+ * secret key.
209
+ *
210
+ * The runtime guard only catches the no-handshake case
211
+ * (`t3n.getSessionId()` returns `null`); a client that has handshaken but
212
+ * not authenticated will pass the guard and instead fail later with an
213
+ * `RpcError` from `action.execute`. Authorisation is similarly the
214
+ * caller's responsibility — the contract will refuse calls that aren't
215
+ * backed by a recognised admin / writer DID, surfaced as the usual
216
+ * `'CODE: detail'` refusal string.
217
+ */
218
+ export declare class SessionOrgDataClient {
219
+ private readonly t3n;
220
+ private readonly baseUrl;
221
+ /**
222
+ * @param t3n - a `T3nClient` that the caller has already driven through
223
+ * `handshake()` and `authenticate()`. The constructor does not verify
224
+ * this; the runtime guard on each method only catches the
225
+ * no-handshake case (`getSessionId()` returns `null`). A
226
+ * handshake-only-no-authenticate client will fail later with an
227
+ * `RpcError` from `action.execute`.
228
+ * @param baseUrl - node base URL (trailing slashes stripped). Mirrors
229
+ * `OrgDataClient`'s signature for ergonomic parity; used only for the
230
+ * `tee:org-data/contracts` version lookup and should match the node
231
+ * the supplied `t3n` is bound to.
232
+ */
233
+ constructor(t3n: T3nClient, baseUrl: string);
234
+ private call;
235
+ /** Mirrors {@link OrgDataClient.createPolicy}. */
236
+ createPolicy(input: CreatePolicyInput): Promise<MutationResponse>;
237
+ /** Mirrors {@link OrgDataClient.updateMeta}. */
238
+ updateMeta(input: UpdateMetaInput): Promise<MutationResponse>;
239
+ /** Mirrors {@link OrgDataClient.setWriters}. */
240
+ setWriters(input: SetWritersInput): Promise<MutationResponse>;
241
+ /** Mirrors {@link OrgDataClient.setGrants}. */
242
+ setGrants(input: SetGrantsInput): Promise<MutationResponse>;
243
+ /** Mirrors {@link OrgDataClient.deleteGrants}. */
244
+ deleteGrants(input: DeleteGrantsInput): Promise<MutationResponse>;
245
+ /** Mirrors {@link OrgDataClient.writeData}. */
246
+ writeData(input: WriteDataInput): Promise<MutationResponse>;
247
+ /** Mirrors {@link OrgDataClient.deleteData}. */
248
+ deleteData(input: DeleteDataInput): Promise<MutationResponse>;
249
+ /** Mirrors {@link OrgDataClient.deleteScope}. */
250
+ deleteScope(input: DeleteScopeInput): Promise<MutationResponse>;
251
+ /** Mirrors {@link OrgDataClient.policyGet}. */
252
+ policyGet(input: PolicyGetInput): Promise<OrgPolicyMeta>;
253
+ /** Mirrors {@link OrgDataClient.writersGet}. */
254
+ writersGet(input: WritersGetInput): Promise<OrgWriters>;
255
+ /** Mirrors {@link OrgDataClient.grantsGet}. */
256
+ grantsGet(input: GrantsGetInput): Promise<OrgContractGrants>;
257
+ /** Mirrors {@link OrgDataClient.dataList}. */
258
+ dataList(input: DataListInput): Promise<DataListResponse>;
259
+ /** Mirrors {@link OrgDataClient.dataGet}. */
260
+ dataGet(input: DataGetInput): Promise<DataGetResponse>;
261
+ }
262
+ /**
263
+ * Construct a {@link SessionOrgDataClient} from a caller-owned
264
+ * {@link T3nClient} that has already been driven through `handshake()`
265
+ * and `authenticate()`. Thin convenience wrapper — equivalent to
266
+ * `new SessionOrgDataClient(t3n, baseUrl)`. See `SessionOrgDataClient`
267
+ * for the full precondition contract and the runtime guard's limits.
268
+ */
269
+ export declare function createOrgDataClientFromSession(t3n: T3nClient, baseUrl: string): SessionOrgDataClient;
@@ -101,6 +101,10 @@ export declare class T3nClient {
101
101
  * optionally validates it with a schema.
102
102
  */
103
103
  execute(payload: unknown): Promise<string>;
104
+ /**
105
+ * Execute an action with an attached binary blob using multipart RPC.
106
+ */
107
+ executeWithBlob(payload: unknown, blob: Blob): Promise<string>;
104
108
  /**
105
109
  * Execute an action and JSON-decode the response.
106
110
  *
@@ -441,6 +445,7 @@ export declare class T3nClient {
441
445
  * Send an RPC request with automatic encryption/decryption
442
446
  */
443
447
  private sendRpcRequest;
448
+ private sendMultipartRpcRequest;
444
449
  /**
445
450
  * Capture the server-minted `Session-Id` from the last handshake
446
451
  * response headers (pentest M-1 / MAT-983). Validates shape so a
@@ -37,6 +37,10 @@ export interface Transport {
37
37
  * @returns Promise that resolves to the JSON-RPC response
38
38
  */
39
39
  send(request: JsonRpcRequest, headers: Record<string, string>): Promise<JsonRpcResponse>;
40
+ /**
41
+ * Optionally send a JSON-RPC request with an attached binary blob.
42
+ */
43
+ sendMultipart?(request: JsonRpcRequest, headers: Record<string, string>, blob: Blob): Promise<JsonRpcResponse>;
40
44
  /**
41
45
  * Optional accessor for the latest Set-Cookie header value.
42
46
  * (Useful in Node.js demos/tests; browsers block HttpOnly cookies.)
@@ -59,6 +63,7 @@ export declare class HttpTransport implements Transport {
59
63
  getLastSetCookie(): string | null;
60
64
  getLastResponseHeaders(): Record<string, string>;
61
65
  send(request: JsonRpcRequest, headers: Record<string, string>): Promise<JsonRpcResponse>;
66
+ sendMultipart(request: JsonRpcRequest, headers: Record<string, string>, blob: Blob): Promise<JsonRpcResponse>;
62
67
  }
63
68
  /**
64
69
  * Mock transport for testing
@@ -79,6 +84,7 @@ export declare class MockTransport implements Transport {
79
84
  private responseHeaders;
80
85
  private lastResponseHeaders;
81
86
  private requests;
87
+ private multipartRequests;
82
88
  /**
83
89
  * Mock a response for a specific method
84
90
  */
@@ -109,9 +115,15 @@ export declare class MockTransport implements Transport {
109
115
  request: JsonRpcRequest;
110
116
  headers: Record<string, string>;
111
117
  }>;
118
+ getMultipartRequests(): Array<{
119
+ request: JsonRpcRequest;
120
+ headers: Record<string, string>;
121
+ blob: Blob;
122
+ }>;
112
123
  /**
113
124
  * Clear all recorded requests
114
125
  */
115
126
  clearRequests(): void;
127
+ sendMultipart(request: JsonRpcRequest, headers: Record<string, string>, blob: Blob): Promise<JsonRpcResponse>;
116
128
  send(request: JsonRpcRequest, headers: Record<string, string>): Promise<JsonRpcResponse>;
117
129
  }
@@ -20,17 +20,19 @@ export type { KycStatus, KycStatusKind, KycPollOptions, KycPollCadence, } from "
20
20
  export { DEFAULT_KYC_POLL_CADENCE, TERMINAL_KYC_STATUSES, KycStatusTimeoutError, } from "./types/kyc";
21
21
  export type { OtpChannel, OtpRequestInput, OtpRequestResult, OtpVerifyInput, OtpVerifyResult, OtpMergeSuggestion, UserInputProfile, SubmitUserInputArgs, SubmitUserInputResult, UserUpsertErrorKind, } from "./types/user";
22
22
  export { UserUpsertError } from "./types/user";
23
- export { OrgDataClient } from "./client/org-data";
23
+ export { OrgDataClient, SessionOrgDataClient, createOrgDataClientFromSession, } from "./client/org-data";
24
24
  export type { OrgDataClientOptions, CreatePolicyInput, UpdateMetaInput, SetWritersInput, SetGrantsInput, DeleteGrantsInput, WriteDataInput, DeleteDataInput, DeleteScopeInput, PolicyGetInput, WritersGetInput, GrantsGetInput, DataListInput, DataGetInput, ExecuteOrgDataActionOptions, } from "./client/org-data";
25
25
  export type { OrgDataActionWire, OrgPolicyMeta, OrgWriters, OrgContractGrants, UserGrant, EmployeeRecord, EmploymentStatus, ResidencyCategory, AgeBand, ExpenseClaim, MutationResponse, DataListResponse, DataGetResponse, } from "./types/org-data";
26
26
  export { DelegationCustodialClient } from "./client/delegation";
27
27
  export type { DelegationCustodialClientOpts, SignCustodialResult, } from "./client/delegation";
28
- export { DELEGATION_CREDENTIAL_DOMAIN, DELEGATION_INVOCATION_DOMAIN, VC_ID_LEN, NONCE_LEN, REQUEST_HASH_LEN, AGENT_PUBKEY_LEN, ETH_SIG_LEN, buildDelegationCredential, validateCredentialBody, canonicaliseCredential, canonicaliseRequest, requestHash, buildInvocationPreimage, eip191Digest, signCredential, ethRecoverEip191, signAgentInvocation, buildPayrollInvocation, compactDidFromBytes, b64uEncodeBytes, b64uDecodeStrict, _b64uEncode, } from "./client/delegation";
29
- export type { DelegationCredential, DelegationEnvelope, PayrollRunRequest, PayrollInvocation, SignDelegationResponse, BuildDelegationCredentialOpts, BuildPayrollInvocationOpts, } from "./client/delegation";
28
+ export { DELEGATION_CREDENTIAL_DOMAIN, DELEGATION_INVOCATION_DOMAIN, VC_ID_LEN, NONCE_LEN, REQUEST_HASH_LEN, AGENT_PUBKEY_LEN, ETH_SIG_LEN, DEFAULT_INDIVIDUAL_THRESHOLD_CENTS, buildDelegationCredential, validateCredentialBody, canonicaliseCredential, canonicaliseRequest, requestHash, buildInvocationPreimage, eip191Digest, signCredential, ethRecoverEip191, signAgentInvocation, buildPayrollInvocation, buildPayrollDirectInvocation, compactDidFromBytes, b64uEncodeBytes, b64uDecodeStrict, _b64uEncode, } from "./client/delegation";
29
+ export type { DelegationCredential, DelegationEnvelope, PayrollRunRequest, PayrollInvocationDelegated, PayrollInvocationDirect, PayrollInvocation, SignDelegationResponse, BuildDelegationCredentialOpts, BuildPayrollInvocationOpts, BuildPayrollDirectInvocationOpts, } from "./client/delegation";
30
30
  export { metamask_sign, metamask_get_address, eth_get_address, createDefaultHandlers, createMlKemPublicKeyHandler, createRandomHandler, } from "./client/handlers";
31
31
  export type { WasmComponent, ClientHandshake, ClientAuth, SessionCrypto, WasmNextResult, } from "./wasm";
32
32
  export { loadWasmComponent } from "./wasm";
33
33
  export { generateRandomString, generateUUID, getScriptVersion, stringToBytes, bytesToString, redactSecrets, redactSecretsFromJson, } from "./utils";
34
- export { T3nError, SessionStateError, AuthenticationError, HandshakeError, RpcError, WasmError, decodeWasmErrorMessage, extractWasmError, } from "./utils/errors";
34
+ export { T3nError, SessionStateError, AuthenticationError, HandshakeError, RpcError, SessionExpiredError, WasmError, decodeWasmErrorMessage, extractWasmError, } from "./utils/errors";
35
+ export { assertShape, isObject } from "./utils/shape";
36
+ export { isMutationResponse, isOrgPolicyMeta, isOrgWriters, isOrgContractGrants, isDataListResponse, isDataGetResponse, } from "./types/org-data";
35
37
  export type { SdkConfig, Environment, ConfigValidationResult, DkgAttestation, QuoteVerifyResult, DkgVerifyResult, PeerQuoteResult, } from "./config";
36
38
  export { loadConfig, fetchMlKemPublicKey, fetchDkgAttestation, verifyTdxQuote, verifyDkgAttestation, clearKeyCache, getEnvironmentName, getEnvironment, setEnvironment, setNodeUrl, getNodeUrl, NODE_URLS, validateConfig, } from "./config";
@@ -33,12 +33,19 @@ export interface OidcCredentials {
33
33
  interface BaseAuthInput {
34
34
  method: AuthMethod;
35
35
  }
36
+ /**
37
+ * Ethereum authentication options
38
+ */
39
+ export interface EthAuthOptions {
40
+ ethDerived?: boolean;
41
+ }
36
42
  /**
37
43
  * Ethereum authentication input
38
44
  */
39
45
  export interface EthAuthInput extends BaseAuthInput {
40
46
  method: AuthMethod.Ethereum;
41
47
  address: string;
48
+ ethDerived?: boolean;
42
49
  }
43
50
  /**
44
51
  * OIDC authentication input
@@ -54,6 +61,6 @@ export type AuthInput = EthAuthInput | OidcAuthInput;
54
61
  /**
55
62
  * Helper functions to create auth inputs
56
63
  */
57
- export declare function createEthAuthInput(address: string): EthAuthInput;
64
+ export declare function createEthAuthInput(address: string, options?: EthAuthOptions): EthAuthInput;
58
65
  export declare function createOidcAuthInput(credentials: OidcCredentials): OidcAuthInput;
59
66
  export {};
@@ -5,6 +5,13 @@
5
5
  * Plain TypeScript interfaces (no zod) — the SDK does not use a
6
6
  * validation library for domain types; see the existing `types/` files.
7
7
  *
8
+ * Each response type below is paired with a shallow runtime predicate
9
+ * (`isMutationResponse`, `isOrgPolicyMeta`, etc.) so the org-data client
10
+ * can `assertShape` the decoded payload before returning to callers.
11
+ * Predicates check the top-level structure only; nested elements
12
+ * (e.g. each `UserGrant` inside `OrgContractGrants.grants`) are not
13
+ * deeply validated — see `utils/shape.ts` for the rationale.
14
+ *
8
15
  * Reference: `org-data-types/src/lib.rs` and
9
16
  * `tee-contract-org-data/src/org_data.rs`.
10
17
  */
@@ -43,6 +50,8 @@ export interface OrgPolicyMeta {
43
50
  /** Unix timestamp (secs) of the most recent policy update. */
44
51
  updated_at_secs: number;
45
52
  }
53
+ /** Shallow runtime guard for {@link OrgPolicyMeta}. */
54
+ export declare function isOrgPolicyMeta(value: unknown): value is OrgPolicyMeta;
46
55
  export type EmploymentStatus = "Active" | "Terminated";
47
56
  /** Singapore CPF residency categories. */
48
57
  export type ResidencyCategory = "Citizen" | "Pr1" | "Pr2" | "PrThreePlus" | "Foreigner";
@@ -94,6 +103,15 @@ export interface MutationResponse {
94
103
  deleted_entries?: number;
95
104
  tx_hash: string | null;
96
105
  }
106
+ /**
107
+ * Shallow runtime guard for {@link MutationResponse}.
108
+ *
109
+ * Only the always-present fields are checked — `status` is mandatory on
110
+ * every mutation; `tx_hash` is non-optional but nullable. The optional
111
+ * fields (`entry_id`, `deleted`, `deleted_entries`) are not validated
112
+ * because their presence depends on which mutation ran.
113
+ */
114
+ export declare function isMutationResponse(value: unknown): value is MutationResponse;
97
115
  /**
98
116
  * Response type alias for org-writers-get.
99
117
  *
@@ -103,6 +121,8 @@ export interface MutationResponse {
103
121
  export interface OrgWriters {
104
122
  writers: string[];
105
123
  }
124
+ /** Shallow runtime guard for {@link OrgWriters}. */
125
+ export declare function isOrgWriters(value: unknown): value is OrgWriters;
106
126
  /**
107
127
  * Response type alias for org-grants-get.
108
128
  *
@@ -112,6 +132,15 @@ export interface OrgContractGrants {
112
132
  contract_id: string;
113
133
  grants: UserGrant[];
114
134
  }
135
+ /**
136
+ * Shallow runtime guard for {@link OrgContractGrants}.
137
+ *
138
+ * Validates the immediate envelope (`contract_id: string`, `grants:
139
+ * array`) without recursing into each `UserGrant`. The Rust contract
140
+ * is the source of truth for grant element shape; widening the predicate
141
+ * here would create maintenance churn against benign field additions.
142
+ */
143
+ export declare function isOrgContractGrants(value: unknown): value is OrgContractGrants;
115
144
  /** Response for `org-data-list`. */
116
145
  export interface DataListResponse {
117
146
  /** Hex-encoded entry IDs for this page. */
@@ -121,12 +150,16 @@ export interface DataListResponse {
121
150
  /** Total number of entries in the scope (across all pages). */
122
151
  total: number;
123
152
  }
153
+ /** Shallow runtime guard for {@link DataListResponse}. */
154
+ export declare function isDataListResponse(value: unknown): value is DataListResponse;
124
155
  /** Response for `org-data-get`. */
125
156
  export interface DataGetResponse {
126
157
  entry_id: string;
127
158
  /** Hex-encoded raw payload bytes. */
128
159
  payload_hex: string;
129
160
  }
161
+ /** Shallow runtime guard for {@link DataGetResponse}. */
162
+ export declare function isDataGetResponse(value: unknown): value is DataGetResponse;
130
163
  /**
131
164
  * Legacy direct-route org-data envelope shape retained for compatibility.
132
165
  *
@@ -28,6 +28,27 @@ export declare class AuthenticationError extends T3nError {
28
28
  export declare class HandshakeError extends T3nError {
29
29
  constructor(message: string);
30
30
  }
31
+ /**
32
+ * Error thrown when a session-authenticated SDK client detects that the
33
+ * caller-owned session is no longer usable and the caller must
34
+ * re-authenticate before the call can succeed.
35
+ *
36
+ * Unlike {@link OrgDataClient} (which owns its ETH-secret-driven session
37
+ * and silently rebuilds it on expiry), {@link SessionOrgDataClient} is
38
+ * handed a caller-owned `T3nClient` whose session is bound to an
39
+ * interactive flow (typically SIWE). The SDK can't re-authenticate
40
+ * non-interactively, so on the same wire patterns that the
41
+ * self-owned client recovers from, the session-bound client translates
42
+ * the underlying error into this class and rethrows. The original error
43
+ * is preserved on the native ES2022 `cause` property.
44
+ *
45
+ * Callers branch on `instanceof SessionExpiredError` to route the user
46
+ * to a re-auth UX (e.g. SIWE modal / login redirect) rather than
47
+ * parsing the message of a raw {@link RpcError}.
48
+ */
49
+ export declare class SessionExpiredError extends T3nError {
50
+ constructor(cause: unknown);
51
+ }
31
52
  /**
32
53
  * Error thrown during RPC communication.
33
54
  *
@@ -7,3 +7,4 @@ export * from "./errors";
7
7
  export * from "./logger";
8
8
  export * from "./redaction";
9
9
  export * from "./session";
10
+ export * from "./shape";
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Runtime shape guards for SDK response decoding.
3
+ *
4
+ * The contract layer is the source of truth for response shapes, but the
5
+ * SDK's typed wrappers (`result as T`) are pure compile-time casts that
6
+ * silently accept anything if a contract drifts or returns an unexpected
7
+ * payload past the heuristic refusal-string check. `assertShape` lets the
8
+ * outermost SDK boundary throw a deterministic, named error at the call
9
+ * site rather than letting callers reach for `.admins` on `undefined`
10
+ * deep in their own code.
11
+ *
12
+ * Predicates are intentionally shallow — they validate the immediate
13
+ * top-level structure (object kind, presence/type of leading fields)
14
+ * but do not deeply validate nested elements (e.g. each `UserGrant`
15
+ * inside `OrgContractGrants.grants`). Deep validation would be brittle
16
+ * against benign contract additions; shallow guards catch the failure
17
+ * modes that actually surface as runtime crashes (null/string/missing
18
+ * top-level field).
19
+ */
20
+ /** Narrowing helper: value is a non-null object record. */
21
+ export declare function isObject(value: unknown): value is Record<string, unknown>;
22
+ /**
23
+ * Run a type-predicate guard against `value` and throw a named error if
24
+ * it fails. Returns the value typed as `T` on success.
25
+ *
26
+ * @param where - call-site identifier included in the thrown error
27
+ * message (e.g. `'org-policy-get'`) so operators can grep logs back
28
+ * to the offending RPC.
29
+ */
30
+ export declare function assertShape<T>(value: unknown, guard: (v: unknown) => v is T, where: string): T;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@terminal3/t3n-sdk",
3
- "version": "2.7.0",
3
+ "version": "2.10.1",
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",