svelte-realtime 0.4.17 → 0.4.19

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 CHANGED
@@ -574,7 +574,7 @@ Same arguments return the same cached store instance. The cache is cleaned up wh
574
574
 
575
575
  ## Schema validation
576
576
 
577
- Use `live.validated(schema, fn)` to validate the first argument against a Zod or Valibot schema before the function runs.
577
+ Use `live.validated(schema, fn)` to validate the first argument against a schema before the function runs. Any [Standard Schema](https://standardschema.dev/)-compatible validator is supported, including Zod, ArkType, Valibot, and others.
578
578
 
579
579
  ```js
580
580
  import { z } from 'zod';
@@ -592,7 +592,22 @@ export const addTodo = live.validated(CreateTodo, async (ctx, input) => {
592
592
  });
593
593
  ```
594
594
 
595
- On the client, validated exports work like regular `live()` calls. Validation errors are thrown as `RpcError` with `code: 'VALIDATION'` and an `issues` array. Valibot schemas are also supported -- the adapter detects the schema type automatically.
595
+ Because `live.validated()` uses the [Standard Schema](https://standardschema.dev/) interface, you can swap in any compatible validator:
596
+
597
+ ```js
598
+ import { type } from 'arktype';
599
+ import { live } from 'svelte-realtime/server';
600
+
601
+ const CreateTodo = type({ text: 'string>0', priority: '"low"|"medium"|"high"|undefined' });
602
+
603
+ export const addTodo = live.validated(CreateTodo, async (ctx, input) => {
604
+ const todo = await db.todos.insert({ ...input, userId: ctx.user.id });
605
+ ctx.publish('todos', 'created', todo);
606
+ return todo;
607
+ });
608
+ ```
609
+
610
+ On the client, validated exports work like regular `live()` calls. Validation errors are thrown as `RpcError` with `code: 'VALIDATION'` and an `issues` array.
596
611
 
597
612
  ---
598
613
 
@@ -1948,7 +1963,7 @@ Import from `svelte-realtime/server`.
1948
1963
  | `live.stream(topic, initFn, options?)` | Create a reactive stream |
1949
1964
  | `live.channel(topic, options?)` | Create an ephemeral pub/sub channel |
1950
1965
  | `live.binary(fn, options?)` | Mark a function as a binary RPC handler (`maxSize` limits payload, default 10MB) |
1951
- | `live.validated(schema, fn)` | RPC with Zod/Valibot input validation |
1966
+ | `live.validated(schema, fn)` | RPC with [Standard Schema](https://standardschema.dev/) input validation (Zod, ArkType, Valibot, etc.) |
1952
1967
  | `live.cron(schedule, topic, fn)` | Server-side scheduled function |
1953
1968
  | `live.derived(sources, fn, options?)` | Server-side computed stream (static or dynamic sources) |
1954
1969
  | `live.effect(sources, fn, options?)` | Server-side reactive side effect |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-realtime",
3
- "version": "0.4.17",
3
+ "version": "0.4.19",
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
@@ -370,18 +370,29 @@ export namespace live {
370
370
  /**
371
371
  * Mark a function as RPC-callable with schema validation.
372
372
  * Validates args[0] against the schema before calling fn.
373
- * Supports Zod and Valibot schemas.
373
+ * Supports any [Standard Schema](https://standardschema.dev/)-compatible schema,
374
+ * including Zod, ArkType, Valibot v1+, and others.
374
375
  *
375
- * @param schema - Zod or Valibot schema
376
+ * @param schema - Zod, ArkType, Valibot, or any Standard Schema-compatible schema
376
377
  * @param fn - Handler function (ctx, validatedInput, ...rest)
377
378
  *
378
379
  * @example
379
380
  * ```js
381
+ * import { z } from 'zod';
380
382
  * const SendSchema = z.object({ text: z.string().min(1) });
381
383
  * export const send = live.validated(SendSchema, async (ctx, input) => {
382
384
  * // input is validated and typed
383
385
  * });
384
386
  * ```
387
+ *
388
+ * @example
389
+ * ```js
390
+ * import { type } from 'arktype';
391
+ * const SendSchema = type({ text: 'string>0' });
392
+ * export const send = live.validated(SendSchema, async (ctx, input) => {
393
+ * // works with any Standard Schema-compatible validator
394
+ * });
395
+ * ```
385
396
  */
386
397
  function validated<S, T extends (ctx: LiveContext<any>, input: any, ...args: any[]) => any>(
387
398
  schema: S,
package/server.js CHANGED
@@ -600,9 +600,10 @@ live.rateLimit = function rateLimit(config, fn) {
600
600
  /**
601
601
  * Mark a function as RPC-callable with schema validation.
602
602
  * Validates args[0] against the schema before calling fn.
603
- * Supports Zod (.safeParse method on schema) and Valibot (safeParse as standalone).
603
+ * Supports any Standard Schema-compatible schema (https://standardschema.dev/),
604
+ * including Zod, ArkType, Valibot v1+, and others.
604
605
  *
605
- * @param {any} schema - Zod or Valibot schema
606
+ * @param {any} schema - Zod, ArkType, Valibot, or any Standard Schema-compatible schema
606
607
  * @param {Function} fn - Handler function (ctx, validatedInput, ...rest)
607
608
  * @returns {Function}
608
609
  */
@@ -626,13 +627,36 @@ live.validated = function validated(schema, fn) {
626
627
  };
627
628
 
628
629
  /**
629
- * Validate input against a Zod or Valibot schema.
630
+ * Validate input against a Standard Schema-compatible schema, with legacy Zod/Valibot fallbacks.
630
631
  * @param {any} schema
631
632
  * @param {any} input
632
633
  * @returns {{ ok: true, data: any } | { ok: false, message: string, issues: Array<{ path: string[], message: string }> }}
633
634
  */
634
635
  function _validate(schema, input) {
635
- // Zod-style: schema has .safeParse method
636
+ // Standard Schema: schema exposes `~standard.validate` (https://standardschema.dev/)
637
+ if (schema?.['~standard'] && typeof schema['~standard'].validate === 'function') {
638
+ const result = schema['~standard'].validate(input);
639
+ if (result instanceof Promise) {
640
+ return {
641
+ ok: false,
642
+ message: 'Async schemas are not supported in live.validated(). Use a synchronous schema.',
643
+ issues: [{ path: [], message: 'Async schema not supported' }]
644
+ };
645
+ }
646
+ if (result.issues == null) {
647
+ return { ok: true, data: result.value };
648
+ }
649
+ const issues = result.issues.map((/** @type {any} */ i) => ({
650
+ path: (i.path || []).map((/** @type {any} */ p) => {
651
+ const key = typeof p === 'object' && p !== null && 'key' in p ? p.key : p;
652
+ return key != null ? String(key) : '';
653
+ }).filter((k) => k !== ''),
654
+ message: i.message || 'Validation failed'
655
+ }));
656
+ return { ok: false, message: 'Validation failed', issues };
657
+ }
658
+
659
+ // Zod legacy fallback: schema has .safeParse method
636
660
  if (typeof schema?.safeParse === 'function') {
637
661
  const result = schema.safeParse(input);
638
662
  if (result.success) {
@@ -649,7 +673,7 @@ function _validate(schema, input) {
649
673
  };
650
674
  }
651
675
 
652
- // Valibot-style: schema is passed to a standalone safeParse
676
+ // Valibot legacy fallback: schema is passed to a standalone safeParse
653
677
  // In Valibot v1, schemas have a ._run or .pipe method
654
678
  // Try to use the schema directly as a Valibot schema
655
679
  if (schema?._run || schema?.pipe || schema?.type) {
@@ -675,7 +699,7 @@ function _validate(schema, input) {
675
699
  // Unknown schema type -- reject. Passing unvalidated input through is a security risk.
676
700
  return {
677
701
  ok: false,
678
- message: 'Unrecognized schema type passed to live.validated(). Supported: Zod (.safeParse), Valibot (._run).',
702
+ message: 'Unrecognized schema type passed to live.validated(). Supported: Standard Schema (https://standardschema.dev/), Zod (.safeParse), Valibot (._run).',
679
703
  issues: [{ path: [], message: 'Unrecognized schema type' }]
680
704
  };
681
705
  }
@@ -1369,8 +1393,24 @@ export function __registerDerived(path, fn) {
1369
1393
  if (/** @type {any} */ (fn).__derivedDynamic) {
1370
1394
  const sourceFactory = /** @type {any} */ (fn).__derivedSourceFactory;
1371
1395
  const debounce = /** @type {any} */ (fn).__derivedDebounce || 0;
1396
+
1397
+ /** @type {Map<string, any[]>} */
1398
+ const topicArgs = new Map();
1399
+ const topicFn = (...args) => {
1400
+ const t = path + '\x00' + args.map(a => String(a).replace(/\x00/g, '')).join('\x00');
1401
+ topicArgs.set(t, args);
1402
+ if (topicArgs.size > 10000) {
1403
+ const iter = topicArgs.keys();
1404
+ topicArgs.delete(iter.next().value);
1405
+ }
1406
+ return t;
1407
+ };
1408
+ /** @type {any} */ (topicFn).__topicUsesCtx = false;
1409
+ /** @type {any} */ (fn).__streamTopic = topicFn;
1410
+ /** @type {any} */ (fn).__derivedTopicArgs = topicArgs;
1411
+
1372
1412
  const entry = {
1373
- sources: null, sourceFactory, fn, topic: /** @type {any} */ (fn).__streamTopic,
1413
+ sources: null, sourceFactory, fn, topic: topicFn,
1374
1414
  debounce, timer: null, dynamic: true, instances: new Map()
1375
1415
  };
1376
1416
  derivedRegistry.set(path, entry);
@@ -1379,11 +1419,11 @@ export function __registerDerived(path, fn) {
1379
1419
  return;
1380
1420
  }
1381
1421
 
1422
+ /** @type {any} */ (fn).__streamTopic = path;
1382
1423
  const sources = /** @type {any} */ (fn).__derivedSources;
1383
- const topic = /** @type {any} */ (fn).__streamTopic;
1384
1424
  const debounce = /** @type {any} */ (fn).__derivedDebounce || 0;
1385
- if (!sources || !topic) return;
1386
- derivedRegistry.set(path, { sources, fn, topic, debounce, timer: null });
1425
+ if (!sources) return;
1426
+ derivedRegistry.set(path, { sources, fn, topic: path, debounce, timer: null });
1387
1427
  for (const src of sources) {
1388
1428
  let set = _derivedBySource.get(src);
1389
1429
  if (!set) { set = new Set(); _derivedBySource.set(src, set); }