hyperstack-typescript 0.2.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/README.md +111 -0
- package/dist/index.d.ts +206 -0
- package/dist/index.esm.js +691 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +706 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Hyperstack TypeScript SDK
|
|
2
|
+
|
|
3
|
+
Pure TypeScript SDK for the Hyperstack Solana streaming platform. Framework-agnostic core with AsyncIterable-based streaming.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install hyperstack-typescript
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
### Setup
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { HyperStack } from 'hyperstack-typescript';
|
|
17
|
+
import { SETTLEMENT_GAME_STACK } from './generated/settlement-game-stack';
|
|
18
|
+
|
|
19
|
+
const hs = await HyperStack.connect('wss://mainnet.hyperstack.xyz', {
|
|
20
|
+
stack: SETTLEMENT_GAME_STACK,
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Streaming with AsyncIterable
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
for await (const update of hs.views.settlementGame.list.watch()) {
|
|
28
|
+
if (update.type === 'upsert') {
|
|
29
|
+
console.log('Game updated:', update.key, update.data);
|
|
30
|
+
} else if (update.type === 'delete') {
|
|
31
|
+
console.log('Game deleted:', update.key);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
for await (const update of hs.views.settlementGame.state.watch('game-123')) {
|
|
36
|
+
console.log('Game 123 updated:', update.data);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for await (const update of hs.views.settlementGame.list.watchRich()) {
|
|
40
|
+
if (update.type === 'updated') {
|
|
41
|
+
console.log('Changed from:', update.before);
|
|
42
|
+
console.log('Changed to:', update.after);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### One-Shot Queries
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
const games = await hs.views.settlementGame.list.get();
|
|
51
|
+
|
|
52
|
+
const game = await hs.views.settlementGame.state.get('game-123');
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Connection Management
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
console.log(hs.connectionState);
|
|
59
|
+
|
|
60
|
+
const unsubscribe = hs.onConnectionStateChange((state) => {
|
|
61
|
+
console.log('Connection state:', state);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
await hs.disconnect();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## API
|
|
68
|
+
|
|
69
|
+
### HyperStack
|
|
70
|
+
|
|
71
|
+
Main client class with typed view accessors.
|
|
72
|
+
|
|
73
|
+
- `HyperStack.connect(url, options)` - Connect to a HyperStack server
|
|
74
|
+
- `views` - Typed view accessors based on your stack definition
|
|
75
|
+
- `connectionState` - Current connection state
|
|
76
|
+
- `onConnectionStateChange(callback)` - Listen for connection changes
|
|
77
|
+
- `disconnect()` - Disconnect from the server
|
|
78
|
+
|
|
79
|
+
### Views
|
|
80
|
+
|
|
81
|
+
Each view provides:
|
|
82
|
+
|
|
83
|
+
**StateView (keyed entities)**
|
|
84
|
+
- `watch(key)` - AsyncIterable of updates for a specific key
|
|
85
|
+
- `watchRich(key)` - AsyncIterable with before/after diffs
|
|
86
|
+
- `get(key)` - Get entity by key
|
|
87
|
+
- `getSync(key)` - Get entity synchronously (if available)
|
|
88
|
+
|
|
89
|
+
**ListView (collections)**
|
|
90
|
+
- `watch()` - AsyncIterable of all updates
|
|
91
|
+
- `watchRich()` - AsyncIterable with before/after diffs
|
|
92
|
+
- `get()` - Get all entities
|
|
93
|
+
- `getSync()` - Get all entities synchronously (if available)
|
|
94
|
+
|
|
95
|
+
### Update Types
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
type Update<T> =
|
|
99
|
+
| { type: 'upsert'; key: string; data: T }
|
|
100
|
+
| { type: 'patch'; key: string; data: Partial<T> }
|
|
101
|
+
| { type: 'delete'; key: string };
|
|
102
|
+
|
|
103
|
+
type RichUpdate<T> =
|
|
104
|
+
| { type: 'created'; key: string; data: T }
|
|
105
|
+
| { type: 'updated'; key: string; before: T; after: T; patch?: unknown }
|
|
106
|
+
| { type: 'deleted'; key: string; lastKnown?: T };
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## License
|
|
110
|
+
|
|
111
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error';
|
|
2
|
+
type Update<T> = {
|
|
3
|
+
type: 'upsert';
|
|
4
|
+
key: string;
|
|
5
|
+
data: T;
|
|
6
|
+
} | {
|
|
7
|
+
type: 'patch';
|
|
8
|
+
key: string;
|
|
9
|
+
data: Partial<T>;
|
|
10
|
+
} | {
|
|
11
|
+
type: 'delete';
|
|
12
|
+
key: string;
|
|
13
|
+
};
|
|
14
|
+
type RichUpdate<T> = {
|
|
15
|
+
type: 'created';
|
|
16
|
+
key: string;
|
|
17
|
+
data: T;
|
|
18
|
+
} | {
|
|
19
|
+
type: 'updated';
|
|
20
|
+
key: string;
|
|
21
|
+
before: T;
|
|
22
|
+
after: T;
|
|
23
|
+
patch?: unknown;
|
|
24
|
+
} | {
|
|
25
|
+
type: 'deleted';
|
|
26
|
+
key: string;
|
|
27
|
+
lastKnown?: T;
|
|
28
|
+
};
|
|
29
|
+
interface ViewDef<T, TMode extends 'state' | 'list'> {
|
|
30
|
+
readonly mode: TMode;
|
|
31
|
+
readonly view: string;
|
|
32
|
+
readonly _entity?: T;
|
|
33
|
+
}
|
|
34
|
+
interface StackDefinition {
|
|
35
|
+
readonly name: string;
|
|
36
|
+
readonly views: Record<string, ViewGroup>;
|
|
37
|
+
}
|
|
38
|
+
interface ViewGroup {
|
|
39
|
+
state?: ViewDef<unknown, 'state'>;
|
|
40
|
+
list?: ViewDef<unknown, 'list'>;
|
|
41
|
+
}
|
|
42
|
+
interface Subscription {
|
|
43
|
+
view: string;
|
|
44
|
+
key?: string;
|
|
45
|
+
partition?: string;
|
|
46
|
+
filters?: Record<string, string>;
|
|
47
|
+
}
|
|
48
|
+
interface HyperStackOptions<TStack extends StackDefinition> {
|
|
49
|
+
stack: TStack;
|
|
50
|
+
autoReconnect?: boolean;
|
|
51
|
+
reconnectIntervals?: number[];
|
|
52
|
+
maxReconnectAttempts?: number;
|
|
53
|
+
}
|
|
54
|
+
interface HyperStackConfig {
|
|
55
|
+
websocketUrl?: string;
|
|
56
|
+
reconnectIntervals?: number[];
|
|
57
|
+
maxReconnectAttempts?: number;
|
|
58
|
+
initialSubscriptions?: Subscription[];
|
|
59
|
+
}
|
|
60
|
+
declare const DEFAULT_CONFIG: Required<Pick<HyperStackConfig, 'reconnectIntervals' | 'maxReconnectAttempts'>>;
|
|
61
|
+
declare class HyperStackError extends Error {
|
|
62
|
+
code: string;
|
|
63
|
+
details?: unknown | undefined;
|
|
64
|
+
constructor(message: string, code: string, details?: unknown | undefined);
|
|
65
|
+
}
|
|
66
|
+
type TypedViews<TViews extends StackDefinition['views']> = {
|
|
67
|
+
[K in keyof TViews]: TypedViewGroup<TViews[K]>;
|
|
68
|
+
};
|
|
69
|
+
type TypedViewGroup<TGroup> = {
|
|
70
|
+
state: TGroup extends {
|
|
71
|
+
state: ViewDef<infer T, 'state'>;
|
|
72
|
+
} ? TypedStateView<T> : never;
|
|
73
|
+
list: TGroup extends {
|
|
74
|
+
list: ViewDef<infer T, 'list'>;
|
|
75
|
+
} ? TypedListView<T> : never;
|
|
76
|
+
};
|
|
77
|
+
interface TypedStateView<T> {
|
|
78
|
+
watch(key: string): AsyncIterable<Update<T>>;
|
|
79
|
+
watchRich(key: string): AsyncIterable<RichUpdate<T>>;
|
|
80
|
+
get(key: string): Promise<T | null>;
|
|
81
|
+
getSync(key: string): T | null | undefined;
|
|
82
|
+
}
|
|
83
|
+
interface TypedListView<T> {
|
|
84
|
+
watch(): AsyncIterable<Update<T>>;
|
|
85
|
+
watchRich(): AsyncIterable<RichUpdate<T>>;
|
|
86
|
+
get(): Promise<T[]>;
|
|
87
|
+
getSync(): T[] | undefined;
|
|
88
|
+
}
|
|
89
|
+
type SubscribeCallback<T> = (update: Update<T>) => void;
|
|
90
|
+
type UnsubscribeFn = () => void;
|
|
91
|
+
type ConnectionStateCallback = (state: ConnectionState, error?: string) => void;
|
|
92
|
+
|
|
93
|
+
type FrameMode = 'state' | 'append' | 'list';
|
|
94
|
+
type FrameOp = 'create' | 'upsert' | 'patch' | 'delete';
|
|
95
|
+
interface EntityFrame<T = unknown> {
|
|
96
|
+
mode: FrameMode;
|
|
97
|
+
entity: string;
|
|
98
|
+
op: FrameOp;
|
|
99
|
+
key: string;
|
|
100
|
+
data: T;
|
|
101
|
+
}
|
|
102
|
+
declare function parseFrame(data: ArrayBuffer | string): EntityFrame;
|
|
103
|
+
declare function parseFrameFromBlob(blob: Blob): Promise<EntityFrame>;
|
|
104
|
+
declare function isValidFrame(frame: unknown): frame is EntityFrame;
|
|
105
|
+
|
|
106
|
+
type FrameHandler = <T>(frame: EntityFrame<T>) => void;
|
|
107
|
+
declare class ConnectionManager {
|
|
108
|
+
private ws;
|
|
109
|
+
private websocketUrl;
|
|
110
|
+
private reconnectIntervals;
|
|
111
|
+
private maxReconnectAttempts;
|
|
112
|
+
private reconnectAttempts;
|
|
113
|
+
private reconnectTimeout;
|
|
114
|
+
private pingInterval;
|
|
115
|
+
private currentState;
|
|
116
|
+
private subscriptionQueue;
|
|
117
|
+
private activeSubscriptions;
|
|
118
|
+
private frameHandlers;
|
|
119
|
+
private stateHandlers;
|
|
120
|
+
constructor(config: HyperStackConfig);
|
|
121
|
+
getState(): ConnectionState;
|
|
122
|
+
onFrame(handler: FrameHandler): () => void;
|
|
123
|
+
onStateChange(handler: ConnectionStateCallback): () => void;
|
|
124
|
+
connect(): Promise<void>;
|
|
125
|
+
disconnect(): void;
|
|
126
|
+
subscribe(subscription: Subscription): void;
|
|
127
|
+
unsubscribe(view: string, key?: string): void;
|
|
128
|
+
isConnected(): boolean;
|
|
129
|
+
private makeSubKey;
|
|
130
|
+
private flushSubscriptionQueue;
|
|
131
|
+
private resubscribeActive;
|
|
132
|
+
private updateState;
|
|
133
|
+
private notifyFrameHandlers;
|
|
134
|
+
private handleReconnect;
|
|
135
|
+
private clearReconnectTimeout;
|
|
136
|
+
private startPingInterval;
|
|
137
|
+
private stopPingInterval;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
type EntityUpdateCallback = (viewPath: string, key: string, update: Update<unknown>) => void;
|
|
141
|
+
type RichUpdateCallback = (viewPath: string, key: string, update: RichUpdate<unknown>) => void;
|
|
142
|
+
declare class EntityStore {
|
|
143
|
+
private entities;
|
|
144
|
+
private updateCallbacks;
|
|
145
|
+
private richUpdateCallbacks;
|
|
146
|
+
handleFrame<T>(frame: EntityFrame<T>): void;
|
|
147
|
+
getAll<T>(viewPath: string): T[];
|
|
148
|
+
get<T>(viewPath: string, key: string): T | null;
|
|
149
|
+
getAllSync<T>(viewPath: string): T[] | undefined;
|
|
150
|
+
getSync<T>(viewPath: string, key: string): T | null | undefined;
|
|
151
|
+
keys(viewPath: string): string[];
|
|
152
|
+
size(viewPath: string): number;
|
|
153
|
+
clear(): void;
|
|
154
|
+
clearView(viewPath: string): void;
|
|
155
|
+
onUpdate(callback: EntityUpdateCallback): UnsubscribeFn;
|
|
156
|
+
onRichUpdate(callback: RichUpdateCallback): UnsubscribeFn;
|
|
157
|
+
subscribe<T>(viewPath: string, callback: SubscribeCallback<T>): UnsubscribeFn;
|
|
158
|
+
subscribeToKey<T>(viewPath: string, key: string, callback: SubscribeCallback<T>): UnsubscribeFn;
|
|
159
|
+
private notifyUpdate;
|
|
160
|
+
private notifyRichUpdate;
|
|
161
|
+
private notifyRichDelete;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
declare class SubscriptionRegistry {
|
|
165
|
+
private subscriptions;
|
|
166
|
+
private connection;
|
|
167
|
+
constructor(connection: ConnectionManager);
|
|
168
|
+
subscribe(subscription: Subscription): UnsubscribeFn;
|
|
169
|
+
unsubscribe(subscription: Subscription): void;
|
|
170
|
+
getRefCount(subscription: Subscription): number;
|
|
171
|
+
getActiveSubscriptions(): Subscription[];
|
|
172
|
+
clear(): void;
|
|
173
|
+
private makeSubKey;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
declare class HyperStack<TStack extends StackDefinition> {
|
|
177
|
+
private readonly connection;
|
|
178
|
+
private readonly store;
|
|
179
|
+
private readonly subscriptionRegistry;
|
|
180
|
+
private readonly _views;
|
|
181
|
+
private readonly stack;
|
|
182
|
+
private constructor();
|
|
183
|
+
static connect<T extends StackDefinition>(url: string, options: HyperStackOptions<T>): Promise<HyperStack<T>>;
|
|
184
|
+
get views(): TypedViews<TStack['views']>;
|
|
185
|
+
get connectionState(): ConnectionState;
|
|
186
|
+
get stackName(): string;
|
|
187
|
+
onConnectionStateChange(callback: ConnectionStateCallback): UnsubscribeFn;
|
|
188
|
+
onFrame(callback: (frame: EntityFrame) => void): UnsubscribeFn;
|
|
189
|
+
connect(): Promise<void>;
|
|
190
|
+
disconnect(): void;
|
|
191
|
+
isConnected(): boolean;
|
|
192
|
+
clearStore(): void;
|
|
193
|
+
getStore(): EntityStore;
|
|
194
|
+
getConnection(): ConnectionManager;
|
|
195
|
+
getSubscriptionRegistry(): SubscriptionRegistry;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
declare function createUpdateStream<T>(store: EntityStore, subscriptionRegistry: SubscriptionRegistry, subscription: Subscription, keyFilter?: string): AsyncIterable<Update<T>>;
|
|
199
|
+
declare function createRichUpdateStream<T>(store: EntityStore, subscriptionRegistry: SubscriptionRegistry, subscription: Subscription, keyFilter?: string): AsyncIterable<RichUpdate<T>>;
|
|
200
|
+
|
|
201
|
+
declare function createTypedStateView<T>(viewDef: ViewDef<T, 'state'>, store: EntityStore, subscriptionRegistry: SubscriptionRegistry): TypedStateView<T>;
|
|
202
|
+
declare function createTypedListView<T>(viewDef: ViewDef<T, 'list'>, store: EntityStore, subscriptionRegistry: SubscriptionRegistry): TypedListView<T>;
|
|
203
|
+
declare function createTypedViews<TStack extends StackDefinition>(stack: TStack, store: EntityStore, subscriptionRegistry: SubscriptionRegistry): TypedViews<TStack['views']>;
|
|
204
|
+
|
|
205
|
+
export { ConnectionManager, DEFAULT_CONFIG, EntityStore, HyperStack, HyperStackError, SubscriptionRegistry, createRichUpdateStream, createTypedListView, createTypedStateView, createTypedViews, createUpdateStream, isValidFrame, parseFrame, parseFrameFromBlob };
|
|
206
|
+
export type { ConnectionState, ConnectionStateCallback, EntityFrame, FrameMode, FrameOp, HyperStackConfig, HyperStackOptions, RichUpdate, StackDefinition, SubscribeCallback, Subscription, TypedListView, TypedStateView, TypedViewGroup, TypedViews, UnsubscribeFn, Update, ViewDef, ViewGroup };
|