svelte-adapter-uws 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/client.d.ts ADDED
@@ -0,0 +1,356 @@
1
+ import type { Readable } from 'svelte/store';
2
+
3
+ export interface ConnectOptions {
4
+ /**
5
+ * WebSocket endpoint path. Must match the adapter config.
6
+ * @default '/ws'
7
+ */
8
+ path?: string;
9
+
10
+ /**
11
+ * Base delay in ms before reconnecting after a disconnect.
12
+ * Uses exponential backoff with jitter.
13
+ * @default 3000
14
+ */
15
+ reconnectInterval?: number;
16
+
17
+ /**
18
+ * Maximum delay in ms between reconnection attempts.
19
+ * @default 30000
20
+ */
21
+ maxReconnectInterval?: number;
22
+
23
+ /**
24
+ * Maximum number of reconnection attempts before giving up.
25
+ * @default Infinity
26
+ */
27
+ maxReconnectAttempts?: number;
28
+
29
+ /**
30
+ * Log all WebSocket events to the console.
31
+ * Useful during development to see exactly what's happening.
32
+ * @default false
33
+ */
34
+ debug?: boolean;
35
+ }
36
+
37
+ /**
38
+ * A message received from the server via `platform.publish(topic, event, data)`.
39
+ */
40
+ export interface WSEvent<T = unknown> {
41
+ /** The topic this message was published to. */
42
+ topic: string;
43
+ /** The event name (e.g. `'created'`, `'updated'`, `'deleted'`). */
44
+ event: string;
45
+ /** The event payload. */
46
+ data: T;
47
+ }
48
+
49
+ // ── Scannable store ──────────────────────────────────────────────────────────
50
+
51
+ /**
52
+ * A readable store with an additional `.scan()` method for accumulating state.
53
+ */
54
+ export interface TopicStore<T> extends Readable<T | null> {
55
+ /**
56
+ * Create a derived store that accumulates events using a reducer.
57
+ *
58
+ * Like `Array.reduce` but reactive - each new event feeds through
59
+ * the reducer and the store updates with the new accumulated value.
60
+ *
61
+ * @example
62
+ * ```svelte
63
+ * <script>
64
+ * import { on } from 'svelte-adapter-uws/client';
65
+ *
66
+ * const todos = on('todos').scan([], (list, { event, data }) => {
67
+ * if (event === 'created') return [...list, data];
68
+ * if (event === 'deleted') return list.filter(t => t.id !== data.id);
69
+ * if (event === 'updated') return list.map(t => t.id === data.id ? data : t);
70
+ * return list;
71
+ * });
72
+ * </script>
73
+ *
74
+ * {#each $todos as todo}
75
+ * <p>{todo.text}</p>
76
+ * {/each}
77
+ * ```
78
+ *
79
+ * @param initial - Starting value (e.g. `[]`, `{}`, `0`)
80
+ * @param reducer - Called with `(accumulator, event)` on each new event
81
+ */
82
+ scan<A>(initial: A, reducer: (acc: A, value: T) => A): Readable<A>;
83
+ }
84
+
85
+ // ── Direct exports (recommended) ────────────────────────────────────────────
86
+
87
+ /**
88
+ * Get a reactive Svelte store for a topic. Auto-connects and auto-subscribes.
89
+ *
90
+ * **This is the only function most users need.**
91
+ *
92
+ * @example Topic-level (all events):
93
+ * ```svelte
94
+ * <script>
95
+ * import { on } from 'svelte-adapter-uws/client';
96
+ * const todos = on('todos');
97
+ * </script>
98
+ *
99
+ * {#if $todos}
100
+ * <p>{$todos.event}: {JSON.stringify($todos.data)}</p>
101
+ * {/if}
102
+ * ```
103
+ *
104
+ * @example Event-level (filtered, data-only):
105
+ * ```svelte
106
+ * <script>
107
+ * import { on } from 'svelte-adapter-uws/client';
108
+ * const newTodo = on('todos', 'created');
109
+ * </script>
110
+ *
111
+ * {#if $newTodo}
112
+ * <p>New: {$newTodo.text}</p>
113
+ * {/if}
114
+ * ```
115
+ *
116
+ * @example Accumulate state with .scan() (Svelte 5):
117
+ * ```svelte
118
+ * <script>
119
+ * import { on } from 'svelte-adapter-uws/client';
120
+ * const todos = on('todos').scan([], (list, { event, data }) => {
121
+ * if (event === 'created') return [...list, data];
122
+ * if (event === 'deleted') return list.filter(t => t.id !== data.id);
123
+ * return list;
124
+ * });
125
+ * </script>
126
+ * ```
127
+ */
128
+ export function on<T = unknown>(topic: string): TopicStore<WSEvent<T>>;
129
+ export function on<T = unknown>(topic: string, event: string): TopicStore<T>;
130
+
131
+ /**
132
+ * Readable store - connection status: `'connecting'` | `'open'` | `'closed'`.
133
+ * Auto-connects on first access.
134
+ *
135
+ * @example
136
+ * ```svelte
137
+ * <script>
138
+ * import { status } from 'svelte-adapter-uws/client';
139
+ * </script>
140
+ *
141
+ * {#if $status === 'open'}
142
+ * <span class="badge">Live</span>
143
+ * {/if}
144
+ * ```
145
+ */
146
+ export const status: Readable<'connecting' | 'open' | 'closed'>;
147
+
148
+ /**
149
+ * Live CRUD list - one line for real-time collections.
150
+ *
151
+ * Subscribes to a topic and automatically handles `created`, `updated`,
152
+ * and `deleted` events. Pair with `platform.topic('...').created(item)`
153
+ * on the server for zero-boilerplate real-time lists.
154
+ *
155
+ * @param topic - Topic to subscribe to
156
+ * @param initial - Starting data (e.g. from a load function)
157
+ * @param options - Options (default key: `'id'`)
158
+ *
159
+ * @example
160
+ * ```svelte
161
+ * <script>
162
+ * import { crud } from 'svelte-adapter-uws/client';
163
+ * let { data } = $props(); // { todos: [...] } from +page.server.js load()
164
+ *
165
+ * const todos = crud('todos', data.todos);
166
+ * // $todos auto-updates when server publishes created/updated/deleted
167
+ * </script>
168
+ *
169
+ * {#each $todos as todo (todo.id)}
170
+ * <p>{todo.text}</p>
171
+ * {/each}
172
+ * ```
173
+ *
174
+ * @example Notification feed (newest first):
175
+ * ```js
176
+ * const notifications = crud('notifications', [], { prepend: true });
177
+ * ```
178
+ */
179
+ export function crud<T extends Record<string, any>>(
180
+ topic: string,
181
+ initial?: T[],
182
+ options?: { key?: keyof T & string; prepend?: boolean }
183
+ ): Readable<T[]>;
184
+
185
+ /**
186
+ * Live keyed object - like `crud()` but returns a `Record` keyed by ID.
187
+ * Better for dashboards and fast lookups where you need `$users['abc']`.
188
+ *
189
+ * @param topic - Topic to subscribe to
190
+ * @param initial - Starting data (e.g. from a load function)
191
+ * @param options - Options (default key: `'id'`)
192
+ *
193
+ * @example
194
+ * ```svelte
195
+ * <script>
196
+ * import { lookup } from 'svelte-adapter-uws/client';
197
+ * let { data } = $props();
198
+ *
199
+ * const users = lookup('users', data.users);
200
+ * </script>
201
+ *
202
+ * {#if $users[selectedId]}
203
+ * <UserCard user={$users[selectedId]} />
204
+ * {/if}
205
+ * ```
206
+ */
207
+ export function lookup<T extends Record<string, any>>(
208
+ topic: string,
209
+ initial?: T[],
210
+ options?: { key?: keyof T & string }
211
+ ): Readable<Record<string, T>>;
212
+
213
+ /**
214
+ * Ring buffer of the last N events on a topic.
215
+ * Perfect for chat messages, activity feeds, and notification lists.
216
+ *
217
+ * @param topic - Topic to subscribe to
218
+ * @param max - Maximum number of events to keep (default: 50)
219
+ * @param initial - Starting data
220
+ *
221
+ * @example
222
+ * ```svelte
223
+ * <script>
224
+ * import { latest } from 'svelte-adapter-uws/client';
225
+ *
226
+ * const messages = latest('chat', 100);
227
+ * </script>
228
+ *
229
+ * {#each $messages as msg}
230
+ * <p><b>{msg.event}:</b> {msg.data.text}</p>
231
+ * {/each}
232
+ * ```
233
+ */
234
+ export function latest<T = unknown>(
235
+ topic: string,
236
+ max?: number,
237
+ initial?: WSEvent<T>[]
238
+ ): Readable<WSEvent<T>[]>;
239
+
240
+ /**
241
+ * Live counter store -- handles `set`, `increment`, and `decrement` events.
242
+ *
243
+ * Pair with `platform.topic('metric').publish('increment', 1)` on the server.
244
+ *
245
+ * @param topic - Topic to subscribe to
246
+ * @param initial - Starting value (default: 0)
247
+ *
248
+ * @example
249
+ * ```svelte
250
+ * <script>
251
+ * import { count } from 'svelte-adapter-uws/client';
252
+ * const online = count('online-users');
253
+ * </script>
254
+ *
255
+ * <p>{$online} users online</p>
256
+ * ```
257
+ */
258
+ export function count(topic: string, initial?: number): Readable<number>;
259
+
260
+ /**
261
+ * Wait for a specific event on a topic. Resolves once and unsubscribes.
262
+ *
263
+ * @param topic - Topic to listen on
264
+ * @param event - Optional event name to filter on
265
+ * @param options - Options (e.g. `{ timeout: 5000 }`)
266
+ *
267
+ * @example
268
+ * ```js
269
+ * import { once } from 'svelte-adapter-uws/client';
270
+ *
271
+ * // Wait for server confirmation after a form submit
272
+ * const result = await once('jobs', 'completed');
273
+ *
274
+ * // With a timeout (rejects if no event within 5s)
275
+ * const result = await once('jobs', 'completed', { timeout: 5000 });
276
+ *
277
+ * // Timeout without event filter
278
+ * const event = await once('jobs', { timeout: 5000 });
279
+ * ```
280
+ */
281
+ export function once<T = unknown>(topic: string, options?: { timeout?: number }): Promise<WSEvent<T>>;
282
+ export function once<T = unknown>(topic: string, event: string, options?: { timeout?: number }): Promise<T>;
283
+
284
+ /**
285
+ * Returns a promise that resolves when the WebSocket connection is open.
286
+ * Auto-connects if not already connected.
287
+ *
288
+ * @example
289
+ * ```js
290
+ * import { ready } from 'svelte-adapter-uws/client';
291
+ * await ready();
292
+ * // connection is now open
293
+ * ```
294
+ */
295
+ export function ready(): Promise<void>;
296
+
297
+ // ── Power-user API ──────────────────────────────────────────────────────────
298
+
299
+ export interface WSConnection {
300
+ /** Readable store - the latest event from any subscribed topic. */
301
+ events: Readable<WSEvent | null>;
302
+
303
+ /** Readable store - connection status. */
304
+ status: Readable<'connecting' | 'open' | 'closed'>;
305
+
306
+ /**
307
+ * Get a reactive store for a specific topic.
308
+ * Auto-subscribes to the topic.
309
+ */
310
+ on<T = unknown>(topic: string): TopicStore<WSEvent<T>>;
311
+
312
+ /**
313
+ * Subscribe to a topic. Duplicate calls are ignored.
314
+ * Subscriptions persist across reconnects.
315
+ *
316
+ * **Tip:** `on()` calls this automatically.
317
+ */
318
+ subscribe(topic: string): void;
319
+
320
+ /** Unsubscribe from a topic. */
321
+ unsubscribe(topic: string): void;
322
+
323
+ /**
324
+ * Send a custom message to the server.
325
+ * Dropped silently if not connected.
326
+ */
327
+ send(data: unknown): void;
328
+
329
+ /**
330
+ * Send a message, queuing it if not currently connected.
331
+ * Queued messages flush automatically on reconnect (FIFO order).
332
+ */
333
+ sendQueued(data: unknown): void;
334
+
335
+ /** Close the connection permanently. Will not auto-reconnect. */
336
+ close(): void;
337
+ }
338
+
339
+ /**
340
+ * Connect to the adapter's WebSocket server.
341
+ *
342
+ * Returns a **singleton**. Auto-connects and auto-reconnects.
343
+ *
344
+ * Most users should use `on()` and `status` directly - they auto-connect
345
+ * behind the scenes. Use `connect()` when you need `close()`, `send()`,
346
+ * or custom `ConnectOptions`.
347
+ *
348
+ * @example
349
+ * ```js
350
+ * import { connect } from 'svelte-adapter-uws/client';
351
+ * const ws = connect();
352
+ * ws.subscribe('notifications');
353
+ * ws.close(); // when done
354
+ * ```
355
+ */
356
+ export function connect(options?: ConnectOptions): WSConnection;