cogsbox-state 0.5.476 → 0.5.479

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/src/CogsState.tsx CHANGED
@@ -1,6 +1,10 @@
1
1
  'use client';
2
2
  import { pluginStore } from './pluginStore';
3
- import { FormWrapperParams, type CogsPlugin } from './plugins';
3
+ import {
4
+ FormWrapperParams,
5
+ type ChainMethodCallables,
6
+ type CogsPlugin,
7
+ } from './plugins';
4
8
  import {
5
9
  createElement,
6
10
  startTransition,
@@ -79,7 +83,8 @@ type CutFunctionType<T> = (
79
83
  options?: { waitForSync?: boolean }
80
84
  ) => StateObject<T>;
81
85
 
82
- export type InferArrayElement<T> = T extends (infer U)[] ? U : never;
86
+ export type InferArrayElement<T> =
87
+ NonNullable<T> extends (infer U)[] ? U : never;
83
88
 
84
89
  export type FormControl<T> = (obj: FormElementParams<T>) => JSX.Element;
85
90
 
@@ -95,7 +100,15 @@ export type InsertTypeObj<T> = (payload: InsertParams<T>) => void;
95
100
  type EffectFunction<T, R> = (state: T, deps: any[]) => R;
96
101
  export type PerPathFormOptsType<
97
102
  TState,
98
- TPlugins extends readonly CogsPlugin<any, any, any, any, any>[] = [],
103
+ TPlugins extends readonly CogsPlugin<
104
+ any,
105
+ any,
106
+ any,
107
+ any,
108
+ any,
109
+ any,
110
+ any
111
+ >[] = [],
99
112
  > = Omit<FormOptsType, 'formElements'> & {
100
113
  formElements?: FormsElementsType<TState, TPlugins>;
101
114
  };
@@ -123,7 +136,15 @@ export type ArrayElementExtras<TParentArray = unknown> = {
123
136
  // EndType - NO $cutThis here, it's purely contextual
124
137
  export type EndType<
125
138
  T,
126
- TPlugins extends readonly CogsPlugin<any, any, any, any, any>[] = [],
139
+ TPlugins extends readonly CogsPlugin<
140
+ any,
141
+ any,
142
+ any,
143
+ any,
144
+ any,
145
+ any,
146
+ any
147
+ >[] = [],
127
148
  > = {
128
149
  $getPluginMetaData: (pluginName: string) => Record<string, any>;
129
150
  $addPluginMetaData: (key: string, data: Record<string, any>) => void;
@@ -175,6 +196,7 @@ export type EndType<
175
196
  selectText: () => void;
176
197
  };
177
198
  $removeStorage: () => void;
199
+ $setRaw: (value: T) => void;
178
200
  $sync: () => void;
179
201
  $validationWrapper: ({
180
202
  children,
@@ -190,12 +212,20 @@ export type EndType<
190
212
  export type ArrayElementState<
191
213
  TElement,
192
214
  TParentArray,
193
- TPlugins extends readonly CogsPlugin<any, any, any, any, any>[] = [],
215
+ TPlugins extends readonly CogsPlugin<
216
+ any,
217
+ any,
218
+ any,
219
+ any,
220
+ any,
221
+ any,
222
+ any
223
+ >[] = [],
194
224
  > = StateObject<TElement, TPlugins> & ArrayElementExtras<TParentArray>;
195
225
 
196
226
  export type ArrayEndType<
197
227
  TShape extends unknown,
198
- TPlugins extends readonly CogsPlugin<any, any, any, any, any>[],
228
+ TPlugins extends readonly CogsPlugin<any, any, any, any, any, any, any>[],
199
229
  > = {
200
230
  (): TShape;
201
231
  (newValue: TShape | ((prev: TShape) => TShape)): void;
@@ -299,24 +329,33 @@ export type ArrayEndType<
299
329
 
300
330
  export type StateObject<
301
331
  T,
302
- TPlugins extends readonly CogsPlugin<any, any, any, any, any>[] = [],
332
+ TPlugins extends readonly CogsPlugin<
333
+ any,
334
+ any,
335
+ any,
336
+ any,
337
+ any,
338
+ any,
339
+ any
340
+ >[] = [],
303
341
  > = {
304
342
  (): T;
305
343
  (newValue: T | ((prev: T) => T)): void;
306
- } & (T extends any[]
344
+ } & ([NonNullable<T>] extends [any[]] // <-- Wrap in brackets
307
345
  ? ArrayEndType<T, TPlugins>
308
- : T extends Record<string, unknown> | object
309
- ? { [K in keyof T]-?: StateObject<T[K], TPlugins> }
310
- : EndType<T, TPlugins>) & // primitives just get EndType
346
+ : [NonNullable<T>] extends [Record<string, unknown> | object] // <-- Wrap in brackets
347
+ ? {
348
+ [K in keyof NonNullable<T>]-?: StateObject<NonNullable<T>[K], TPlugins>;
349
+ }
350
+ : {}) & // Fallback to {} since we intersect EndType below anyway
311
351
  EndType<T, TPlugins> & {
312
- // NO third param = no $cutThis
313
- $toggle: T extends boolean ? () => void : never;
352
+ $toggle: NonNullable<T> extends boolean ? () => void : never;
314
353
  $validate: () => { success: boolean; data?: T; error?: any };
315
354
  $_componentId: string | null;
316
355
  $getComponents: () => ComponentsType;
317
356
  $_initialState: T;
318
357
  $updateInitialState: (newState: T | null) => {
319
- fetchId: (field: keyof T) => string | number;
358
+ fetchId: (field: keyof NonNullable<T>) => string | number;
320
359
  };
321
360
  $initializeAndMergeShadowState: (newState: any | null) => void;
322
361
  $_isLoading: boolean;
@@ -332,10 +371,23 @@ export type StateObject<
332
371
  }) => void
333
372
  ) => void;
334
373
  $getLocalStorage: (key: string) => LocalStorageData<T> | null;
335
- };
336
-
374
+ } & PluginChainMethodCallables<TPlugins>;
337
375
  export type CogsUpdate<T extends unknown> = UpdateType<T>;
338
376
 
377
+ type UnionToIntersection<T> = (
378
+ T extends any ? (arg: T) => void : never
379
+ ) extends (arg: infer I) => void
380
+ ? I
381
+ : never;
382
+
383
+ type PluginChainMethodCallables<
384
+ TPlugins extends readonly CogsPlugin<any, any, any, any, any, any, any>[],
385
+ > = UnionToIntersection<
386
+ TPlugins[number] extends CogsPlugin<any, any, any, any, any, infer TMethods>
387
+ ? ChainMethodCallables<TMethods>
388
+ : {}
389
+ >;
390
+
339
391
  type EffectiveSetStateArg<
340
392
  T,
341
393
  UpdateType extends 'update' | 'insert' | 'cut',
@@ -407,7 +459,15 @@ type SyncOptionsType<TApiParams> = {
407
459
 
408
460
  export type CreateStateOptionsType<
409
461
  T extends unknown = unknown,
410
- TPlugins extends readonly CogsPlugin<any, any, any, any, any>[] = [],
462
+ TPlugins extends readonly CogsPlugin<
463
+ any,
464
+ any,
465
+ any,
466
+ any,
467
+ any,
468
+ any,
469
+ any
470
+ >[] = [],
411
471
  > = {
412
472
  formElements?: FormsElementsType<T, TPlugins>;
413
473
  validation?: ValidationOptionsType;
@@ -470,7 +530,15 @@ type ScopedPluginApi<THookReturn, TFieldMetaData> = {
470
530
  };
471
531
  export type FormsElementsType<
472
532
  TState,
473
- TPlugins extends readonly CogsPlugin<any, any, any, any, any>[] = [],
533
+ TPlugins extends readonly CogsPlugin<
534
+ any,
535
+ any,
536
+ any,
537
+ any,
538
+ any,
539
+ any,
540
+ any
541
+ >[] = [],
474
542
  > = {
475
543
  // These optional, built-in wrappers are unchanged.
476
544
  validation?: (options: {
@@ -504,16 +572,6 @@ export type FormsElementsType<
504
572
  key?: string;
505
573
  }) => React.ReactNode;
506
574
  };
507
- export type CogsInitialState<T> =
508
- | {
509
- initialState: T;
510
- }
511
- | CreateStateOptionsType<T>;
512
-
513
- export type TransformedStateType<T> = {
514
- [P in keyof T]: T[P] extends CogsInitialState<infer U> ? U : T[P];
515
- };
516
-
517
575
  const {
518
576
  getInitialOptions,
519
577
  updateInitialStateGlobal,
@@ -692,18 +750,8 @@ function setOptions<StateKey, Opt>({
692
750
 
693
751
  return mergedOptions;
694
752
  }
695
- export function addStateOptions<T>(
696
- initialState: T,
697
- options: CreateStateOptionsType<T>
698
- ) {
699
- return {
700
- ...options,
701
- initialState,
702
- _addStateOptions: true,
703
- };
704
- }
705
753
  export type PluginData = {
706
- plugin: CogsPlugin<any, any, any, any, any>;
754
+ plugin: CogsPlugin<any, any, any, any, any, any, any>;
707
755
  options: any;
708
756
  hookData?: any;
709
757
  };
@@ -712,7 +760,15 @@ export type PluginData = {
712
760
 
713
761
  export const createCogsState = <
714
762
  State extends Record<string, unknown>,
715
- const TPlugins extends readonly CogsPlugin<string, any, any, any, any>[] = [],
763
+ const TPlugins extends readonly CogsPlugin<
764
+ string,
765
+ any,
766
+ any,
767
+ any,
768
+ any,
769
+ any,
770
+ any
771
+ >[] = [],
716
772
  >(
717
773
  initialState: State,
718
774
  opt?: {
@@ -721,60 +777,92 @@ export const createCogsState = <
721
777
  validation?: ValidationOptionsType;
722
778
  }
723
779
  ) => {
724
- type PluginOptions = {
725
- [K in TPlugins[number] as K['name']]?: K extends CogsPlugin<
726
- string,
727
- infer O,
728
- any,
729
- any,
730
- any
731
- >
780
+ type ExtractPluginOptions<T> = T extends {
781
+ useHook?: (params: { options: infer O }) => any; // infers O here
782
+ }
783
+ ? O
784
+ : T extends CogsPlugin<string, infer O, any, any, any, any, any> // AND here
732
785
  ? O
733
786
  : never;
787
+
788
+ type PluginOptions = {
789
+ [K in TPlugins[number] as K['name']]?: ExtractPluginOptions<K>;
734
790
  };
735
791
 
736
792
  if (opt?.plugins) {
737
793
  pluginStore.getState().setRegisteredPlugins(opt.plugins as any);
738
794
  }
795
+ type UnionToIntersection<U> = (
796
+ U extends any ? (k: U) => void : never
797
+ ) extends (k: infer I) => void
798
+ ? I
799
+ : never;
800
+
801
+ // Extract plugin initial state from the CogsPlugin generic (7th param) first,
802
+ // falling back to structural inference from initialState() return type.
803
+ type ExtractPluginState<T> = T extends CogsPlugin<
804
+ string,
805
+ any,
806
+ any,
807
+ any,
808
+ any,
809
+ any,
810
+ infer S
811
+ >
812
+ ? S extends Record<string, unknown>
813
+ ? S
814
+ : {}
815
+ : T extends {
816
+ initialState?: () => infer S;
817
+ }
818
+ ? S extends Record<string, unknown>
819
+ ? S
820
+ : {}
821
+ : {};
822
+
823
+ // Extract the merged plugin states into a helper type
824
+ type PluginStates = UnionToIntersection<ExtractPluginState<TPlugins[number]>>;
825
+
826
+ // User keys win over plugin keys — omit overlapping plugin keys before merging.
827
+ type FullState = Prettify<
828
+ State & {
829
+ [K in keyof PluginStates as K extends keyof State
830
+ ? never
831
+ : K]: PluginStates[K];
832
+ }
833
+ >;
834
+ const pluginState: Record<string, unknown> = {};
835
+ if (opt?.plugins) {
836
+ for (const plugin of opt.plugins) {
837
+ if (typeof plugin.initialState === 'function') {
838
+ Object.assign(pluginState, plugin.initialState());
839
+ }
840
+ }
841
+ }
842
+
843
+ const mergedInitialState = { ...pluginState, ...initialState } as FullState;
739
844
 
740
845
  const [statePart, initialOptionsPart] =
741
- transformStateFunc<State>(initialState);
846
+ transformStateFunc<FullState>(mergedInitialState);
742
847
 
743
- // FIX: Store options INCLUDING validation for each state key
744
848
  Object.keys(statePart).forEach((key) => {
745
- let existingOptions = initialOptionsPart[key] || {};
746
-
747
- const mergedOptions: any = {
748
- ...existingOptions,
749
- };
849
+ let mergedOptions: any = {};
750
850
 
751
851
  if (opt?.formElements) {
752
- mergedOptions.formElements = {
753
- ...opt.formElements,
754
- ...(existingOptions.formElements || {}),
755
- };
852
+ mergedOptions.formElements = opt.formElements;
756
853
  }
757
854
 
758
855
  mergedOptions.validation = {
759
856
  onBlur: 'error',
760
857
  ...opt?.validation,
761
- ...(existingOptions.validation || {}),
762
858
  };
763
859
 
764
- if (opt?.validation?.key && !existingOptions.validation?.key) {
765
- mergedOptions.validation.key = `${opt.validation.key}.${key}`;
766
- }
767
-
768
860
  const existingGlobalOptions = getInitialOptions(key);
769
861
 
770
862
  const finalOptions = existingGlobalOptions
771
863
  ? {
772
864
  ...existingGlobalOptions,
773
- ...mergedOptions,
774
- formElements: {
775
- ...existingGlobalOptions.formElements,
776
- ...mergedOptions.formElements,
777
- },
865
+ formElements: opt?.formElements,
778
866
  validation: {
779
867
  ...existingGlobalOptions.validation,
780
868
  ...mergedOptions.validation,
@@ -782,35 +870,56 @@ export const createCogsState = <
782
870
  }
783
871
  : mergedOptions;
784
872
 
785
- setInitialStateOptions(key, finalOptions);
873
+ if (Object.keys(finalOptions).length > 0) {
874
+ setInitialStateOptions(key, finalOptions);
875
+ }
786
876
  });
787
877
 
788
878
  Object.keys(statePart).forEach((key) => {
789
879
  initializeShadowState(key, statePart[key]);
790
880
  });
791
- type Prettify<T> = {
792
- [K in keyof T]: T[K];
793
- } & {};
794
- type StateKeys = keyof typeof statePart;
881
+ type StateKeys = keyof FullState;
882
+
883
+ // Flattens the 4x spam into a single clean object
884
+ type CleanIntersection<T> = T extends object ? { [K in keyof T]: T[K] } : T;
885
+
886
+ // Helper to find which keys are "keyed" (like queryParams)
887
+ type KeyedKeys<P> = {
888
+ [K in keyof P]-?: NonNullable<P[K]> extends { __key: 'keyed'; map: any }
889
+ ? K
890
+ : never;
891
+ }[keyof P];
892
+
893
+ type StateSlice<StateKey extends StateKeys> = FullState[StateKey];
795
894
 
796
895
  const useCogsState = <StateKey extends StateKeys>(
797
896
  stateKey: StateKey,
798
897
  options?: Prettify<
799
- OptionsType<(typeof statePart)[StateKey], never> & {
898
+ OptionsType<StateSlice<StateKey>, never> & {
800
899
  [PName in keyof PluginOptions]?: PluginOptions[PName] extends infer P
801
900
  ? P extends Record<string, any>
802
- ? {
803
- [K in keyof P]: P[K] extends { __key: 'keyed'; map: infer TMap }
804
- ? StateKey extends keyof TMap
805
- ? TMap[StateKey]
806
- : never
807
- : P[K];
808
- }
901
+ ? Prettify<
902
+ Partial<Pick<P, Exclude<keyof P, KeyedKeys<P>>>> & {
903
+ [K in KeyedKeys<P> as StateKey extends keyof NonNullable<
904
+ P[K]
905
+ >['map']
906
+ ? NonNullable<P[K]>['map'][StateKey] extends undefined
907
+ ? never
908
+ : keyof NonNullable<P[K]>['map'][StateKey] extends never
909
+ ? never
910
+ : K
911
+ : never]: CleanIntersection<
912
+ StateKey extends keyof NonNullable<P[K]>['map']
913
+ ? NonNullable<P[K]>['map'][StateKey]
914
+ : never
915
+ >;
916
+ }
917
+ >
809
918
  : P
810
919
  : never;
811
920
  }
812
921
  >
813
- ) => {
922
+ ): StateObject<StateSlice<StateKey>> => {
814
923
  const [componentId] = useState(options?.componentId ?? uuidv4());
815
924
 
816
925
  const currentOptions = setOptions({
@@ -825,21 +934,18 @@ export const createCogsState = <
825
934
  const thiState =
826
935
  getShadowValue(stateKey as string, []) || statePart[stateKey as string];
827
936
 
828
- const updater = useCogsStateFn<(typeof statePart)[StateKey], TPlugins>(
829
- thiState,
830
- {
831
- stateKey: stateKey as string,
832
- syncUpdate: options?.syncUpdate,
833
- componentId,
834
- localStorage: options?.localStorage,
835
- middleware: options?.middleware,
836
- reactiveType: options?.reactiveType,
837
- reactiveDeps: options?.reactiveDeps,
838
- defaultState: options?.defaultState as any,
839
- dependencies: options?.dependencies,
840
- serverState: options?.serverState,
841
- }
842
- );
937
+ const updater = useCogsStateFn<StateSlice<StateKey>>(thiState, {
938
+ stateKey: stateKey as string,
939
+ syncUpdate: options?.syncUpdate,
940
+ componentId,
941
+ localStorage: options?.localStorage,
942
+ middleware: options?.middleware,
943
+ reactiveType: options?.reactiveType,
944
+ reactiveDeps: options?.reactiveDeps,
945
+ defaultState: options?.defaultState as any,
946
+ dependencies: options?.dependencies,
947
+ serverState: options?.serverState,
948
+ });
843
949
 
844
950
  useEffect(() => {
845
951
  if (options) {
@@ -858,14 +964,14 @@ export const createCogsState = <
858
964
  };
859
965
  }, [stateKey, updater]);
860
966
 
861
- return updater;
967
+ return updater as StateObject<StateSlice<StateKey>>;
862
968
  };
863
969
 
864
970
  function setCogsOptionsByKey<StateKey extends StateKeys>(
865
971
  stateKey: StateKey,
866
- options: CreateStateOptionsType<(typeof statePart)[StateKey], TPlugins> &
972
+ options: CreateStateOptionsType<StateSlice<StateKey>, TPlugins> &
867
973
  Omit<
868
- OptionsType<(typeof statePart)[StateKey]>,
974
+ OptionsType<StateSlice<StateKey>>,
869
975
  keyof CreateStateOptionsType
870
976
  >
871
977
  ) {
@@ -984,6 +1090,18 @@ const loadFromLocalStorage = (localStorageKey: string) => {
984
1090
  return null;
985
1091
  }
986
1092
  };
1093
+
1094
+ const removeFromLocalStorage = (localStorageKey?: string) => {
1095
+ if (!localStorageKey) return;
1096
+
1097
+ try {
1098
+ if (typeof window !== 'undefined' && window.localStorage) {
1099
+ window.localStorage.removeItem(localStorageKey);
1100
+ }
1101
+ } catch (error) {
1102
+ console.error('Error removing from localStorage:', error);
1103
+ }
1104
+ };
987
1105
  const loadAndApplyLocalStorage = (stateKey: string, options: any) => {
988
1106
  const currentState = getShadowValue(stateKey, []);
989
1107
  const { sessionId } = useCogsConfig();
@@ -1210,7 +1328,7 @@ function getComponentNotifications(
1210
1328
  const pathMeta = getShadowMetadata(stateKey, currentPath);
1211
1329
 
1212
1330
  if (pathMeta?.pathComponents) {
1213
- pathMeta.pathComponents.forEach((componentId: string) => {
1331
+ pathMeta.pathComponents.forEach((componentId) => {
1214
1332
  const component = rootMeta.components?.get(componentId);
1215
1333
  if (component) {
1216
1334
  componentsToNotify.add(component);
@@ -1499,7 +1617,15 @@ function createEffectiveSetState<T>(
1499
1617
 
1500
1618
  export function useCogsStateFn<
1501
1619
  TStateObject extends unknown,
1502
- const TPlugins extends readonly CogsPlugin<any, any, any, any, any>[],
1620
+ const TPlugins extends readonly CogsPlugin<
1621
+ any,
1622
+ any,
1623
+ any,
1624
+ any,
1625
+ any,
1626
+ any,
1627
+ any
1628
+ >[] = [],
1503
1629
  >(
1504
1630
  stateObject: TStateObject,
1505
1631
  {
@@ -1959,9 +2085,72 @@ function getScopedData(stateKey: string, path: string[], meta?: MetaData) {
1959
2085
  };
1960
2086
  }
1961
2087
 
2088
+ function pathMatchesPattern(path: string[], pattern?: string[]) {
2089
+ if (!pattern) return true;
2090
+ if (path.length !== pattern.length) return false;
2091
+
2092
+ return pattern.every((segment, index) => {
2093
+ return segment === '*' || segment === path[index];
2094
+ });
2095
+ }
2096
+
2097
+ function valueMatchesChainTarget(value: any, target: string) {
2098
+ if (target === 'any') return true;
2099
+ if (target === 'array') return Array.isArray(value);
2100
+ if (target === 'boolean') return typeof value === 'boolean';
2101
+ if (target === 'object') {
2102
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
2103
+ }
2104
+ if (target === 'primitive') {
2105
+ return (
2106
+ value === null || (typeof value !== 'object' && !Array.isArray(value))
2107
+ );
2108
+ }
2109
+ return false;
2110
+ }
2111
+
2112
+ function getFieldRefsForPath(stateKey: string, path: string[]) {
2113
+ const meta = getGlobalStore.getState().getShadowMetadata(stateKey, path);
2114
+ if (!meta?.clientActivityState?.elements) return [];
2115
+ const refs: RefObject<any>[] = [];
2116
+ meta.clientActivityState.elements.forEach((entry: any) => {
2117
+ if (entry.domRef?.current) refs.push(entry.domRef);
2118
+ });
2119
+ return refs;
2120
+ }
2121
+
2122
+ function getFieldElementsForPath(stateKey: string, path: string[]) {
2123
+ const refs = getFieldRefsForPath(stateKey, path);
2124
+ return refs.map((ref) => ref.current).filter(Boolean);
2125
+ }
2126
+
2127
+ function setFieldDisabledForPath(
2128
+ stateKey: string,
2129
+ path: string[],
2130
+ disabled: boolean
2131
+ ) {
2132
+ getFieldElementsForPath(stateKey, path).forEach((el: any) => {
2133
+ if ('disabled' in el) {
2134
+ el.disabled = disabled;
2135
+ return;
2136
+ }
2137
+
2138
+ el.style.pointerEvents = disabled ? 'none' : '';
2139
+ el.setAttribute('aria-disabled', String(disabled));
2140
+ });
2141
+ }
2142
+
1962
2143
  function createProxyHandler<
1963
2144
  T,
1964
- const TPlugins extends readonly CogsPlugin<any, any, any, any, any>[],
2145
+ const TPlugins extends readonly CogsPlugin<
2146
+ any,
2147
+ any,
2148
+ any,
2149
+ any,
2150
+ any,
2151
+ any,
2152
+ any
2153
+ >[],
1965
2154
  >(
1966
2155
  stateKey: string,
1967
2156
  effectiveSetState: EffectiveSetState<T>,
@@ -1979,6 +2168,11 @@ function createProxyHandler<
1979
2168
  componentId: string;
1980
2169
  meta?: MetaData;
1981
2170
  }): any {
2171
+ const rawMeta = getShadowMetadata(stateKey, path);
2172
+ if (rawMeta?.isRaw) {
2173
+ return getShadowValue(stateKey, path);
2174
+ }
2175
+
1982
2176
  const derivationSignature = meta
1983
2177
  ? JSON.stringify(meta.arrayViews || meta.transforms)
1984
2178
  : '';
@@ -2055,6 +2249,91 @@ function createProxyHandler<
2055
2249
  }
2056
2250
 
2057
2251
  if (typeof prop === 'string' && !prop.startsWith('$')) {
2252
+ const { value } = getScopedData(stateKey, path, meta);
2253
+ const hasStateChild =
2254
+ value !== null &&
2255
+ typeof value === 'object' &&
2256
+ !Array.isArray(value) &&
2257
+ Object.prototype.hasOwnProperty.call(value, prop);
2258
+
2259
+ if (hasStateChild) {
2260
+ const nextPath = [...path, prop];
2261
+ return rebuildStateShape({
2262
+ path: nextPath,
2263
+ componentId: componentId!,
2264
+ meta,
2265
+ });
2266
+ }
2267
+
2268
+ const registeredPlugins = pluginStore.getState().registeredPlugins;
2269
+ for (const plugin of registeredPlugins) {
2270
+ const chainMethod = (plugin.chainMethods as any)?.[prop];
2271
+ if (!chainMethod) continue;
2272
+ if (!pathMatchesPattern(path, chainMethod.pathPattern)) continue;
2273
+ if (!valueMatchesChainTarget(value, chainMethod.target)) continue;
2274
+
2275
+ return (...args: any[]) => {
2276
+ const store = pluginStore.getState();
2277
+ const options = store.pluginOptions
2278
+ .get(stateKey)
2279
+ ?.get(plugin.name);
2280
+ const hookData = store.getHookResult(stateKey, plugin.name);
2281
+
2282
+ return chainMethod.handler(
2283
+ {
2284
+ stateKey,
2285
+ path,
2286
+ pluginName: plugin.name,
2287
+ options,
2288
+ hookData,
2289
+ $get: () => getScopedData(stateKey, path, meta).value,
2290
+ $update: (payload: any) => {
2291
+ effectiveSetState(payload, path, {
2292
+ updateType: 'update',
2293
+ });
2294
+
2295
+ return {
2296
+ synced: () => {
2297
+ const shadowMeta = getGlobalStore
2298
+ .getState()
2299
+ .getShadowMetadata(stateKey, path);
2300
+
2301
+ setShadowMetadata(stateKey, path, {
2302
+ ...shadowMeta,
2303
+ isDirty: false,
2304
+ stateSource: 'server',
2305
+ lastServerSync: Date.now(),
2306
+ });
2307
+ },
2308
+ };
2309
+ },
2310
+ $applyOperation: (
2311
+ operation: UpdateTypeDetail,
2312
+ metaData?: Record<string, any>
2313
+ ) => {
2314
+ effectiveSetState(operation.newValue, operation.path, {
2315
+ updateType: operation.updateType,
2316
+ itemId: operation.itemId,
2317
+ metaData,
2318
+ });
2319
+ },
2320
+ getFieldMetaData: () =>
2321
+ getPluginMetaDataMap(stateKey, path)?.get(plugin.name),
2322
+ setFieldMetaData: (data: Record<string, any>) =>
2323
+ setPluginMetaData(stateKey, path, plugin.name, data),
2324
+ removeFieldMetaData: () =>
2325
+ removePluginMetaData(stateKey, path, plugin.name),
2326
+ getFieldRefs: () => getFieldRefsForPath(stateKey, path),
2327
+ getFieldElements: () =>
2328
+ getFieldElementsForPath(stateKey, path),
2329
+ setFieldDisabled: (disabled: boolean) =>
2330
+ setFieldDisabledForPath(stateKey, path, disabled),
2331
+ },
2332
+ ...args
2333
+ );
2334
+ };
2335
+ }
2336
+
2058
2337
  const nextPath = [...path, prop];
2059
2338
  return rebuildStateShape({
2060
2339
  path: nextPath,
@@ -2171,8 +2450,18 @@ function createProxyHandler<
2171
2450
  const localKey = isFunction(initalOptionsGet?.localStorage?.key)
2172
2451
  ? initalOptionsGet.localStorage.key(initialState)
2173
2452
  : initalOptionsGet?.localStorage?.key;
2174
- const storageKey = `${sessionId}-${stateKey}-${localKey}`;
2175
- if (storageKey) localStorage.removeItem(storageKey);
2453
+ const storageKey =
2454
+ sessionId && localKey
2455
+ ? `${sessionId}-${stateKey}-${localKey}`
2456
+ : undefined;
2457
+ removeFromLocalStorage(storageKey);
2458
+ };
2459
+ }
2460
+ if (prop === '$setRaw') {
2461
+ return (value: any) => {
2462
+ const currentMeta = getShadowMetadata(stateKey, path) || {};
2463
+ setShadowMetadata(stateKey, path, { ...currentMeta, isRaw: true });
2464
+ effectiveSetState(value, path, { updateType: 'update' });
2176
2465
  };
2177
2466
  }
2178
2467
 
@@ -3323,10 +3612,11 @@ function createProxyHandler<
3323
3612
  const localKey = isFunction(initalOptionsGet?.localStorage?.key)
3324
3613
  ? initalOptionsGet?.localStorage?.key(revertState)
3325
3614
  : initalOptionsGet?.localStorage?.key;
3326
- const storageKey = `${sessionId}-${stateKey}-${localKey}`;
3327
- if (storageKey) {
3328
- localStorage.removeItem(storageKey);
3329
- }
3615
+ const storageKey =
3616
+ sessionId && localKey
3617
+ ? `${sessionId}-${stateKey}-${localKey}`
3618
+ : undefined;
3619
+ removeFromLocalStorage(storageKey);
3330
3620
 
3331
3621
  notifyComponents(stateKey);
3332
3622
 
@@ -3350,11 +3640,11 @@ function createProxyHandler<
3350
3640
  ? initalOptionsGet?.localStorage?.key(initialState)
3351
3641
  : initalOptionsGet?.localStorage?.key;
3352
3642
 
3353
- const storageKey = `${sessionId}-${stateKey}-${localKey}`;
3354
-
3355
- if (localStorage.getItem(storageKey)) {
3356
- localStorage.removeItem(storageKey);
3357
- }
3643
+ const storageKey =
3644
+ sessionId && localKey
3645
+ ? `${sessionId}-${stateKey}-${localKey}`
3646
+ : undefined;
3647
+ removeFromLocalStorage(storageKey);
3358
3648
  startTransition(() => {
3359
3649
  updateInitialStateGlobal(stateKey, newState);
3360
3650
  initializeShadowState(stateKey, newState);