hyperstack-react 0.3.1 → 0.3.3

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/README.md CHANGED
@@ -45,6 +45,7 @@ function MyComponent() {
45
45
  - **Type Safety**: Full TypeScript support with comprehensive type definitions
46
46
  - **View Definitions**: Create state and list views for your data
47
47
  - **Transaction Handling**: Define and execute transactions with hooks
48
+ - **Single Item Queries**: Type-safe single item fetching with `take: 1` or `useOne()`
48
49
 
49
50
  ### API
50
51
 
@@ -57,6 +58,12 @@ function MyComponent() {
57
58
  - `useHyperstack` - Main hook for accessing stack functionality
58
59
  - `useHyperstackContext` - Access the runtime context directly
59
60
 
61
+ #### View Methods
62
+
63
+ - `.use()` - Subscribe to view data (returns `T[]` for lists, `T` for state)
64
+ - `.use({ take: 1 })` - Subscribe to single item with type narrowing (returns `T | undefined`)
65
+ - `.useOne()` - Convenience method for single item queries (returns `T | undefined`)
66
+
60
67
  #### Factory Functions
61
68
 
62
69
  - `defineStack` - Define a new stack configuration
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import React, { ReactNode } from 'react';
2
- import { StorageAdapter, StorageAdapterConfig, UpdateCallback, RichUpdateCallback, Update, RichUpdate, ConnectionState, ConnectionManager, SubscriptionRegistry } from 'hyperstack-typescript';
2
+ import { StorageAdapter, StorageAdapterConfig, UpdateCallback, RichUpdateCallback, Update, RichUpdate, ConnectionState, ViewSortConfig, ConnectionManager, SubscriptionRegistry } from 'hyperstack-typescript';
3
3
  export { ConnectionManager, ConnectionState, DEFAULT_CONFIG, DEFAULT_MAX_ENTRIES_PER_VIEW, EntityFrame, Frame, FrameMode, FrameOp, FrameProcessor, FrameProcessorConfig, HyperStack, HyperStackConfig, HyperStackError, HyperStackOptions, HyperStackOptionsWithStorage, MemoryAdapter, RichUpdate, RichUpdateCallback, SnapshotEntity, SnapshotFrame, StorageAdapter, StorageAdapterConfig, Subscription, SubscriptionRegistry, Update, UpdateCallback, isSnapshotFrame, isValidFrame, parseFrame, parseFrameFromBlob } from 'hyperstack-typescript';
4
4
  import { UseBoundStore, StoreApi } from 'zustand';
5
5
 
@@ -31,6 +31,8 @@ interface StackDefinition {
31
31
  interface ViewGroup {
32
32
  state?: ViewDef<unknown, 'state'>;
33
33
  list?: ViewDef<unknown, 'list'>;
34
+ /** Allow arbitrary derived views with any name */
35
+ [key: string]: ViewDef<unknown, ViewMode> | undefined;
34
36
  }
35
37
  interface HyperstackConfig {
36
38
  websocketUrl?: string;
@@ -41,6 +43,13 @@ interface HyperstackConfig {
41
43
  reconnectIntervals?: number[];
42
44
  maxReconnectAttempts?: number;
43
45
  maxEntriesPerView?: number | null;
46
+ /**
47
+ * Interval in milliseconds to buffer WebSocket updates before flushing to Zustand.
48
+ * Reduces React re-renders during high-frequency updates.
49
+ * Default: 16ms (one frame at 60fps)
50
+ * Set to 0 for immediate updates (no buffering).
51
+ */
52
+ flushIntervalMs?: number;
44
53
  }
45
54
  interface WalletAdapter {
46
55
  publicKey: string;
@@ -57,12 +66,20 @@ interface ViewHookResult<T> {
57
66
  error?: Error;
58
67
  refresh: () => void;
59
68
  }
60
- interface ListParams {
69
+ interface ListParamsBase {
61
70
  key?: string;
62
71
  where?: Record<string, unknown>;
63
72
  limit?: number;
64
73
  filters?: Record<string, string>;
74
+ skip?: number;
65
75
  }
76
+ interface ListParamsSingle extends ListParamsBase {
77
+ take: 1;
78
+ }
79
+ interface ListParamsMultiple extends ListParamsBase {
80
+ take?: number;
81
+ }
82
+ type ListParams = ListParamsSingle | ListParamsMultiple;
66
83
  interface UseMutationReturn {
67
84
  submit: (instructionOrTx: unknown | unknown[]) => Promise<string>;
68
85
  status: 'idle' | 'pending' | 'success' | 'error';
@@ -76,11 +93,15 @@ interface StateViewHook<T> {
76
93
  }, options?: ViewHookOptions) => ViewHookResult<T>;
77
94
  }
78
95
  interface ListViewHook<T> {
79
- use: (params?: ListParams, options?: ViewHookOptions) => ViewHookResult<T[]>;
96
+ use(params: ListParamsSingle, options?: ViewHookOptions): ViewHookResult<T | undefined>;
97
+ use(params?: ListParamsMultiple, options?: ViewHookOptions): ViewHookResult<T[]>;
98
+ useOne: (params?: Omit<ListParamsBase, 'take'>, options?: ViewHookOptions) => ViewHookResult<T | undefined>;
80
99
  }
81
100
 
82
101
  interface ZustandState {
83
102
  entities: Map<string, Map<string, unknown>>;
103
+ sortedKeys: Map<string, string[]>;
104
+ viewConfigs: Map<string, ViewSortConfig>;
84
105
  connectionState: ConnectionState;
85
106
  lastError?: string;
86
107
  }
@@ -89,6 +110,8 @@ interface ZustandActions {
89
110
  _delete: (viewPath: string, key: string) => void;
90
111
  _clear: (viewPath?: string) => void;
91
112
  _setConnectionState: (state: ConnectionState, error?: string) => void;
113
+ _setViewConfig: (viewPath: string, config: ViewSortConfig) => void;
114
+ _updateSortedKeys: (viewPath: string, sortedKeys: string[]) => void;
92
115
  }
93
116
  type HyperStackStore = ZustandState & ZustandActions;
94
117
  declare class ZustandAdapter implements StorageAdapter {
@@ -113,12 +136,17 @@ declare class ZustandAdapter implements StorageAdapter {
113
136
  notifyUpdate<T>(viewPath: string, key: string, update: Update<T>): void;
114
137
  notifyRichUpdate<T>(viewPath: string, key: string, update: RichUpdate<T>): void;
115
138
  setConnectionState(state: ConnectionState, error?: string): void;
139
+ setViewConfig(viewPath: string, config: ViewSortConfig): void;
140
+ getViewConfig(viewPath: string): ViewSortConfig | undefined;
141
+ private rebuildSortedKeys;
116
142
  }
117
143
 
118
144
  interface SubscriptionHandle {
119
145
  view: string;
120
146
  key?: string;
121
147
  filters?: Record<string, string>;
148
+ take?: number;
149
+ skip?: number;
122
150
  unsubscribe: () => void;
123
151
  }
124
152
  interface HyperstackRuntime {
@@ -127,7 +155,7 @@ interface HyperstackRuntime {
127
155
  connection: ConnectionManager;
128
156
  subscriptionRegistry: SubscriptionRegistry;
129
157
  wallet?: WalletAdapter;
130
- subscribe(view: string, key?: string, filters?: Record<string, string>): SubscriptionHandle;
158
+ subscribe(view: string, key?: string, filters?: Record<string, string>, take?: number, skip?: number): SubscriptionHandle;
131
159
  unsubscribe(handle: SubscriptionHandle): void;
132
160
  }
133
161
  declare function createRuntime(config: HyperstackConfig): HyperstackRuntime;
@@ -144,30 +172,25 @@ declare function useConnectionState(): ConnectionState;
144
172
  declare function useView<T>(viewPath: string): T[];
145
173
  declare function useEntity<T>(viewPath: string, key: string): T | null;
146
174
 
175
+ type ViewHookForDef<TDef> = TDef extends ViewDef<infer T, 'state'> ? {
176
+ use: (key?: Record<string, string>, options?: ViewHookOptions) => ViewHookResult<T>;
177
+ } : TDef extends ViewDef<infer T, 'list'> ? {
178
+ use: {
179
+ (params: ListParamsSingle, options?: ViewHookOptions): ViewHookResult<T | undefined>;
180
+ (params?: ListParamsMultiple, options?: ViewHookOptions): ViewHookResult<T[]>;
181
+ };
182
+ useOne: (params?: Omit<ListParamsBase, 'take'>, options?: ViewHookOptions) => ViewHookResult<T | undefined>;
183
+ } : TDef extends ViewDef<infer T, 'state' | 'list'> ? {
184
+ use: {
185
+ (params: ListParamsSingle, options?: ViewHookOptions): ViewHookResult<T | undefined>;
186
+ (params?: ListParamsMultiple | Record<string, string>, options?: ViewHookOptions): ViewHookResult<T | T[]>;
187
+ };
188
+ useOne: (params?: Omit<ListParamsBase, 'take'>, options?: ViewHookOptions) => ViewHookResult<T | undefined>;
189
+ } : never;
147
190
  type BuildViewInterface<TViews extends Record<string, ViewGroup>> = {
148
- [K in keyof TViews]: TViews[K] extends {
149
- state: ViewDef<infer S, 'state'>;
150
- list: ViewDef<infer L, 'list'>;
151
- } ? {
152
- state: {
153
- use: (key: Record<string, string>, options?: ViewHookOptions) => ViewHookResult<S>;
154
- };
155
- list: {
156
- use: (params?: ListParams, options?: ViewHookOptions) => ViewHookResult<L[]>;
157
- };
158
- } : TViews[K] extends {
159
- state: ViewDef<infer S, 'state'>;
160
- } ? {
161
- state: {
162
- use: (key: Record<string, string>, options?: ViewHookOptions) => ViewHookResult<S>;
163
- };
164
- } : TViews[K] extends {
165
- list: ViewDef<infer L, 'list'>;
166
- } ? {
167
- list: {
168
- use: (params?: ListParams, options?: ViewHookOptions) => ViewHookResult<L[]>;
169
- };
170
- } : object;
191
+ [K in keyof TViews]: {
192
+ [SubK in keyof TViews[K] as TViews[K][SubK] extends ViewDef<unknown, ViewMode> ? SubK : never]: ViewHookForDef<TViews[K][SubK]>;
193
+ };
171
194
  };
172
195
  type StackClient<TStack extends StackDefinition> = {
173
196
  views: BuildViewInterface<TStack['views']>;
@@ -184,4 +207,4 @@ type StackClient<TStack extends StackDefinition> = {
184
207
  declare function useHyperstack<TStack extends StackDefinition>(stack: TStack): StackClient<TStack>;
185
208
 
186
209
  export { HyperstackProvider, ZustandAdapter, createRuntime, useConnectionState, useEntity, useHyperstack, useHyperstackContext, useView };
187
- export type { HyperStackStore, HyperstackConfig, HyperstackRuntime, ListParams, ListViewHook, NetworkConfig, StackDefinition, StateViewHook, SubscriptionHandle, TransactionDefinition, UseMutationReturn, ViewDef, ViewGroup, ViewHookOptions, ViewHookResult, ViewMode, WalletAdapter };
210
+ export type { HyperStackStore, HyperstackConfig, HyperstackRuntime, ListParams, ListParamsBase, ListParamsMultiple, ListParamsSingle, ListViewHook, NetworkConfig, StackDefinition, StateViewHook, SubscriptionHandle, TransactionDefinition, UseMutationReturn, ViewDef, ViewGroup, ViewHookOptions, ViewHookResult, ViewMode, WalletAdapter };