@stackwright-pro/pulse 0.1.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 ADDED
@@ -0,0 +1,348 @@
1
+ # @stackwright-pro/pulse
2
+
3
+ > Source-agnostic real-time data polling for Stackwright Pro. Works with OpenAPI, WebSockets, GraphQL, SSE, or any data source.
4
+
5
+ [![License: PROPRIETARY](https://img.shields.io/badge/License-PROPRIETARY-red.svg)](./package.json)
6
+
7
+ ## Features
8
+
9
+ - **πŸ”Œ Source-Agnostic** - Works with ANY async data source via a simple `fetcher` interface
10
+ - **⏱️ Real-time Polling** - Configurable polling intervals with automatic retries
11
+ - **πŸ“Š State Management** - Built-in states: `loading`, `live`, `stale`, `error`
12
+ - **πŸ›‘οΈ Runtime Validation** - Optional Zod schema validation for data integrity
13
+ - **⚑ React Query Powered** - Leverages TanStack Query for caching and background updates
14
+ - **🎨 Flexible UI** - Render props with metadata for custom state indicators
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ pnpm add @stackwright-pro/pulse
20
+ ```
21
+
22
+ **Peer Dependencies:**
23
+ ```bash
24
+ pnpm add react react-dom @tanstack/react-query
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ### Basic Usage
30
+
31
+ ```tsx
32
+ import { Pulse, PulseIndicator } from '@stackwright-pro/pulse';
33
+
34
+ function EquipmentPanel() {
35
+ return (
36
+ <Pulse
37
+ fetcher={() => fetch('/api/equipment').then(r => r.json())}
38
+ interval={5000}
39
+ >
40
+ {(equipment, meta) => (
41
+ <>
42
+ <PulseIndicator meta={meta} />
43
+ <EquipmentGrid data={equipment} />
44
+ </>
45
+ )}
46
+ </Pulse>
47
+ );
48
+ }
49
+ ```
50
+
51
+ ### With Zod Validation
52
+
53
+ ```tsx
54
+ import { z } from 'zod';
55
+ import { Pulse } from '@stackwright-pro/pulse';
56
+
57
+ const EquipmentSchema = z.object({
58
+ id: z.string(),
59
+ name: z.string(),
60
+ status: z.enum(['online', 'offline', 'maintenance']),
61
+ lastUpdated: z.string().datetime(),
62
+ });
63
+
64
+ function EquipmentPanel() {
65
+ return (
66
+ <Pulse
67
+ fetcher={() => fetch('/api/equipment').then(r => r.json())}
68
+ schema={EquipmentSchema}
69
+ interval={5000}
70
+ >
71
+ {(equipment) => <EquipmentGrid data={equipment} />}
72
+ </Pulse>
73
+ );
74
+ }
75
+ ```
76
+
77
+ ### Custom State UI
78
+
79
+ ```tsx
80
+ import { Pulse } from '@stackwright-pro/pulse';
81
+
82
+ function CustomEquipmentPanel() {
83
+ return (
84
+ <Pulse
85
+ fetcher={fetchEquipment}
86
+ interval={5000}
87
+ staleThreshold={30000}
88
+ maxStaleAge={60000}
89
+ loadingState={<SkeletonLoader />}
90
+ errorState={(meta) => (
91
+ <ErrorBanner
92
+ message="Failed to load equipment"
93
+ lastUpdated={meta.lastUpdated}
94
+ onRetry={meta.refetch}
95
+ />
96
+ )}
97
+ emptyState={<EmptyState message="No equipment found" />}
98
+ >
99
+ {(equipment, meta) => (
100
+ <>
101
+ {meta.state === 'stale' && <StaleBanner />}
102
+ <EquipmentGrid data={equipment} />
103
+ </>
104
+ )}
105
+ </Pulse>
106
+ );
107
+ }
108
+ ```
109
+
110
+ ## Architecture
111
+
112
+ ```
113
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
114
+ β”‚ <Pulse> Component β”‚
115
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
116
+ β”‚ β”‚
117
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
118
+ β”‚ β”‚ Render β”‚ β”‚ usePulse β”‚ β”‚ React Query β”‚ β”‚
119
+ β”‚ β”‚ Props │───▢│ Hook │───▢│ Provider β”‚ β”‚
120
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
121
+ β”‚ β”‚ β”‚ β”‚ β”‚
122
+ β”‚ β”‚ β”‚ β”‚ β”‚
123
+ β”‚ β–Ό β–Ό β–Ό β”‚
124
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
125
+ β”‚ β”‚ PulseMeta β”‚ β”‚ Fetcher β”‚ β”‚ Caching & β”‚ β”‚
126
+ β”‚ β”‚ (metadata) β”‚ β”‚ Validation β”‚ β”‚ Polling β”‚ β”‚
127
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
128
+ β”‚ β”‚
129
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
130
+ β”‚
131
+ β–Ό
132
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
133
+ β”‚ ANY Data Source β”‚
134
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
135
+ β”‚ β€’ OpenAPI (fetch/axios) β”‚
136
+ β”‚ β€’ WebSocket β”‚
137
+ β”‚ β€’ GraphQL (urql/Apollo) β”‚
138
+ β”‚ β€’ SSE (EventSource) β”‚
139
+ β”‚ β€’ Custom async functions β”‚
140
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
141
+ ```
142
+
143
+ ## API Reference
144
+
145
+ ### `<Pulse>` Component
146
+
147
+ ```tsx
148
+ interface PulseProps<T> {
149
+ // Core
150
+ fetcher: () => Promise<T>; // Your data fetching function
151
+ children: (data: T, meta: PulseMeta) => React.ReactNode;
152
+
153
+ // Polling config
154
+ interval?: number; // Poll interval in ms (default: 5000, min: 1000)
155
+ enabled?: boolean; // Enable/disable polling (default: true)
156
+ retryCount?: number; // Number of retries on error (default: 3)
157
+ refetchOnWindowFocus?: boolean; // Refetch on window focus (default: true)
158
+
159
+ // State thresholds (in milliseconds)
160
+ staleThreshold?: number; // Show stale warning (default: 30000)
161
+ maxStaleAge?: number; // Show error state (default: 60000)
162
+
163
+ // Validation
164
+ schema?: ZodSchema<T>; // Optional Zod schema
165
+
166
+ // Custom state UI
167
+ loadingState?: React.ReactNode;
168
+ errorState?: React.ReactNode | ((meta: PulseMeta) => React.ReactNode);
169
+ emptyState?: React.ReactNode;
170
+ showStaleDataOnError?: boolean; // Show data during error (default: true)
171
+ }
172
+ ```
173
+
174
+ ### `PulseMeta` (passed to children)
175
+
176
+ ```tsx
177
+ interface PulseMeta {
178
+ lastUpdated: Date; // Timestamp of last successful fetch
179
+ isStale: boolean; // Data older than staleThreshold
180
+ isError: boolean; // Data older than maxStaleAge or fetch failed
181
+ isLoading: boolean; // Currently fetching
182
+ errorCount: number; // Number of consecutive errors
183
+ refetch: () => void; // Manual refresh trigger
184
+ state: 'loading' | 'live' | 'stale' | 'error';
185
+ }
186
+ ```
187
+
188
+ ### `<PulseIndicator>` Component
189
+
190
+ ```tsx
191
+ interface PulseIndicatorProps {
192
+ meta: PulseMeta; // Required meta object
193
+ showSeconds?: boolean; // Show "Xs ago" (default: true)
194
+ className?: string; // Additional CSS classes
195
+ labels?: {
196
+ live?: string; // Custom live label
197
+ syncing?: string; // Custom syncing label
198
+ stale?: string; // Custom stale label
199
+ error?: string; // Custom error label
200
+ };
201
+ }
202
+ ```
203
+
204
+ ### `usePulse` Hook
205
+
206
+ ```tsx
207
+ const result = usePulse<T>({
208
+ fetcher,
209
+ interval = 5000,
210
+ staleThreshold = 30000,
211
+ maxStaleAge = 60000,
212
+ schema,
213
+ enabled = true,
214
+ refetchOnWindowFocus = true,
215
+ retryCount = 3,
216
+ });
217
+
218
+ // Returns
219
+ {
220
+ data: T | undefined,
221
+ meta: PulseMeta,
222
+ state: PulseState,
223
+ error: Error | null,
224
+ }
225
+ ```
226
+
227
+ ## Source Adapters
228
+
229
+ The `fetcher` prop accepts **any** async function. This makes Pulse work with:
230
+
231
+ | Source | Example Fetcher |
232
+ |--------|-----------------|
233
+ | REST/OpenAPI | `() => fetch('/api/data').then(r => r.json())` |
234
+ | WebSocket | `() => websocket.nextMessage()` |
235
+ | GraphQL | `() => client.query({ query: MY_QUERY })` |
236
+ | SSE | `() => eventSource.nextEvent()` |
237
+
238
+ See [SOURCE_ADAPTERS.md](./docs/SOURCE_ADAPTERS.md) for planned first-party adapter documentation.
239
+
240
+ ## State Transitions
241
+
242
+ ```
243
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
244
+ β”‚ loading β”‚ ← Initial state
245
+ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
246
+ β”‚ data received
247
+ β–Ό
248
+ β”Œβ”€β”€β”€β”€β”€β”€β”
249
+ β”‚ live β”‚ ← Normal operation
250
+ β””β”€β”€β”¬β”€β”€β”€β”˜
251
+ β”‚ time > staleThreshold
252
+ β–Ό
253
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”
254
+ β”‚ stale β”‚ ← Data is old but usable
255
+ β””β”€β”€β”¬β”€β”€β”€β”˜
256
+ β”‚ time > maxStaleAge OR fetch error
257
+ β–Ό
258
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”
259
+ β”‚ error β”‚ ← Data may be stale, show error UI
260
+ β””β”€β”€β”¬β”€β”€β”€β”˜
261
+ β”‚ successful refetch
262
+ β–Ό
263
+ β”Œβ”€β”€β”€β”€β”€β”€β”
264
+ β”‚ live β”‚ ← Back to normal
265
+ β””β”€β”€β”€β”€β”€β”€β”˜
266
+ ```
267
+
268
+ ## Validation
269
+
270
+ Use Zod schemas to validate incoming data:
271
+
272
+ ```tsx
273
+ import { z } from 'zod';
274
+ import { createPulseValidator, PulseValidationError } from '@stackwright-pro/pulse';
275
+
276
+ const validator = createPulseValidator(MySchema);
277
+
278
+ // Safe parse - returns null on failure
279
+ const data = validator.safeParse(rawData);
280
+
281
+ // Throws PulseValidationError on failure with detailed issues
282
+ const data = validator.parse(rawData);
283
+ ```
284
+
285
+ ## Best Practices
286
+
287
+ 1. **Use appropriate intervals** - Consider network cost vs. data freshness needs
288
+ 2. **Handle empty states** - Always provide `emptyState` for collections
289
+ 3. **Validate early** - Use Zod schemas to catch data contract issues
290
+ 4. **Leverage meta state** - Use `meta.state` for fine-grained UI control
291
+ 5. **Cleanup properly** - Disable polling when component unmounts if needed
292
+
293
+ ## Live Demo
294
+
295
+ See the [Marine Logistics Demo](../../examples/marine-logistics-demo/) for a complete example of Pulse with OpenAPI integration:
296
+
297
+ ```tsx
298
+ import { Pulse, PulseIndicator } from '@stackwright-pro/pulse';
299
+ import { createOpenAPIFetcher } from '@stackwright-pro/openapi';
300
+ import type { Equipment } from './generated/types';
301
+ import { EquipmentSchema } from './generated/schemas';
302
+
303
+ // Create typed fetcher from OpenAPI config
304
+ const fetcher = createOpenAPIFetcher({
305
+ baseUrl: 'https://api.logistics.example.mil/v1',
306
+ endpoint: '/equipment',
307
+ auth: { type: 'bearer', token: process.env.API_TOKEN },
308
+ });
309
+
310
+ function EquipmentDashboard() {
311
+ return (
312
+ <Pulse
313
+ fetcher={fetcher}
314
+ interval={5000}
315
+ staleThreshold={30000}
316
+ maxStaleAge={60000}
317
+ schema={EquipmentSchema}
318
+ loadingState={<SkeletonLoader />}
319
+ >
320
+ {(equipment: Equipment[], meta) => (
321
+ <>
322
+ <PulseIndicator meta={meta} />
323
+ <div className="equipment-grid">
324
+ {equipment.map((item) => (
325
+ <EquipmentCard key={item.id} data={item} />
326
+ ))}
327
+ </div>
328
+ </>
329
+ )}
330
+ </Pulse>
331
+ );
332
+ }
333
+ ```
334
+
335
+ For a full working demo, see [examples/marine-logistics-demo/src/pages/dashboard-live.tsx](../../examples/marine-logistics-demo/src/pages/dashboard-live.tsx)
336
+
337
+ ## Future Features
338
+
339
+ - [ ] `createWebSocketFetcher()` - Real-time WebSocket adapter
340
+ - [ ] `createGraphQLFetcher()` - GraphQL query polling adapter
341
+ - [ ] `createSSEFetcher()` - Server-Sent Events adapter
342
+ - [ ] Streaming mode via `useStreaming` hook
343
+
344
+ See [docs/SOURCE_ADAPTERS.md](./docs/SOURCE_ADAPTERS.md) for planned adapter documentation.
345
+
346
+ ## License
347
+
348
+ PROPRIETARY - All rights reserved.
@@ -0,0 +1,233 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+ import { ZodSchema, z } from 'zod';
4
+
5
+ /**
6
+ * Source-agnostic polling options
7
+ * The fetcher can be ANY async function - OpenAPI, WebSocket, GraphQL, SSE, etc.
8
+ */
9
+ interface PulseOptions<T> {
10
+ /**
11
+ * ANY async function that returns data
12
+ * Examples:
13
+ * - OpenAPI: () => fetch('/api/equipment').then(r => r.json())
14
+ * - WebSocket: () => websocket.nextMessage()
15
+ * - GraphQL: () => graphqlClient.query(GET_EQUIPMENT)
16
+ * - SSE: () => eventSource.nextEvent()
17
+ */
18
+ fetcher: () => Promise<T>;
19
+ /** Polling interval in milliseconds (default: 5000, min: 1000) */
20
+ interval?: number;
21
+ /** Show stale warning after this many ms without update (default: 30000) */
22
+ staleThreshold?: number;
23
+ /** Show error state after this many ms without update (default: 60000) */
24
+ maxStaleAge?: number;
25
+ /** Optional Zod schema for runtime validation */
26
+ schema?: ZodSchema<T>;
27
+ /** Enable/disable polling (default: true) */
28
+ enabled?: boolean;
29
+ /** React Query option - refetch on window focus (default: true) */
30
+ refetchOnWindowFocus?: boolean;
31
+ /** Number of retry attempts on error (default: 3) */
32
+ retryCount?: number;
33
+ }
34
+ /**
35
+ * Metadata passed to children render function
36
+ */
37
+ interface PulseMeta {
38
+ /** Timestamp of last successful fetch */
39
+ lastUpdated: Date;
40
+ /** Data is older than staleThreshold */
41
+ isStale: boolean;
42
+ /** Data is older than maxStaleAge or fetch failed */
43
+ isError: boolean;
44
+ /** Currently fetching data */
45
+ isLoading: boolean;
46
+ /** Number of consecutive errors */
47
+ errorCount: number;
48
+ /** Manually trigger a refresh */
49
+ refetch: () => void;
50
+ /** Current state: 'loading' | 'live' | 'stale' | 'error' */
51
+ state: PulseState;
52
+ }
53
+ /** Possible states */
54
+ type PulseState = 'loading' | 'live' | 'stale' | 'error';
55
+ /**
56
+ * Component props
57
+ */
58
+ interface PulseProps<T> extends PulseOptions<T> {
59
+ /** Render prop - receives data and meta */
60
+ children: (data: T, meta: PulseMeta) => React.ReactNode;
61
+ /** Initial loading state UI */
62
+ loadingState?: React.ReactNode;
63
+ /** Error state UI (receives meta) */
64
+ errorState?: ((meta: PulseMeta) => React.ReactNode) | React.ReactNode;
65
+ /** Empty state UI (when fetcher returns empty/null) */
66
+ emptyState?: React.ReactNode;
67
+ /** Show stale data while in error state (default: true) */
68
+ showStaleDataOnError?: boolean;
69
+ }
70
+ /**
71
+ * Indicator component props
72
+ */
73
+ interface PulseIndicatorProps {
74
+ meta: PulseMeta;
75
+ showSeconds?: boolean;
76
+ className?: string;
77
+ labels?: {
78
+ live?: string;
79
+ syncing?: string;
80
+ stale?: string;
81
+ error?: string;
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Source-agnostic real-time data polling component
87
+ *
88
+ * Works with ANY data source via the fetcher prop.
89
+ * OpenAPI, WebSocket, GraphQL, SSE - doesn't matter.
90
+ *
91
+ * @example OpenAPI
92
+ * ```tsx
93
+ * <Pulse
94
+ * fetcher={() => fetch('/api/equipment').then(r => r.json())}
95
+ * interval={5000}
96
+ * schema={EquipmentSchema}
97
+ * >
98
+ * {(equipment, meta) => (
99
+ * <>
100
+ * <PulseIndicator meta={meta} />
101
+ * <EquipmentGrid data={equipment} />
102
+ * </>
103
+ * )}
104
+ * </Pulse>
105
+ * ```
106
+ */
107
+ declare function Pulse<T>({ fetcher, interval, staleThreshold, maxStaleAge, schema, enabled, refetchOnWindowFocus, retryCount, children, loadingState, errorState, emptyState, showStaleDataOnError, }: PulseProps<T>): react_jsx_runtime.JSX.Element;
108
+
109
+ /**
110
+ * Visual status indicator for Pulse data
111
+ * Shows live/syncing/stale/error states with animated dot
112
+ */
113
+ declare function PulseIndicator({ meta, showSeconds, className, labels, }: PulseIndicatorProps): react_jsx_runtime.JSX.Element;
114
+
115
+ /**
116
+ * Loading state component
117
+ */
118
+ declare function PulseLoadingState({ className, text, }: {
119
+ className?: string;
120
+ text?: string;
121
+ }): react_jsx_runtime.JSX.Element;
122
+ /**
123
+ * Error state component
124
+ */
125
+ declare function PulseErrorState({ meta, className, customMessage, }: {
126
+ meta: PulseMeta;
127
+ className?: string;
128
+ customMessage?: string;
129
+ }): react_jsx_runtime.JSX.Element;
130
+ /**
131
+ * Empty state component
132
+ */
133
+ declare function PulseEmptyState({ className, text, }: {
134
+ className?: string;
135
+ text?: string;
136
+ }): react_jsx_runtime.JSX.Element;
137
+ /**
138
+ * Stale state component
139
+ */
140
+ declare function PulseStaleState({ meta, className, customMessage, }: {
141
+ meta: PulseMeta;
142
+ className?: string;
143
+ customMessage?: string;
144
+ }): react_jsx_runtime.JSX.Element;
145
+ /**
146
+ * Syncing state component
147
+ */
148
+ declare function PulseSyncingState({ className, text, }: {
149
+ className?: string;
150
+ text?: string;
151
+ }): react_jsx_runtime.JSX.Element;
152
+
153
+ /**
154
+ * Source-agnostic polling hook
155
+ *
156
+ * Works with ANY fetcher function:
157
+ * - OpenAPI endpoints
158
+ * - WebSocket messages
159
+ * - GraphQL queries
160
+ * - SSE events
161
+ * - Custom fetch functions
162
+ */
163
+ declare function usePulse<T>(options: PulseOptions<T>): {
164
+ data: T | undefined;
165
+ meta: PulseMeta;
166
+ state: PulseState;
167
+ error: Error | null;
168
+ };
169
+
170
+ /**
171
+ * useStreaming - Future streaming mode hook
172
+ *
173
+ * This hook is a placeholder for future streaming support.
174
+ * Planned implementation will support:
175
+ * - Server-Sent Events (SSE)
176
+ * - WebSocket streams
177
+ * - Chunked transfer encoding
178
+ * - Real-time push notifications
179
+ *
180
+ * @example Future usage
181
+ * ```tsx
182
+ * const { data, isConnected } = useStreaming({
183
+ * url: '/api/events',
184
+ * type: 'sse',
185
+ * onMessage: (event) => handleEvent(event),
186
+ * });
187
+ * ```
188
+ */
189
+ declare function useStreaming<T>(_options: StreamingOptions<T>): StreamingResult<T>;
190
+ interface StreamingOptions<T> {
191
+ url: string;
192
+ type: 'sse' | 'websocket';
193
+ onMessage?: (data: T) => void;
194
+ reconnectInterval?: number;
195
+ maxRetries?: number;
196
+ }
197
+ interface StreamingResult<T> {
198
+ data: T | null;
199
+ isConnected: boolean;
200
+ isConnecting: boolean;
201
+ error: Error | null;
202
+ }
203
+
204
+ /**
205
+ * Creates a validation wrapper for Pulse data
206
+ */
207
+ declare function createPulseValidator<T>(schema: z.ZodSchema<T>): {
208
+ /**
209
+ * Validates data, throwing on failure
210
+ */
211
+ parse: (data: unknown) => T;
212
+ /**
213
+ * Safe parse - returns null on failure
214
+ */
215
+ safeParse: (data: unknown) => T | null;
216
+ };
217
+ /**
218
+ * Error class for validation failures
219
+ */
220
+ declare class PulseValidationError extends Error {
221
+ readonly issues: z.ZodIssue[];
222
+ constructor(message: string, issues: z.ZodIssue[]);
223
+ /**
224
+ * Get formatted error messages
225
+ */
226
+ getFormattedErrors(): {
227
+ path: string;
228
+ message: string;
229
+ code: "custom" | "invalid_type" | "too_big" | "too_small" | "invalid_format" | "not_multiple_of" | "unrecognized_keys" | "invalid_union" | "invalid_key" | "invalid_element" | "invalid_value";
230
+ }[];
231
+ }
232
+
233
+ export { Pulse, PulseEmptyState, PulseErrorState, PulseIndicator, type PulseIndicatorProps, PulseLoadingState, type PulseMeta, type PulseOptions, type PulseProps, PulseStaleState, type PulseState, PulseSyncingState, PulseValidationError, createPulseValidator, usePulse, useStreaming };