@bandeira-tech/b3nd-web 0.2.7 → 0.3.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.
@@ -3,6 +3,59 @@
3
3
  *
4
4
  * Type definitions for the B3nd Wallet Client that interacts with wallet servers.
5
5
  */
6
+ /**
7
+ * Common interface for wallet clients (WalletClient and MemoryWalletClient)
8
+ *
9
+ * Implement this interface to create custom wallet clients or use
10
+ * for dependency injection in tests.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * function setupApp(wallet: WalletClientInterface) {
15
+ * // Works with both WalletClient and MemoryWalletClient
16
+ * await wallet.proxyWrite({ uri: "...", data: {...} });
17
+ * }
18
+ *
19
+ * // Production
20
+ * setupApp(new WalletClient({ walletServerUrl: "...", apiBasePath: "/api/v1" }));
21
+ *
22
+ * // Tests
23
+ * setupApp(await MemoryWalletClient.create());
24
+ * ```
25
+ */
26
+ interface WalletClientInterface {
27
+ getSession(): AuthSession | null;
28
+ setSession(session: AuthSession | null): void;
29
+ isAuthenticated(): boolean;
30
+ getUsername(): string | null;
31
+ getToken(): string | null;
32
+ logout(): void;
33
+ health(): Promise<HealthResponse>;
34
+ getServerKeys(): Promise<{
35
+ identityPublicKeyHex: string;
36
+ encryptionPublicKeyHex: string;
37
+ }>;
38
+ /**
39
+ * Signup with session keypair.
40
+ * Session must be approved by app at mutable://accounts/{appKey}/sessions/{sessionPubkey} = 1
41
+ */
42
+ signupWithToken(appKey: string, session: SessionKeypair, credentials: UserCredentials): Promise<AuthSession>;
43
+ /**
44
+ * Login with session keypair.
45
+ * Session must be approved by app at mutable://accounts/{appKey}/sessions/{sessionPubkey} = 1
46
+ */
47
+ loginWithTokenSession(appKey: string, session: SessionKeypair, credentials: UserCredentials): Promise<AuthSession>;
48
+ changePassword(appKey: string, oldPassword: string, newPassword: string): Promise<void>;
49
+ requestPasswordResetWithToken(appKey: string, tokenOrUsername: string, maybeUsername?: string): Promise<PasswordResetToken>;
50
+ resetPasswordWithToken(appKey: string, tokenOrUsername: string, usernameOrReset: string, resetToken?: string, newPassword?: string): Promise<AuthSession>;
51
+ getPublicKeys(appKey: string): Promise<UserPublicKeys>;
52
+ getMyPublicKeys(appKey: string): Promise<UserPublicKeys>;
53
+ proxyWrite(request: ProxyWriteRequest): Promise<ProxyWriteResponse>;
54
+ proxyRead(request: ProxyReadRequest): Promise<ProxyReadResponse>;
55
+ proxyReadMulti(request: ProxyReadMultiRequest): Promise<ProxyReadMultiResponse>;
56
+ signupWithGoogle(appKey: string, token: string, googleIdToken: string): Promise<GoogleAuthSession>;
57
+ loginWithGoogle(appKey: string, token: string, session: SessionKeypair, googleIdToken: string): Promise<GoogleAuthSession>;
58
+ }
6
59
  /**
7
60
  * Configuration for wallet client
8
61
  */
@@ -27,6 +80,17 @@ interface UserCredentials {
27
80
  username: string;
28
81
  password: string;
29
82
  }
83
+ /**
84
+ * Session keypair for authentication
85
+ * Sessions are Ed25519 keypairs. The client creates the session, requests
86
+ * approval from the app, then uses the private key to sign login requests.
87
+ */
88
+ interface SessionKeypair {
89
+ /** Session public key (hex encoded) - used as session identifier */
90
+ publicKeyHex: string;
91
+ /** Session private key (hex encoded) - used to sign login requests */
92
+ privateKeyHex: string;
93
+ }
30
94
  /**
31
95
  * Authenticated session with JWT token
32
96
  */
@@ -89,6 +153,38 @@ interface ProxyReadResponse {
89
153
  decrypted?: unknown;
90
154
  error?: string;
91
155
  }
156
+ /**
157
+ * Read-multi proxy request
158
+ */
159
+ interface ProxyReadMultiRequest {
160
+ uris: string[];
161
+ }
162
+ /**
163
+ * Read-multi proxy result item
164
+ */
165
+ interface ProxyReadMultiResultItem {
166
+ uri: string;
167
+ success: boolean;
168
+ record?: {
169
+ data: unknown;
170
+ ts: number;
171
+ };
172
+ decrypted?: unknown;
173
+ error?: string;
174
+ }
175
+ /**
176
+ * Read-multi proxy response
177
+ */
178
+ interface ProxyReadMultiResponse {
179
+ success: boolean;
180
+ results: ProxyReadMultiResultItem[];
181
+ summary: {
182
+ total: number;
183
+ succeeded: number;
184
+ failed: number;
185
+ };
186
+ error?: string;
187
+ }
92
188
  /**
93
189
  * API response wrapper
94
190
  */
@@ -283,13 +379,31 @@ declare class WalletClient {
283
379
  */
284
380
  resetPassword(_username: string, _resetToken: string, _newPassword: string): Promise<AuthSession>;
285
381
  /**
286
- * Sign up with app token (scoped to an app)
382
+ * Sign up with session keypair (scoped to an app)
383
+ *
384
+ * The session must be approved by the app beforehand:
385
+ * 1. Client writes request to: immutable://inbox/{appKey}/sessions/{sessionPubkey} = 1
386
+ * 2. App approves by writing: mutable://accounts/{appKey}/sessions/{sessionPubkey} = 1
387
+ * 3. Client calls this method with the session keypair
388
+ *
389
+ * @param appKey - The app's public key
390
+ * @param session - Session keypair (generated via generateSessionKeypair)
391
+ * @param credentials - User credentials (username/password)
287
392
  */
288
- signupWithToken(appKey: string, tokenOrCredentials: string | UserCredentials, maybeCredentials?: UserCredentials): Promise<AuthSession>;
393
+ signupWithToken(appKey: string, session: SessionKeypair, credentials: UserCredentials): Promise<AuthSession>;
289
394
  /**
290
- * Login with app token and session (scoped to an app)
395
+ * Login with session keypair (scoped to an app)
396
+ *
397
+ * The session must be approved by the app beforehand:
398
+ * 1. Client writes request to: immutable://inbox/{appKey}/sessions/{sessionPubkey} = 1
399
+ * 2. App approves by writing: mutable://accounts/{appKey}/sessions/{sessionPubkey} = 1
400
+ * 3. Client calls this method with the session keypair
401
+ *
402
+ * @param appKey - The app's public key
403
+ * @param session - Session keypair (generated via generateSessionKeypair)
404
+ * @param credentials - User credentials (username/password)
291
405
  */
292
- loginWithTokenSession(appKey: string, tokenOrSession: string, sessionOrCredentials: string | UserCredentials, maybeCredentials?: UserCredentials): Promise<AuthSession>;
406
+ loginWithTokenSession(appKey: string, session: SessionKeypair, credentials: UserCredentials): Promise<AuthSession>;
293
407
  /**
294
408
  * Request password reset scoped to app token
295
409
  */
@@ -307,14 +421,27 @@ declare class WalletClient {
307
421
  * Proxy a write request through the wallet server
308
422
  * The server signs the write with its identity key
309
423
  * Requires active authentication session
424
+ *
425
+ * @returns ProxyWriteResponse - check `success` field for result
310
426
  */
311
427
  proxyWrite(request: ProxyWriteRequest): Promise<ProxyWriteResponse>;
312
428
  /**
313
429
  * Proxy a read request through the wallet server
314
430
  * The server decrypts encrypted data using user's encryption key
315
431
  * Requires active authentication session
432
+ *
433
+ * @returns ProxyReadResponse - check `success` field for result, `decrypted` for decrypted data
316
434
  */
317
435
  proxyRead(request: ProxyReadRequest): Promise<ProxyReadResponse>;
436
+ /**
437
+ * Proxy multiple read requests through the wallet server
438
+ * Reads multiple URIs in a single request (max 50 URIs)
439
+ * The server decrypts encrypted data using user's encryption key
440
+ * Requires active authentication session
441
+ *
442
+ * @returns ProxyReadMultiResponse - check `success` for overall result, `results` for per-URI results
443
+ */
444
+ proxyReadMulti(request: ProxyReadMultiRequest): Promise<ProxyReadMultiResponse>;
318
445
  /**
319
446
  * Convenience method: Get current user's public keys
320
447
  * Requires active authentication session
@@ -340,15 +467,27 @@ declare class WalletClient {
340
467
  */
341
468
  signupWithGoogle(appKey: string, token: string, googleIdToken: string): Promise<GoogleAuthSession>;
342
469
  /**
343
- * Login with Google OAuth (scoped to app token and session)
470
+ * Login with Google OAuth (scoped to app token and session keypair)
344
471
  * Returns session data with Google profile info - call setSession() to activate it
345
472
  *
473
+ * The session must be approved by the app beforehand.
474
+ *
475
+ * @param appKey - The app's public key
346
476
  * @param token - App token from app server
347
- * @param session - Session key from app server
477
+ * @param session - Session keypair (generated via generateSessionKeypair)
348
478
  * @param googleIdToken - Google ID token from Google Sign-In
349
479
  * @returns GoogleAuthSession with username, JWT token, and Google profile info
350
480
  */
351
- loginWithGoogle(appKey: string, token: string, session: string, googleIdToken: string): Promise<GoogleAuthSession>;
481
+ loginWithGoogle(appKey: string, token: string, session: SessionKeypair, googleIdToken: string): Promise<GoogleAuthSession>;
352
482
  }
483
+ /**
484
+ * Generate a new session keypair for authentication
485
+ * The public key should be registered with the app before login.
486
+ *
487
+ * Uses SDK crypto for consistent key generation across the codebase.
488
+ *
489
+ * @returns SessionKeypair with publicKeyHex and privateKeyHex
490
+ */
491
+ declare function generateSessionKeypair(): Promise<SessionKeypair>;
353
492
 
354
- export { type AuthSession as A, type ChangePasswordResponse as C, type GoogleAuthSession as G, type HealthResponse as H, type LoginResponse as L, type PasswordResetToken as P, type RequestPasswordResetResponse as R, type SignupResponse as S, type UserCredentials as U, WalletClient as W, type UserPublicKeys as a, type ProxyWriteRequest as b, type ProxyWriteResponse as c, type ProxyReadRequest as d, type ProxyReadResponse as e, type WalletClientConfig as f, type ApiResponse as g, type PublicKeysResponse as h, type ResetPasswordResponse as i, type GoogleSignupResponse as j, type GoogleLoginResponse as k };
493
+ export { type AuthSession as A, type ChangePasswordResponse as C, type GoogleAuthSession as G, type HealthResponse as H, type LoginResponse as L, type PasswordResetToken as P, type RequestPasswordResetResponse as R, type SessionKeypair as S, type UserCredentials as U, WalletClient as W, type UserPublicKeys as a, type ProxyWriteRequest as b, type ProxyWriteResponse as c, type ProxyReadRequest as d, type ProxyReadResponse as e, type ProxyReadMultiRequest as f, type ProxyReadMultiResponse as g, generateSessionKeypair as h, type WalletClientInterface as i, type WalletClientConfig as j, type ProxyReadMultiResultItem as k, type ApiResponse as l, type SignupResponse as m, type PublicKeysResponse as n, type ResetPasswordResponse as o, type GoogleSignupResponse as p, type GoogleLoginResponse as q };
@@ -1,4 +1,4 @@
1
- import { N as NodeProtocolInterface, a as HttpClientConfig, g as WriteResult, R as ReadResult, b as ListOptions, c as ListResult, D as DeleteResult, H as HealthStatus } from '../../types-oQCx3U-_.js';
1
+ import { N as NodeProtocolInterface, a as HttpClientConfig, g as WriteResult, R as ReadResult, h as ReadMultiResult, b as ListOptions, c as ListResult, D as DeleteResult, H as HealthStatus } from '../../types-uuvn4oKw.js';
2
2
 
3
3
  /**
4
4
  * HttpClient - HTTP implementation of NodeProtocolInterface
@@ -23,6 +23,8 @@ declare class HttpClient implements NodeProtocolInterface {
23
23
  private parseUri;
24
24
  write<T = unknown>(uri: string, value: T): Promise<WriteResult<T>>;
25
25
  read<T = unknown>(uri: string): Promise<ReadResult<T>>;
26
+ readMulti<T = unknown>(uris: string[]): Promise<ReadMultiResult<T>>;
27
+ private readMultiFallback;
26
28
  list(uri: string, options?: ListOptions): Promise<ListResult>;
27
29
  delete(uri: string): Promise<DeleteResult>;
28
30
  health(): Promise<HealthStatus>;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  HttpClient
3
- } from "../../chunk-LFUC4ETD.js";
3
+ } from "../../chunk-OY4CDOHY.js";
4
4
  import "../../chunk-MLKGABMK.js";
5
5
  export {
6
6
  HttpClient
@@ -1,4 +1,4 @@
1
- import { N as NodeProtocolInterface, d as LocalStorageClientConfig, g as WriteResult, R as ReadResult, b as ListOptions, c as ListResult, D as DeleteResult, H as HealthStatus } from '../../types-oQCx3U-_.js';
1
+ import { N as NodeProtocolInterface, d as LocalStorageClientConfig, g as WriteResult, R as ReadResult, h as ReadMultiResult, b as ListOptions, c as ListResult, D as DeleteResult, H as HealthStatus } from '../../types-uuvn4oKw.js';
2
2
 
3
3
  /**
4
4
  * LocalStorageClient - Browser localStorage implementation of NodeProtocolInterface
@@ -34,6 +34,7 @@ declare class LocalStorageClient implements NodeProtocolInterface {
34
34
  private deserialize;
35
35
  write<T = unknown>(uri: string, value: T): Promise<WriteResult<T>>;
36
36
  read<T = unknown>(uri: string): Promise<ReadResult<T>>;
37
+ readMulti<T = unknown>(uris: string[]): Promise<ReadMultiResult<T>>;
37
38
  list(uri: string, options?: ListOptions): Promise<ListResult>;
38
39
  /**
39
40
  * Check if a URI has children (is a directory)
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  LocalStorageClient
3
- } from "../../chunk-7U5JDFQW.js";
3
+ } from "../../chunk-PZFEKQ7F.js";
4
4
  import "../../chunk-MLKGABMK.js";
5
5
  export {
6
6
  LocalStorageClient
@@ -1,4 +1,4 @@
1
- import { S as Schema, N as NodeProtocolInterface, g as WriteResult, R as ReadResult, b as ListOptions, c as ListResult, H as HealthStatus, D as DeleteResult } from '../../types-oQCx3U-_.js';
1
+ import { N as NodeProtocolInterface, S as Schema, g as WriteResult, R as ReadResult, h as ReadMultiResult, b as ListOptions, c as ListResult, H as HealthStatus, D as DeleteResult } from '../../types-uuvn4oKw.js';
2
2
 
3
3
  type MemoryClientStorageNode<T> = {
4
4
  value?: T;
@@ -6,20 +6,54 @@ type MemoryClientStorageNode<T> = {
6
6
  };
7
7
  type MemoryClientStorage = Map<string, MemoryClientStorageNode<unknown>>;
8
8
  interface MemoryClientConfig {
9
+ /**
10
+ * Schema mapping protocol://hostname to validators.
11
+ *
12
+ * Keys MUST be in format: "protocol://hostname"
13
+ * Examples: "mutable://accounts", "immutable://data", "mutable://open"
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const schema = {
18
+ * "mutable://accounts": async () => ({ valid: true }),
19
+ * "immutable://accounts": async () => ({ valid: true }),
20
+ * };
21
+ * const client = new MemoryClient({ schema });
22
+ * ```
23
+ */
9
24
  schema: Schema;
10
25
  storage?: MemoryClientStorage;
11
26
  }
12
27
  declare class MemoryClient implements NodeProtocolInterface {
13
28
  protected storage: MemoryClientStorage;
14
29
  protected schema: Schema;
30
+ /**
31
+ * Create a new MemoryClient
32
+ *
33
+ * @param config - Configuration with schema mapping
34
+ * @throws Error if schema keys are not in "protocol://hostname" format
35
+ */
15
36
  constructor(config: MemoryClientConfig);
16
37
  write<T = unknown>(uri: string, payload: T): Promise<WriteResult<T>>;
17
38
  read<T>(uri: string): Promise<ReadResult<T>>;
39
+ readMulti<T = unknown>(uris: string[]): Promise<ReadMultiResult<T>>;
18
40
  list(uri: string, options?: ListOptions): Promise<ListResult>;
19
41
  health(): Promise<HealthStatus>;
20
42
  getSchema(): Promise<string[]>;
21
43
  cleanup(): Promise<void>;
22
44
  delete(uri: string): Promise<DeleteResult>;
23
45
  }
46
+ /**
47
+ * Default schema for testing that accepts all writes.
48
+ * Includes common b3nd protocol prefixes.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * import { MemoryClient, createTestSchema } from "@bandeira-tech/b3nd-web/clients/memory";
53
+ *
54
+ * const backend = new MemoryClient({ schema: createTestSchema() });
55
+ * ```
56
+ */
57
+ declare function createTestSchema(): Schema;
24
58
 
25
- export { MemoryClient, type MemoryClientConfig };
59
+ export { MemoryClient, type MemoryClientConfig, createTestSchema };
@@ -1,7 +1,9 @@
1
1
  import {
2
- MemoryClient
3
- } from "../../chunk-GIMIWVPX.js";
2
+ MemoryClient,
3
+ createTestSchema
4
+ } from "../../chunk-O53KW746.js";
4
5
  import "../../chunk-MLKGABMK.js";
5
6
  export {
6
- MemoryClient
7
+ MemoryClient,
8
+ createTestSchema
7
9
  };
@@ -1,4 +1,4 @@
1
- import { N as NodeProtocolInterface, W as WebSocketClientConfig, g as WriteResult, R as ReadResult, b as ListOptions, c as ListResult, D as DeleteResult, H as HealthStatus } from '../../types-oQCx3U-_.js';
1
+ import { N as NodeProtocolInterface, W as WebSocketClientConfig, g as WriteResult, R as ReadResult, h as ReadMultiResult, b as ListOptions, c as ListResult, D as DeleteResult, H as HealthStatus } from '../../types-uuvn4oKw.js';
2
2
 
3
3
  /**
4
4
  * WebSocketClient - WebSocket implementation of NodeProtocolInterface
@@ -52,6 +52,7 @@ declare class WebSocketClient implements NodeProtocolInterface {
52
52
  private sendRequest;
53
53
  write<T = unknown>(uri: string, value: T): Promise<WriteResult<T>>;
54
54
  read<T = unknown>(uri: string): Promise<ReadResult<T>>;
55
+ readMulti<T = unknown>(uris: string[]): Promise<ReadMultiResult<T>>;
55
56
  list(uri: string, options?: ListOptions): Promise<ListResult>;
56
57
  delete(uri: string): Promise<DeleteResult>;
57
58
  health(): Promise<HealthStatus>;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  WebSocketClient
3
- } from "../../chunk-T43IWAQK.js";
3
+ } from "../../chunk-UUHVOWVI.js";
4
4
  import "../../chunk-MLKGABMK.js";
5
5
  export {
6
6
  WebSocketClient
@@ -1,5 +1,5 @@
1
1
  import { Hono } from 'hono';
2
- import { N as NodeProtocolInterface } from './types-oQCx3U-_.js';
2
+ import { N as NodeProtocolInterface } from './types-uuvn4oKw.js';
3
3
 
4
4
  /**
5
5
  * Wallet Server Dependency Injection Interfaces
@@ -169,6 +169,7 @@ interface ProxyWriteResponse {
169
169
  */
170
170
  interface ProxyReadResponse {
171
171
  success: boolean;
172
+ uri?: string;
172
173
  error?: string;
173
174
  record?: {
174
175
  data: unknown;
@@ -268,7 +269,22 @@ declare class WalletServerCore {
268
269
  private normalizeApiBasePath;
269
270
  private readBootstrapState;
270
271
  private writeBootstrapState;
272
+ /**
273
+ * Validate that a session is approved by the app.
274
+ * Sessions are keypairs - the sessionPubkey is used directly as the identifier.
275
+ * App approves sessions by writing 1 to mutable://accounts/{appKey}/sessions/{sessionPubkey}
276
+ *
277
+ * @param appKey - The app's public key
278
+ * @param sessionPubkey - The session's public key (hex encoded)
279
+ * @returns { valid: true } if approved, { valid: false, reason } if not
280
+ */
271
281
  private sessionExists;
282
+ /**
283
+ * Verify that a login request signature is valid for the given session pubkey.
284
+ * The signature should be over the stringified login payload (without the signature field).
285
+ * Uses SDK crypto for consistent verification across the codebase.
286
+ */
287
+ private verifySessionSignature;
272
288
  private createApp;
273
289
  }
274
290
 
@@ -1,7 +1,7 @@
1
- export { C as ClientError, D as DeleteResult, H as HealthStatus, a as HttpClientConfig, L as ListItem, b as ListOptions, c as ListResult, d as LocalStorageClientConfig, N as NodeProtocolInterface, P as PersistenceRecord, R as ReadResult, S as Schema, V as ValidationFn, W as WebSocketClientConfig, e as WebSocketRequest, f as WebSocketResponse, g as WriteResult } from '../types-oQCx3U-_.js';
1
+ export { C as ClientError, D as DeleteResult, H as HealthStatus, a as HttpClientConfig, L as ListItem, b as ListOptions, c as ListResult, d as LocalStorageClientConfig, N as NodeProtocolInterface, P as PersistenceRecord, R as ReadResult, S as Schema, V as ValidationFn, W as WebSocketClientConfig, e as WebSocketRequest, f as WebSocketResponse, g as WriteResult } from '../types-uuvn4oKw.js';
2
2
  export { HttpClient } from '../clients/http/mod.js';
3
3
  export { WebSocketClient } from '../clients/websocket/mod.js';
4
4
  export { LocalStorageClient } from '../clients/local-storage/mod.js';
5
- export { W as WalletClient } from '../client-B0Ekm99R.js';
5
+ export { W as WalletClient } from '../client-C4oQxiDu.js';
6
6
  export { AppsClient } from '../apps/mod.js';
7
7
  export { m as encrypt } from '../mod-CII9wqu2.js';
@@ -1,23 +1,23 @@
1
+ import {
2
+ WebSocketClient
3
+ } from "../chunk-UUHVOWVI.js";
1
4
  import {
2
5
  AppsClient
3
6
  } from "../chunk-VAZUCGED.js";
4
7
  import {
5
8
  WalletClient
6
- } from "../chunk-7O4D7SF6.js";
7
- import {
8
- LocalStorageClient
9
- } from "../chunk-7U5JDFQW.js";
10
- import "../chunk-GIMIWVPX.js";
11
- import {
12
- WebSocketClient
13
- } from "../chunk-T43IWAQK.js";
14
- import "../chunk-F3W5GZU6.js";
9
+ } from "../chunk-GWPCZVXV.js";
10
+ import "../chunk-B4VAPGAO.js";
15
11
  import {
16
12
  mod_exports
17
13
  } from "../chunk-JN75UL5C.js";
18
14
  import {
19
15
  HttpClient
20
- } from "../chunk-LFUC4ETD.js";
16
+ } from "../chunk-OY4CDOHY.js";
17
+ import {
18
+ LocalStorageClient
19
+ } from "../chunk-PZFEKQ7F.js";
20
+ import "../chunk-O53KW746.js";
21
21
  import "../chunk-MLKGABMK.js";
22
22
  export {
23
23
  AppsClient,
@@ -25,6 +25,33 @@ interface ReadResult<T> {
25
25
  record?: PersistenceRecord<T>;
26
26
  error?: string;
27
27
  }
28
+ /**
29
+ * Result for a single URI in a multi-read operation
30
+ */
31
+ type ReadMultiResultItem<T = unknown> = {
32
+ uri: string;
33
+ success: true;
34
+ record: PersistenceRecord<T>;
35
+ } | {
36
+ uri: string;
37
+ success: false;
38
+ error: string;
39
+ };
40
+ /**
41
+ * Result of reading multiple URIs in a single operation
42
+ */
43
+ interface ReadMultiResult<T = unknown> {
44
+ /** true if at least one read succeeded */
45
+ success: boolean;
46
+ /** Per-URI results */
47
+ results: ReadMultiResultItem<T>[];
48
+ /** Summary statistics */
49
+ summary: {
50
+ total: number;
51
+ succeeded: number;
52
+ failed: number;
53
+ };
54
+ }
28
55
  /**
29
56
  * Result of a delete operation
30
57
  */
@@ -109,6 +136,13 @@ interface NodeProtocolWriteInterface {
109
136
  interface NodeProtocolReadInterface {
110
137
  /** Read data from a URI */
111
138
  read<T = unknown>(uri: string): Promise<ReadResult<T>>;
139
+ /**
140
+ * Read multiple URIs in a single operation.
141
+ * Implementations may optimize for batch reads (e.g., SQL IN clause).
142
+ * @param uris - Array of URIs to read (max 50)
143
+ * @returns ReadMultiResult with per-URI results and summary
144
+ */
145
+ readMulti<T = unknown>(uris: string[]): Promise<ReadMultiResult<T>>;
112
146
  /** List items at a URI path */
113
147
  list(uri: string, options?: ListOptions): Promise<ListResult>;
114
148
  /** Health status */
@@ -206,7 +240,7 @@ declare class ClientError extends Error {
206
240
  */
207
241
  interface WebSocketRequest {
208
242
  id: string;
209
- type: "write" | "read" | "list" | "delete" | "health" | "getSchema";
243
+ type: "write" | "read" | "readMulti" | "list" | "delete" | "health" | "getSchema";
210
244
  payload: unknown;
211
245
  }
212
246
  interface WebSocketResponse {
@@ -216,4 +250,4 @@ interface WebSocketResponse {
216
250
  error?: string;
217
251
  }
218
252
 
219
- export { ClientError as C, type DeleteResult as D, type HealthStatus as H, type ListItem as L, type NodeProtocolInterface as N, type PersistenceRecord as P, type ReadResult as R, type Schema as S, type ValidationFn as V, type WebSocketClientConfig as W, type HttpClientConfig as a, type ListOptions as b, type ListResult as c, type LocalStorageClientConfig as d, type WebSocketRequest as e, type WebSocketResponse as f, type WriteResult as g };
253
+ export { ClientError as C, type DeleteResult as D, type HealthStatus as H, type ListItem as L, type NodeProtocolInterface as N, type PersistenceRecord as P, type ReadResult as R, type Schema as S, type ValidationFn as V, type WebSocketClientConfig as W, type HttpClientConfig as a, type ListOptions as b, type ListResult as c, type LocalStorageClientConfig as d, type WebSocketRequest as e, type WebSocketResponse as f, type WriteResult as g, type ReadMultiResult as h };