1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//! Basic Example: Using HyperStack Server
//!
//! This example demonstrates how to use the hyperstack-server crate
//! with a generated spec from transform-macros.
//!
//! # Prerequisites
//!
//! 1. You need a Solana program with an IDL file
//! 2. Create a spec module using the `#[stream_spec]` macro
//! 3. Generate the spec using the macro system
//!
//! # Basic Usage
//!
//! The simplest way to start a HyperStack server:
//!
//! ```no_run
//! use hyperstack_server::Server;
//! # use transform::compiler::MultiEntityBytecode;
//! # use hyperstack_server::Spec;
//!
//! # fn mock_spec() -> Spec {
//! # Spec::new(MultiEntityBytecode::new().build(), "your_program_id")
//! # }
//!
//! #[tokio::main]
//! async fn main() -> anyhow::Result<()> {
//! // Setup logging
//! tracing_subscriber::fmt()
//! .with_env_filter("info")
//! .init();
//!
//! // Start server with default WebSocket configuration
//! Server::builder()
//! .spec(mock_spec())
//! .websocket()
//! .bind("[::]:8877".parse()?)
//! .start()
//! .await
//! }
//! ```
//!
//! # Advanced Usage with Custom Configuration
//!
//! For more control over the server configuration:
//!
//! ```no_run
//! use hyperstack_server::{Server, WebSocketConfig, YellowstoneConfig, HealthConfig};
//! use std::net::SocketAddr;
//! use std::time::Duration;
//! # use transform::compiler::MultiEntityBytecode;
//! # use hyperstack_server::Spec;
//!
//! # fn mock_spec() -> Spec {
//! # Spec::new(MultiEntityBytecode::new().build(), "your_program_id")
//! # }
//!
//! #[tokio::main]
//! async fn main() -> anyhow::Result<()> {
//! // Setup logging with custom filter
//! tracing_subscriber::fmt()
//! .with_env_filter(
//! std::env::var("RUST_LOG")
//! .unwrap_or_else(|_| "info,hyperstack_server=debug".into())
//! )
//! .init();
//!
//! // Configure WebSocket server
//! let ws_config = WebSocketConfig::new("[::]:8877".parse()?);
//!
//! // Configure Yellowstone gRPC connection (if needed)
//! let yellowstone_config = YellowstoneConfig {
//! endpoint: std::env::var("YELLOWSTONE_ENDPOINT")
//! .unwrap_or_else(|_| "http://localhost:10000".into()),
//! x_token: std::env::var("YELLOWSTONE_X_TOKEN").ok(),
//! };
//!
//! // Configure health monitoring (optional)
//! let health_config = HealthConfig::new()
//! .with_heartbeat_interval(Duration::from_secs(30))
//! .with_health_check_timeout(Duration::from_secs(10));
//!
//! // Build and start server with custom configuration
//! Server::builder()
//! .spec(mock_spec())
//! .websocket_config(ws_config)
//! .yellowstone(yellowstone_config)
//! .health_config(health_config) // Enable health monitoring
//! .start()
//! .await
//! }
//! ```
//!
//! # Health Monitoring
//!
//! HyperStack Server includes built-in health monitoring for stream connections:
//!
//! ```no_run
//! use hyperstack_server::Server;
//! # use transform::compiler::MultiEntityBytecode;
//! # use hyperstack_server::Spec;
//!
//! # fn mock_spec() -> Spec {
//! # Spec::new(MultiEntityBytecode::new().build(), "your_program_id")
//! # }
//!
//! #[tokio::main]
//! async fn main() -> anyhow::Result<()> {
//! // Enable health monitoring with defaults (30s heartbeat, 10s timeout)
//! Server::builder()
//! .spec(mock_spec())
//! .websocket()
//! .health_monitoring() // Simple one-liner to enable
//! .bind("[::]:8877".parse()?)
//! .start()
//! .await
//! }
//! ```
//!
//! Health monitoring tracks:
//! - Stream connection status (Connected, Disconnected, Reconnecting, Error)
//! - Event staleness detection (warns if no events received for 2x heartbeat interval)
//! - Error counting and logging
//! - Connection duration tracking
//!
//! # Creating a Spec
//!
//! The spec is generated automatically by the `transform-macros` crate.
//! Here's how to set it up:
//!
//! ```ignore
//! // In your lib.rs or a separate spec module
//! use transform_macros::stream_spec;
//!
//! #[stream_spec(idl = "path/to/your/program.json")]
//! pub mod my_program_spec {
//! use transform_macros::StreamSection;
//! use serde::{Deserialize, Serialize};
//!
//! #[entity(name = "MyEntity")]
//! pub struct MyEntity {
//! pub id: EntityId,
//! pub data: EntityData,
//! }
//!
//! #[derive(Debug, Clone, Serialize, Deserialize, StreamSection)]
//! pub struct EntityId {
//! #[map(generated_sdk::accounts::MyAccount::id, primary_key, strategy = SetOnce)]
//! pub id: u64,
//! }
//!
//! #[derive(Debug, Clone, Serialize, Deserialize, StreamSection)]
//! pub struct EntityData {
//! #[map(generated_sdk::accounts::MyAccount::data, strategy = LastWrite)]
//! pub value: String,
//! }
//! }
//! ```
//!
//! Then use it in your main:
//!
//! ```ignore
//! use hyperstack_server::Server;
//! use my_crate::my_program_spec;
//!
//! #[tokio::main]
//! async fn main() -> anyhow::Result<()> {
//! Server::builder()
//! .spec(my_program_spec::spec()) // Generated by the macro!
//! .websocket()
//! .bind("[::]:8877".parse()?)
//! .start()
//! .await
//! }
//! ```
//!
//! # Environment Variables
//!
//! - `RUST_LOG`: Set log level (e.g., `info`, `debug`, `trace`)
//! - `YELLOWSTONE_ENDPOINT`: Yellowstone gRPC endpoint URL
//! - `YELLOWSTONE_X_TOKEN`: Authentication token for Yellowstone
//!
//! # Running the Example
//!
//! Note: This example cannot run standalone as it requires a real program spec.
//! See the flip-atom implementation for a complete working example.