cogsbox-state 0.5.487 → 0.5.488

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cogsbox-state",
3
- "version": "0.5.487",
3
+ "version": "0.5.488",
4
4
  "description": "React state management library with form controls and server sync",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/CogsState.tsx CHANGED
@@ -383,7 +383,21 @@ export type StateObject<
383
383
  : {}) & // Fallback to {} since we intersect EndType below anyway
384
384
  EndType<T, TPlugins> & {
385
385
  $toggle: NonNullable<T> extends boolean ? () => void : never;
386
- $validate: () => { success: boolean; data?: T; error?: any };
386
+ $validate: {
387
+ (): { success: boolean; data?: T; error?: any };
388
+ <K extends Extract<keyof NonNullable<T>, string>>(
389
+ keys: readonly K[]
390
+ ): {
391
+ success: boolean;
392
+ results: Array<{
393
+ key: K;
394
+ path: string[];
395
+ success: boolean;
396
+ data?: unknown;
397
+ error?: any;
398
+ }>;
399
+ };
400
+ };
387
401
  $_componentId: string | null;
388
402
  $getComponents: () => ComponentsType;
389
403
  $_initialState: T;
@@ -2579,14 +2593,75 @@ function createProxyHandler<
2579
2593
  setShadowMetadata(stateKey, path, { ...currentMeta, isRaw: true });
2580
2594
  effectiveSetState(value, path, { updateType: 'update' });
2581
2595
  };
2582
- }
2583
-
2584
- if (prop === '$validate') {
2585
- return () => {
2586
- const store = getGlobalStore.getState();
2587
-
2588
- // 1. Get Data & Schema
2589
- const { value } = getScopedData(stateKey, path, meta);
2596
+ }
2597
+
2598
+ if (prop === '$validate') {
2599
+ return (keys?: readonly string[]) => {
2600
+ const store = getGlobalStore.getState();
2601
+
2602
+ if (keys) {
2603
+ const results = keys.map((key) => {
2604
+ const targetPath = [...path, key];
2605
+ const targetValue = store.getShadowValue(stateKey, targetPath);
2606
+ const currentMeta =
2607
+ store.getShadowMetadata(stateKey, targetPath) || {};
2608
+ const fieldSchema = currentMeta.typeInfo?.schema;
2609
+
2610
+ if (!fieldSchema) {
2611
+ return {
2612
+ key,
2613
+ path: targetPath,
2614
+ success: true,
2615
+ data: targetValue,
2616
+ };
2617
+ }
2618
+
2619
+ const result = (fieldSchema as any).safeParse(targetValue);
2620
+ const zodErrors =
2621
+ result.error?.issues || result.error?.errors || [];
2622
+
2623
+ store.setShadowMetadata(stateKey, targetPath, {
2624
+ ...currentMeta,
2625
+ validation: {
2626
+ status: result.success ? 'VALID' : 'INVALID',
2627
+ errors: result.success
2628
+ ? []
2629
+ : [
2630
+ {
2631
+ source: 'client',
2632
+ message:
2633
+ zodErrors[0]?.message || 'Invalid value',
2634
+ severity: 'error',
2635
+ code: zodErrors[0]?.code,
2636
+ },
2637
+ ],
2638
+ lastValidated: Date.now(),
2639
+ validatedValue: targetValue,
2640
+ },
2641
+ });
2642
+ store.notifyPathSubscribers([stateKey, ...targetPath].join('.'), {
2643
+ type: 'VALIDATION_UPDATE',
2644
+ });
2645
+
2646
+ return {
2647
+ key,
2648
+ path: targetPath,
2649
+ success: result.success,
2650
+ data: result.success ? result.data : undefined,
2651
+ error: result.success ? undefined : result.error,
2652
+ };
2653
+ });
2654
+
2655
+ notifyComponents(stateKey);
2656
+
2657
+ return {
2658
+ success: results.every((result) => result.success),
2659
+ results,
2660
+ };
2661
+ }
2662
+
2663
+ // 1. Get Data & Schema
2664
+ const { value } = getScopedData(stateKey, path, meta);
2590
2665
  const opts = store.getInitialOptions(stateKey);
2591
2666
  const schema =
2592
2667
  opts?.validation?.zodSchemaV4 || opts?.validation?.zodSchemaV3;