svelte-realtime 0.4.7 → 0.4.9

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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/server.d.ts +34 -34
  3. package/vite.js +30 -26
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-realtime",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "description": "Realtime RPC and reactive subscriptions for SvelteKit, built on svelte-adapter-uws",
5
5
  "author": "Kevin Radziszewski",
6
6
  "license": "MIT",
package/server.d.ts CHANGED
@@ -83,26 +83,26 @@ export interface StreamOptions {
83
83
  * Called when a client subscribes to this stream.
84
84
  * Receives the context and resolved topic string.
85
85
  */
86
- onSubscribe?(ctx: LiveContext, topic: string): void | Promise<void>;
86
+ onSubscribe?(ctx: LiveContext<any>, topic: string): void | Promise<void>;
87
87
 
88
88
  /**
89
89
  * Called when a client disconnects from this stream.
90
90
  * Fires for both static and dynamic topics.
91
91
  */
92
- onUnsubscribe?(ctx: LiveContext, topic: string): void | Promise<void>;
92
+ onUnsubscribe?(ctx: LiveContext<any>, topic: string): void | Promise<void>;
93
93
 
94
94
  /**
95
95
  * Subscribe-time access predicate. Checked once when a client subscribes.
96
96
  * Return `false` to deny the subscription with an "Access denied" error.
97
97
  * For per-event filtering, use `pipe.filter()`.
98
98
  */
99
- filter?(ctx: LiveContext): boolean;
99
+ filter?(ctx: LiveContext<any>): boolean;
100
100
 
101
101
  /**
102
102
  * Subscribe-time access predicate (alias for `filter`).
103
103
  * Use `live.access` helpers to build predicates.
104
104
  */
105
- access?(ctx: LiveContext): boolean;
105
+ access?(ctx: LiveContext<any>): boolean;
106
106
 
107
107
  /**
108
108
  * Schema version number. Increment when the data shape changes.
@@ -143,7 +143,7 @@ export interface HandleRpcOptions {
143
143
  * Called when an RPC handler throws a non-LiveError.
144
144
  * Use for error reporting (Sentry, logging, etc.).
145
145
  */
146
- onError?(path: string, error: unknown, ctx: LiveContext): void;
146
+ onError?(path: string, error: unknown, ctx: LiveContext<any>): void;
147
147
  }
148
148
 
149
149
  /**
@@ -171,7 +171,7 @@ export interface CreateMessageOptions {
171
171
  * Called when an RPC handler throws a non-LiveError.
172
172
  * Use for error reporting (Sentry, logging, etc.).
173
173
  */
174
- onError?(path: string, error: unknown, ctx: LiveContext): void;
174
+ onError?(path: string, error: unknown, ctx: LiveContext<any>): void;
175
175
 
176
176
  /**
177
177
  * Called when a message is not an RPC request.
@@ -195,7 +195,7 @@ export interface CreateMessageOptions {
195
195
  * });
196
196
  * ```
197
197
  */
198
- export function live<T extends (ctx: LiveContext, ...args: any[]) => any>(fn: T): T;
198
+ export function live<T extends (ctx: LiveContext<any>, ...args: any[]) => any>(fn: T): T;
199
199
 
200
200
  export namespace live {
201
201
  /**
@@ -212,7 +212,7 @@ export namespace live {
212
212
  * }, { merge: 'crud', key: 'id', prepend: true });
213
213
  * ```
214
214
  */
215
- function stream<T extends (ctx: LiveContext, ...args: any[]) => any>(
215
+ function stream<T extends (ctx: LiveContext<any>, ...args: any[]) => any>(
216
216
  topic: string,
217
217
  initFn: T,
218
218
  options?: StreamOptions
@@ -237,8 +237,8 @@ export namespace live {
237
237
  * );
238
238
  * ```
239
239
  */
240
- function stream<T extends (ctx: LiveContext, ...args: any[]) => any>(
241
- topicFn: (ctx: LiveContext, ...args: any[]) => string,
240
+ function stream<T extends (ctx: LiveContext<any>, ...args: any[]) => any>(
241
+ topicFn: (ctx: LiveContext<any>, ...args: any[]) => string,
242
242
  initFn: T,
243
243
  options?: StreamOptions
244
244
  ): T;
@@ -275,7 +275,7 @@ export namespace live {
275
275
  * ```
276
276
  */
277
277
  function channel(
278
- topicFn: (ctx: LiveContext, ...args: any[]) => string,
278
+ topicFn: (ctx: LiveContext<any>, ...args: any[]) => string,
279
279
  options?: { merge?: 'crud' | 'latest' | 'set' | 'presence' | 'cursor'; key?: string; max?: number }
280
280
  ): Function;
281
281
 
@@ -293,7 +293,7 @@ export namespace live {
293
293
  * });
294
294
  * ```
295
295
  */
296
- function binary<T extends (ctx: LiveContext, buffer: ArrayBuffer, ...args: any[]) => any>(
296
+ function binary<T extends (ctx: LiveContext<any>, buffer: ArrayBuffer, ...args: any[]) => any>(
297
297
  fn: T
298
298
  ): T;
299
299
 
@@ -314,7 +314,7 @@ export namespace live {
314
314
  * });
315
315
  * ```
316
316
  */
317
- function middleware(fn: (ctx: LiveContext, next: () => Promise<any>) => Promise<any>): void;
317
+ function middleware(fn: (ctx: LiveContext<any>, next: () => Promise<any>) => Promise<any>): void;
318
318
 
319
319
  /**
320
320
  * Wrap a stream with a server-side gate predicate.
@@ -333,7 +333,7 @@ export namespace live {
333
333
  * ```
334
334
  */
335
335
  function gate<T extends Function>(
336
- predicate: (ctx: LiveContext, ...args: any[]) => boolean,
336
+ predicate: (ctx: LiveContext<any>, ...args: any[]) => boolean,
337
337
  fn: T
338
338
  ): T;
339
339
 
@@ -353,14 +353,14 @@ export namespace live {
353
353
  * });
354
354
  * ```
355
355
  */
356
- function rateLimit<T extends (ctx: LiveContext, ...args: any[]) => any>(
356
+ function rateLimit<T extends (ctx: LiveContext<any>, ...args: any[]) => any>(
357
357
  config: {
358
358
  /** Maximum number of calls allowed within the window. */
359
359
  points: number;
360
360
  /** Time window in milliseconds. */
361
361
  window: number;
362
362
  /** Custom key function. Defaults to `ctx.user.id`. */
363
- key?(ctx: LiveContext): string;
363
+ key?(ctx: LiveContext<any>): string;
364
364
  },
365
365
  fn: T
366
366
  ): T;
@@ -381,7 +381,7 @@ export namespace live {
381
381
  * });
382
382
  * ```
383
383
  */
384
- function validated<S, T extends (ctx: LiveContext, input: any, ...args: any[]) => any>(
384
+ function validated<S, T extends (ctx: LiveContext<any>, input: any, ...args: any[]) => any>(
385
385
  schema: S,
386
386
  fn: T
387
387
  ): T;
@@ -572,15 +572,15 @@ export namespace live {
572
572
  */
573
573
  const access: {
574
574
  /** Only allow subscription if `ctx.user[field]` is present. Default field: `'id'`. */
575
- owner(field?: string): (ctx: LiveContext) => boolean;
575
+ owner(field?: string): (ctx: LiveContext<any>) => boolean;
576
576
  /** Role-based access: map role names to boolean or predicate. */
577
- role(map: Record<string, true | ((ctx: LiveContext) => boolean)>): (ctx: LiveContext) => boolean;
577
+ role(map: Record<string, true | ((ctx: LiveContext<any>) => boolean)>): (ctx: LiveContext<any>) => boolean;
578
578
  /** Only allow subscription if `ctx.user.teamId` is present. */
579
- team(): (ctx: LiveContext) => boolean;
579
+ team(): (ctx: LiveContext<any>) => boolean;
580
580
  /** OR logic: any predicate returning true allows the subscription. */
581
- any(...predicates: Array<(ctx: LiveContext) => boolean>): (ctx: LiveContext) => boolean;
581
+ any(...predicates: Array<(ctx: LiveContext<any>) => boolean>): (ctx: LiveContext<any>) => boolean;
582
582
  /** AND logic: all predicates must return true. */
583
- all(...predicates: Array<(ctx: LiveContext) => boolean>): (ctx: LiveContext) => boolean;
583
+ all(...predicates: Array<(ctx: LiveContext<any>) => boolean>): (ctx: LiveContext<any>) => boolean;
584
584
  };
585
585
  }
586
586
 
@@ -589,21 +589,21 @@ export namespace live {
589
589
  */
590
590
  export interface RoomConfig {
591
591
  /** Function that computes the room topic from context and args. */
592
- topic: (ctx: LiveContext, ...args: any[]) => string;
592
+ topic: (ctx: LiveContext<any>, ...args: any[]) => string;
593
593
  /** Function that returns initial data for the room. */
594
- init: (ctx: LiveContext, ...args: any[]) => Promise<any>;
594
+ init: (ctx: LiveContext<any>, ...args: any[]) => Promise<any>;
595
595
  /** Function that returns presence data for the connecting user. */
596
- presence?: (ctx: LiveContext) => any;
596
+ presence?: (ctx: LiveContext<any>) => any;
597
597
  /** Enable cursor tracking. Pass `true` or `{ throttle: ms }`. */
598
598
  cursors?: boolean | { throttle?: number };
599
599
  /** Room-scoped RPC actions. */
600
- actions?: Record<string, (ctx: LiveContext, ...args: any[]) => any>;
600
+ actions?: Record<string, (ctx: LiveContext<any>, ...args: any[]) => any>;
601
601
  /** Guard function run before data access and actions. */
602
- guard?: (ctx: LiveContext, ...args: any[]) => void | Promise<void>;
602
+ guard?: (ctx: LiveContext<any>, ...args: any[]) => void | Promise<void>;
603
603
  /** Called when a user joins the room. */
604
- onJoin?: (ctx: LiveContext, ...args: any[]) => void | Promise<void>;
604
+ onJoin?: (ctx: LiveContext<any>, ...args: any[]) => void | Promise<void>;
605
605
  /** Called when a user leaves the room. */
606
- onLeave?: (ctx: LiveContext, topic: string) => void | Promise<void>;
606
+ onLeave?: (ctx: LiveContext<any>, topic: string) => void | Promise<void>;
607
607
  /** Merge strategy for the data stream. @default 'crud' */
608
608
  merge?: string;
609
609
  /** Key field for the data stream. @default 'id' */
@@ -649,8 +649,8 @@ export interface WebhookHandler {
649
649
  * A stream transform step created by `pipe.filter`, `pipe.sort`, etc.
650
650
  */
651
651
  export interface PipeTransform {
652
- transformInit?(data: any[], ctx: LiveContext): any[] | Promise<any[]>;
653
- transformEvent?(ctx: LiveContext, event: string, data: any): boolean;
652
+ transformInit?(data: any[], ctx: LiveContext<any>): any[] | Promise<any[]>;
653
+ transformEvent?(ctx: LiveContext<any>, event: string, data: any): boolean;
654
654
  }
655
655
 
656
656
  /**
@@ -672,7 +672,7 @@ export interface PipeTransform {
672
672
  export function pipe<T extends Function>(stream: T, ...transforms: PipeTransform[]): T;
673
673
  export namespace pipe {
674
674
  /** Filter items from initial data and drop non-matching live events. */
675
- function filter(predicate: (ctx: LiveContext, item: any) => boolean): PipeTransform;
675
+ function filter(predicate: (ctx: LiveContext<any>, item: any) => boolean): PipeTransform;
676
676
  /** Sort initial data by a field. */
677
677
  function sort(field: string, direction?: 'asc' | 'desc'): PipeTransform;
678
678
  /** Cap initial data to N items. */
@@ -692,8 +692,8 @@ export namespace pipe {
692
692
  * ```
693
693
  */
694
694
  export function guard(
695
- ...fns: Array<(ctx: LiveContext) => void | Promise<void>>
696
- ): (ctx: LiveContext) => void | Promise<void>;
695
+ ...fns: Array<(ctx: LiveContext<any>) => void | Promise<void>>
696
+ ): (ctx: LiveContext<any>) => void | Promise<void>;
697
697
 
698
698
  /**
699
699
  * Typed error that propagates `code` and `message` to the client.
package/vite.js CHANGED
@@ -552,13 +552,14 @@ function _generateSsrStubs(filePath, modulePath) {
552
552
 
553
553
  for (const name of storeNames) {
554
554
  if (dynamicNames.has(name)) {
555
- // Dynamic stream: return a readable store from a function so name(args) works during SSR
556
- lines.push(`const _${name} = (...args) => readable(undefined);`);
555
+ // Dynamic stream: factory returns a readable with .hydrate() for SSR rendering
556
+ lines.push(`const _${name} = (...args) => { const s = readable(undefined); s.hydrate = (d) => readable(d); return s; };`);
557
557
  lines.push(`_${name}.load = (platform, options) => __directCall(${safeModulePath(name)}, options?.args || [], platform, options);`);
558
558
  lines.push(`export { _${name} as ${name} };`);
559
559
  } else {
560
- // Static stream: plain readable store
560
+ // Static stream: readable with .hydrate() for SSR rendering
561
561
  lines.push(`const _${name} = readable(undefined);`);
562
+ lines.push(`_${name}.hydrate = (d) => readable(d);`);
562
563
  lines.push(`_${name}.load = (platform, options) => __directCall(${safeModulePath(name)}, options?.args || [], platform, options);`);
563
564
  lines.push(`export { _${name} as ${name} };`);
564
565
  }
@@ -1551,7 +1552,7 @@ function _generateTypeDeclarations(liveDir, dir) {
1551
1552
  const exports = [];
1552
1553
  /** @type {Set<string>} */
1553
1554
  const handledNames = new Set();
1554
- let needsReadable = false;
1555
+ let needsStreamStore = false;
1555
1556
  let needsRpcError = false;
1556
1557
 
1557
1558
  // Detect live() exports
@@ -1597,23 +1598,25 @@ function _generateTypeDeclarations(liveDir, dir) {
1597
1598
  while ((match = STREAM_EXPORT_RE.exec(source)) !== null) {
1598
1599
  const name = match[1];
1599
1600
  handledNames.add(name);
1600
- needsReadable = true;
1601
+ needsStreamStore = true;
1601
1602
  needsRpcError = true;
1602
1603
  const isDynamic = _isDynamicExport(source, name, 'live\\.stream');
1603
1604
  if (isTS) {
1604
1605
  const returnType = _extractStreamReturnType(source, name);
1605
- const storeType = `Readable<${returnType} | undefined | { error: RpcError }>`;
1606
+ const storeType = `StreamStore<${returnType} | undefined | { error: RpcError }>`;
1607
+ const loadSig = `{ load(platform: any, options?: { args?: any[] }): Promise<${returnType}> }`;
1606
1608
  if (isDynamic) {
1607
1609
  const factoryParams = _extractDynamicFactoryParams(source, name, 'live\\.stream');
1608
- exports.push(` export const ${name}: ${factoryParams} => ${storeType};`);
1610
+ exports.push(` export const ${name}: (${factoryParams} => ${storeType}) & ${loadSig};`);
1609
1611
  } else {
1610
- exports.push(` export const ${name}: ${storeType};`);
1612
+ exports.push(` export const ${name}: ${storeType} & ${loadSig};`);
1611
1613
  }
1612
1614
  } else {
1615
+ const loadSig = `{ load(platform: any, options?: { args?: any[] }): Promise<any> }`;
1613
1616
  if (isDynamic) {
1614
- exports.push(` export const ${name}: (...args: any[]) => Readable<any>;`);
1617
+ exports.push(` export const ${name}: ((...args: any[]) => StreamStore<any>) & ${loadSig};`);
1615
1618
  } else {
1616
- exports.push(` export const ${name}: Readable<any>;`);
1619
+ exports.push(` export const ${name}: StreamStore<any> & ${loadSig};`);
1617
1620
  }
1618
1621
  }
1619
1622
  }
@@ -1624,17 +1627,18 @@ function _generateTypeDeclarations(liveDir, dir) {
1624
1627
  const name = match[1];
1625
1628
  handledNames.add(name);
1626
1629
  if (!exports.some(e => e.includes(`export const ${name}:`))) {
1627
- needsReadable = true;
1630
+ needsStreamStore = true;
1628
1631
  const isDynamic = _isDynamicExport(source, name, 'live\\.channel');
1632
+ const loadSig = `{ load(platform: any, options?: { args?: any[] }): Promise<any> }`;
1629
1633
  if (isDynamic) {
1630
1634
  if (isTS) {
1631
1635
  const factoryParams = _extractDynamicFactoryParams(source, name, 'live\\.channel');
1632
- exports.push(` export const ${name}: ${factoryParams} => Readable<any>;`);
1636
+ exports.push(` export const ${name}: (${factoryParams} => StreamStore<any>) & ${loadSig};`);
1633
1637
  } else {
1634
- exports.push(` export const ${name}: (...args: any[]) => Readable<any>;`);
1638
+ exports.push(` export const ${name}: ((...args: any[]) => StreamStore<any>) & ${loadSig};`);
1635
1639
  }
1636
1640
  } else {
1637
- exports.push(` export const ${name}: Readable<any>;`);
1641
+ exports.push(` export const ${name}: StreamStore<any> & ${loadSig};`);
1638
1642
  }
1639
1643
  }
1640
1644
  }
@@ -1645,8 +1649,8 @@ function _generateTypeDeclarations(liveDir, dir) {
1645
1649
  const name = match[1];
1646
1650
  handledNames.add(name);
1647
1651
  if (!exports.some(e => e.includes(`export const ${name}:`))) {
1648
- needsReadable = true;
1649
- exports.push(` export const ${name}: Readable<any>;`);
1652
+ needsStreamStore = true;
1653
+ exports.push(` export const ${name}: StreamStore<any> & { load(platform: any, options?: { args?: any[] }): Promise<any> };`);
1650
1654
  }
1651
1655
  }
1652
1656
 
@@ -1656,8 +1660,8 @@ function _generateTypeDeclarations(liveDir, dir) {
1656
1660
  const name = match[1];
1657
1661
  handledNames.add(name);
1658
1662
  if (!exports.some(e => e.includes(`export const ${name}:`))) {
1659
- needsReadable = true;
1660
- exports.push(` export const ${name}: Readable<any>;`);
1663
+ needsStreamStore = true;
1664
+ exports.push(` export const ${name}: StreamStore<any> & { load(platform: any, options?: { args?: any[] }): Promise<any> };`);
1661
1665
  }
1662
1666
  }
1663
1667
 
@@ -1692,8 +1696,8 @@ function _generateTypeDeclarations(liveDir, dir) {
1692
1696
  const name = match[1];
1693
1697
  handledNames.add(name);
1694
1698
  if (!exports.some(e => e.includes(`export const ${name}:`))) {
1695
- needsReadable = true;
1696
- exports.push(` export const ${name}: { data: (...args: any[]) => Readable<any>, presence?: (...args: any[]) => Readable<any>, cursors?: (...args: any[]) => Readable<any>, [action: string]: (...args: any[]) => Promise<any> | ((...args: any[]) => Readable<any>) };`);
1699
+ needsStreamStore = true;
1700
+ exports.push(` export const ${name}: { data: (...args: any[]) => StreamStore<any>, presence?: (...args: any[]) => StreamStore<any>, cursors?: (...args: any[]) => StreamStore<any>, [action: string]: (...args: any[]) => Promise<any> | ((...args: any[]) => StreamStore<any>) };`);
1697
1701
  }
1698
1702
  }
1699
1703
 
@@ -1702,13 +1706,13 @@ function _generateTypeDeclarations(liveDir, dir) {
1702
1706
 
1703
1707
  if (exports.length > 0) {
1704
1708
  declarations.push(`declare module '$live/${rel}' {`);
1705
- if (needsReadable) {
1706
- declarations.push(" import type { Readable } from 'svelte/store';");
1709
+ if (needsStreamStore || needsRpcError) {
1710
+ const clientImports = [];
1711
+ if (needsStreamStore) clientImports.push('StreamStore');
1712
+ if (needsRpcError) clientImports.push('RpcError');
1713
+ declarations.push(` import type { ${clientImports.join(', ')} } from 'svelte-realtime/client';`);
1707
1714
  }
1708
- if (needsRpcError) {
1709
- declarations.push(" import type { RpcError } from 'svelte-realtime/client';");
1710
- }
1711
- if (needsReadable || needsRpcError) {
1715
+ if (needsStreamStore || needsRpcError) {
1712
1716
  declarations.push('');
1713
1717
  }
1714
1718
  declarations.push(...exports);