@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 +348 -0
- package/dist/index.d.mts +233 -0
- package/dist/index.d.ts +233 -0
- package/dist/index.js +366 -0
- package/dist/index.mjs +329 -0
- package/package.json +41 -0
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
|
+
[](./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.
|
package/dist/index.d.mts
ADDED
|
@@ -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 };
|