@sladg/apex-state 3.7.3 → 3.9.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/dist/index.js CHANGED
@@ -1752,7 +1752,7 @@ var filterAndRelativize = (changes, listenerPath) => {
1752
1752
  return result;
1753
1753
  };
1754
1754
  var processListeners = (changes, store, currentState) => {
1755
- const { listeners, sortedListenerPaths } = store._internal.graphs;
1755
+ const { listeners: listeners2, sortedListenerPaths } = store._internal.graphs;
1756
1756
  const { queue } = store._internal.processing;
1757
1757
  const effectiveChanges = [];
1758
1758
  for (const change of changes) {
@@ -1767,7 +1767,7 @@ var processListeners = (changes, store, currentState) => {
1767
1767
  (a, b) => getPathDepth(b[0]) - getPathDepth(a[0])
1768
1768
  );
1769
1769
  for (const listenerPath of sortedListenerPaths) {
1770
- const pathListeners = listeners.get(listenerPath);
1770
+ const pathListeners = listeners2.get(listenerPath);
1771
1771
  const relevantChanges = filterAndRelativize(sortedChanges, listenerPath);
1772
1772
  for (const registration of pathListeners) {
1773
1773
  processListener({
@@ -2068,12 +2068,12 @@ var processChangesWasm = (store, initialChanges) => {
2068
2068
 
2069
2069
  // src/sideEffects/prebuilts/aggregation.ts
2070
2070
  import { effect as effect3 } from "valtio-reactive";
2071
- var registerAggregations = (store, id, aggregationPairs) => {
2071
+ var registerAggregations = (store, id, aggregationPairs2) => {
2072
2072
  const { aggregations } = store._internal.registrations;
2073
2073
  const disposeCallbacks = [];
2074
2074
  const targets = /* @__PURE__ */ new Set();
2075
2075
  const sources = /* @__PURE__ */ new Set();
2076
- for (const [target, source] of aggregationPairs) {
2076
+ for (const [target, source] of aggregationPairs2) {
2077
2077
  targets.add(target);
2078
2078
  sources.add(source);
2079
2079
  }
@@ -2085,7 +2085,7 @@ var registerAggregations = (store, id, aggregationPairs) => {
2085
2085
  }
2086
2086
  }
2087
2087
  const byTarget = /* @__PURE__ */ new Map();
2088
- for (const [target, source] of aggregationPairs) {
2088
+ for (const [target, source] of aggregationPairs2) {
2089
2089
  const existing = byTarget.get(target) ?? [];
2090
2090
  existing.push(source);
2091
2091
  byTarget.set(target, existing);
@@ -2162,30 +2162,33 @@ var validateScopeAndPath = (path, scope) => {
2162
2162
  };
2163
2163
  var registerListenerLegacy = (store, registration) => {
2164
2164
  const { graphs } = store._internal;
2165
- const { listeners, listenerHandlers } = graphs;
2166
- validateScopeAndPath(registration.path, registration.scope);
2165
+ const { listeners: listeners2, listenerHandlers } = graphs;
2166
+ if (registration.scope === void 0) {
2167
+ registration.scope = registration.path;
2168
+ }
2169
+ validateScopeAndPath(registration.path, registration.scope ?? null);
2167
2170
  const subscriberId = nextSubscriberId++;
2168
2171
  const mapKey = registration.path ?? "";
2169
- const existing = listeners.get(mapKey) ?? [];
2172
+ const existing = listeners2.get(mapKey) ?? [];
2170
2173
  const originalFn = registration.fn;
2171
2174
  registration.fn = (changes, state) => store._internal.timing.run("listeners", () => originalFn(changes, state), {
2172
2175
  path: mapKey,
2173
2176
  name: "listener"
2174
2177
  });
2175
- listeners.set(mapKey, [...existing, registration]);
2178
+ listeners2.set(mapKey, [...existing, registration]);
2176
2179
  listenerHandlers.set(subscriberId, {
2177
2180
  scope: registration.scope,
2178
2181
  fn: registration.fn
2179
2182
  });
2180
2183
  updateSortedListenerPaths(graphs);
2181
2184
  return () => {
2182
- const list = listeners.get(mapKey);
2185
+ const list = listeners2.get(mapKey);
2183
2186
  if (list) {
2184
2187
  const filtered = list.filter((l) => l !== registration);
2185
2188
  if (filtered.length > 0) {
2186
- listeners.set(mapKey, filtered);
2189
+ listeners2.set(mapKey, filtered);
2187
2190
  } else {
2188
- listeners.delete(mapKey);
2191
+ listeners2.delete(mapKey);
2189
2192
  }
2190
2193
  updateSortedListenerPaths(graphs);
2191
2194
  }
@@ -2264,17 +2267,20 @@ var registerSyncPairsBatch = (store, pairs) => {
2264
2267
  var registerSideEffectsImpl = (store, id, effects) => {
2265
2268
  const cleanups = [];
2266
2269
  if (effects.syncPaths) {
2267
- const cleanup = registerSyncPairsBatch(store, effects.syncPaths);
2270
+ const pairs = effects.syncPaths;
2271
+ const cleanup = registerSyncPairsBatch(store, pairs);
2268
2272
  cleanups.push(cleanup);
2269
2273
  }
2270
2274
  if (effects.flipPaths) {
2271
- for (const [path1, path2] of effects.flipPaths) {
2275
+ const pairs = effects.flipPaths;
2276
+ for (const [path1, path2] of pairs) {
2272
2277
  const cleanup = registerFlipPair(store, path1, path2);
2273
2278
  cleanups.push(cleanup);
2274
2279
  }
2275
2280
  }
2276
2281
  if (effects.aggregations) {
2277
- const cleanup = registerAggregations(store, id, effects.aggregations);
2282
+ const pairs = effects.aggregations;
2283
+ const cleanup = registerAggregations(store, id, pairs);
2278
2284
  cleanups.push(cleanup);
2279
2285
  }
2280
2286
  if (effects.listeners) {
@@ -2299,12 +2305,12 @@ var registerSideEffects = (store, id, effects) => store._internal.timing.run(
2299
2305
  // src/sideEffects/registration.wasm-impl.ts
2300
2306
  var nextSubscriberId2 = 0;
2301
2307
  var registerSideEffects2 = (store, id, effects) => {
2302
- const syncPairs = effects.syncPaths ?? [];
2303
- const flipPairs = effects.flipPaths ?? [];
2304
- const aggregationPairs = (effects.aggregations ?? []).map(
2308
+ const syncPairs2 = effects.syncPaths ?? [];
2309
+ const flipPairs2 = effects.flipPaths ?? [];
2310
+ const aggregationPairs2 = (effects.aggregations ?? []).map(
2305
2311
  ([target, source, condition]) => condition ? [target, source, JSON.stringify(condition)] : [target, source]
2306
2312
  );
2307
- const computationPairs = (effects.computations ?? []).map(
2313
+ const computationPairs2 = (effects.computations ?? []).map(
2308
2314
  ([op, target, source, condition]) => condition ? [
2309
2315
  op,
2310
2316
  target,
@@ -2316,10 +2322,11 @@ var registerSideEffects2 = (store, id, effects) => {
2316
2322
  triggers,
2317
2323
  targets: opts?.expandMatch ? targets.map((t) => t.replace(/\[\*\]/g, "[**]")) : targets
2318
2324
  }));
2319
- const listeners = effects.listeners?.map((listener) => {
2325
+ const listeners2 = effects.listeners?.map((listener) => {
2320
2326
  const { listenerHandlers } = store._internal.graphs;
2321
2327
  const subscriberId = nextSubscriberId2++;
2322
2328
  const originalFn = listener.fn;
2329
+ const effectiveScope = listener.scope === void 0 ? listener.path : listener.scope;
2323
2330
  const mapKey = listener.path ?? "";
2324
2331
  const wrappedFn = (changes, state) => store._internal.timing.run(
2325
2332
  "listeners",
@@ -2330,27 +2337,27 @@ var registerSideEffects2 = (store, id, effects) => {
2330
2337
  }
2331
2338
  );
2332
2339
  listenerHandlers.set(subscriberId, {
2333
- scope: listener.scope,
2340
+ scope: effectiveScope,
2334
2341
  fn: wrappedFn
2335
2342
  });
2336
2343
  return {
2337
2344
  subscriber_id: subscriberId,
2338
2345
  topic_path: listener.path ?? "",
2339
- scope_path: listener.scope ?? ""
2346
+ scope_path: effectiveScope ?? ""
2340
2347
  };
2341
2348
  });
2342
2349
  const pipeline = store._internal.pipeline;
2343
2350
  const registrationId = `sideEffects-${id}`;
2344
2351
  const result = pipeline.registerSideEffects({
2345
2352
  registration_id: registrationId,
2346
- ...syncPairs.length > 0 && { sync_pairs: syncPairs },
2347
- ...flipPairs.length > 0 && { flip_pairs: flipPairs },
2348
- ...aggregationPairs.length > 0 && { aggregation_pairs: aggregationPairs },
2349
- ...computationPairs.length > 0 && {
2350
- computation_pairs: computationPairs
2353
+ ...syncPairs2.length > 0 && { sync_pairs: syncPairs2 },
2354
+ ...flipPairs2.length > 0 && { flip_pairs: flipPairs2 },
2355
+ ...aggregationPairs2.length > 0 && { aggregation_pairs: aggregationPairs2 },
2356
+ ...computationPairs2.length > 0 && {
2357
+ computation_pairs: computationPairs2
2351
2358
  },
2352
2359
  ...clearPaths && clearPaths.length > 0 && { clear_paths: clearPaths },
2353
- ...listeners && listeners.length > 0 && { listeners }
2360
+ ...listeners2 && listeners2.length > 0 && { listeners: listeners2 }
2354
2361
  });
2355
2362
  if (result.sync_changes.length > 0) {
2356
2363
  applyBatch(
@@ -2373,9 +2380,9 @@ var registerSideEffects2 = (store, id, effects) => {
2373
2380
  const cleanup = () => {
2374
2381
  pipeline.unregisterSideEffects(registrationId);
2375
2382
  effects.listeners?.forEach((_listener, index) => {
2376
- if (listeners && listeners[index]) {
2383
+ if (listeners2 && listeners2[index]) {
2377
2384
  store._internal.graphs.listenerHandlers.delete(
2378
- listeners[index].subscriber_id
2385
+ listeners2[index].subscriber_id
2379
2386
  );
2380
2387
  }
2381
2388
  });
@@ -2847,6 +2854,119 @@ var createProvider = (storeConfig) => {
2847
2854
  return Provider;
2848
2855
  };
2849
2856
 
2857
+ // src/utils/pair-helpers.ts
2858
+ var syncPairs = () => (pairs) => pairs;
2859
+ var flipPairs = () => (pairs) => pairs;
2860
+ var aggregationPairs = () => (pairs) => pairs;
2861
+ var computationPairs = () => (pairs) => pairs;
2862
+ var listeners = () => (items) => items;
2863
+
2864
+ // src/store/warm-pair-helpers.ts
2865
+ var createWarmPairHelpers = () => ({
2866
+ /**
2867
+ * Pre-warmed sync pair validator — DATA type is already bound.
2868
+ * Validates that both paths in each pair resolve to the same value type.
2869
+ * Pass the result to `useSideEffects` as `syncPaths`.
2870
+ *
2871
+ * @example
2872
+ * ```typescript
2873
+ * const { useSideEffects, syncPairs } = createGenericStore<MyState>()
2874
+ *
2875
+ * // Type-safe — no need to repeat <MyState>
2876
+ * const syncs = syncPairs([
2877
+ * ['user.email', 'profile.email'], // ✓ both string
2878
+ * ['user.age', 'profile.age'], // ✓ both number
2879
+ * ])
2880
+ *
2881
+ * // Inside a component:
2882
+ * useSideEffects('my-syncs', { syncPaths: syncs })
2883
+ * ```
2884
+ */
2885
+ syncPairs: syncPairs(),
2886
+ /**
2887
+ * Pre-warmed flip pair validator — DATA type is already bound.
2888
+ * Validates that both paths in each pair resolve to the same value type.
2889
+ * Used for inverted boolean synchronization. Pass the result to `useSideEffects` as `flipPaths`.
2890
+ *
2891
+ * @example
2892
+ * ```typescript
2893
+ * const { useSideEffects, flipPairs } = createGenericStore<MyState>()
2894
+ *
2895
+ * const flips = flipPairs([
2896
+ * ['isExpanded', 'isCollapsed'], // ✓ both boolean
2897
+ * ])
2898
+ *
2899
+ * // Inside a component:
2900
+ * useSideEffects('my-flips', { flipPaths: flips })
2901
+ * ```
2902
+ */
2903
+ flipPairs: flipPairs(),
2904
+ /**
2905
+ * Pre-warmed aggregation pair validator — DATA type is already bound.
2906
+ * Each pair is `[target, source]` or `[target, source, BoolLogic]`.
2907
+ * Validates that target and source resolve to the same value type.
2908
+ * Pass the result to `useSideEffects` as `aggregations`.
2909
+ *
2910
+ * @example
2911
+ * ```typescript
2912
+ * const { useSideEffects, aggregationPairs } = createGenericStore<MyState>()
2913
+ *
2914
+ * const aggs = aggregationPairs([
2915
+ * ['total', 'price1'],
2916
+ * ['total', 'price2', { IS_EQUAL: ['price2.disabled', true] }],
2917
+ * ])
2918
+ *
2919
+ * // Inside a component:
2920
+ * useSideEffects('my-aggs', { aggregations: aggs })
2921
+ * ```
2922
+ */
2923
+ aggregationPairs: aggregationPairs(),
2924
+ /**
2925
+ * Pre-warmed computation pair validator — DATA type is already bound.
2926
+ * Each pair is `[op, target, source]` or `[op, target, source, BoolLogic]`.
2927
+ * Both target and source must be number paths.
2928
+ * Pass the result to `useSideEffects` as `computations`.
2929
+ *
2930
+ * @example
2931
+ * ```typescript
2932
+ * const { useSideEffects, computationPairs } = createGenericStore<MyState>()
2933
+ *
2934
+ * const comps = computationPairs([
2935
+ * ['SUM', 'total', 'price1'],
2936
+ * ['AVG', 'average', 'score1'],
2937
+ * ])
2938
+ *
2939
+ * // Inside a component:
2940
+ * useSideEffects('my-comps', { computations: comps })
2941
+ * ```
2942
+ */
2943
+ computationPairs: computationPairs(),
2944
+ /**
2945
+ * Pre-warmed listener validator — DATA type is already bound.
2946
+ * Validates path/scope relationships and derives fn types from scope.
2947
+ * Pass the result to `useSideEffects` as `listeners`.
2948
+ *
2949
+ * @example
2950
+ * ```typescript
2951
+ * const { useSideEffects, listeners } = createGenericStore<MyState>()
2952
+ *
2953
+ * const myListeners = listeners([
2954
+ * {
2955
+ * path: 'user.profile.name',
2956
+ * scope: 'user.profile',
2957
+ * fn: (changes, state) => {
2958
+ * // state is typed as MyState['user']['profile']
2959
+ * return undefined
2960
+ * }
2961
+ * },
2962
+ * ])
2963
+ *
2964
+ * useSideEffects('my-listeners', { listeners: myListeners })
2965
+ * ```
2966
+ */
2967
+ listeners: listeners()
2968
+ });
2969
+
2850
2970
  // src/store/create-store.ts
2851
2971
  var createGenericStore = (config) => {
2852
2972
  const Provider = createProvider(config);
@@ -2947,7 +3067,8 @@ var createGenericStore = (config) => {
2947
3067
  useSideEffects,
2948
3068
  useConcerns,
2949
3069
  withConcerns,
2950
- withMeta
3070
+ withMeta,
3071
+ ...createWarmPairHelpers()
2951
3072
  };
2952
3073
  };
2953
3074
 
@@ -3106,7 +3227,9 @@ var applyChangesToObject = (obj, changes) => {
3106
3227
  };
3107
3228
  export {
3108
3229
  _,
3230
+ aggregationPairs,
3109
3231
  applyChangesToObject,
3232
+ computationPairs,
3110
3233
  createGenericStore,
3111
3234
  deepClone,
3112
3235
  defaultConcerns,
@@ -3114,14 +3237,17 @@ export {
3114
3237
  evaluateBoolLogic,
3115
3238
  extractPlaceholders,
3116
3239
  findConcern,
3240
+ flipPairs,
3117
3241
  hashKey,
3118
3242
  interpolateTemplate,
3119
3243
  is,
3244
+ listeners,
3120
3245
  prebuilts_exports as prebuilts,
3121
3246
  registerFlipPair,
3122
3247
  registerListenerLegacy,
3123
3248
  registerSideEffects,
3124
3249
  registerSyncPairsBatch,
3250
+ syncPairs,
3125
3251
  useBufferedField,
3126
3252
  useKeyboardSelect,
3127
3253
  useThrottledField,