ccstate 2.0.0 → 2.1.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/README.md CHANGED
@@ -1,4 +1,6 @@
1
- # CCState
1
+ <img src="https://github.com/user-attachments/assets/590797c8-6edf-45cc-8eae-028aef0b2cb3" width="240" >
2
+
3
+ ---
2
4
 
3
5
  [![Coverage Status](https://coveralls.io/repos/github/e7h4n/ccstate/badge.svg?branch=main)](https://coveralls.io/github/e7h4n/ccstate?branch=main)
4
6
  ![NPM Type Definitions](https://img.shields.io/npm/types/ccstate)
@@ -8,17 +10,19 @@
8
10
  [![CodSpeed Badge](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/e7h4n/ccstate)
9
11
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
12
 
13
+ English | [中文](README-zh.md)
14
+
11
15
  CCState is a semantic, strict, and flexible state management library suitable for medium to large single-page applications with complex state management needs.
12
16
 
13
- The name CCState comes from its three basic data types: Computed, Command and State.
17
+ The name of CCState comes from three basic data types: computed, command, and state.
14
18
 
15
19
  ## Quick Features
16
20
 
17
- - Simple API design with only 3 data types and 2 data operations
18
- - Strict test coverage with 100% branch coverage
19
- - Zero dependencies
20
- - Not bound to any UI library - can be used with React or Vanilla JS
21
- - High Performance
21
+ - 💯 Simple & Intuitive: Crystal-clear API design with just 3 data types and 2 operations
22
+ - Rock-solid Reliability: Comprehensive test coverage reaching 100% branch coverage
23
+ - 🪶 Ultra-lightweight: Zero dependencies, only 500 lines of core code
24
+ - 💡 Framework Agnostic: Seamlessly works with React, Vanilla JS, or any UI framework
25
+ - 🚀 Blazing Fast: Optimized performance from day one, 2x-7x faster than Jotai across scenarios
22
26
 
23
27
  ## Getting Started
24
28
 
@@ -35,12 +39,12 @@ pnpm add ccstate
35
39
  yarn add ccstate
36
40
  ```
37
41
 
38
- ### Create Atoms
42
+ ### Create Data
39
43
 
40
- Use `state` to create a simple value unit, and use `computed` to create a derived computation logic:
44
+ Use `state` to store a simple value unit, and use `computed` to create a derived computation logic:
41
45
 
42
46
  ```ts
43
- // atom.js
47
+ // data.js
44
48
  import { state, computed } from 'ccstate';
45
49
 
46
50
  export const userId$ = state('');
@@ -54,14 +58,14 @@ export const user$ = computed(async (get) => {
54
58
  });
55
59
  ```
56
60
 
57
- ### Use Atoms in React
61
+ ### Use data in React
58
62
 
59
- Use `useGet` and `useSet` hooks in React to get/set atoms, and use `useResolved` to get Promise value.
63
+ Use `useGet` and `useSet` hooks in React to get/set data, and use `useResolved` to get Promise value.
60
64
 
61
65
  ```jsx
62
66
  // App.js
63
67
  import { useGet, useSet, useResolved } from 'ccstate';
64
- import { userId$, user$ } from './atom';
68
+ import { userId$, user$ } from './data';
65
69
 
66
70
  export default function App() {
67
71
  const userId = useGet(userId$);
@@ -114,7 +118,7 @@ Through these examples, you should have understood the basic usage of CCState. N
114
118
 
115
119
  ## Core APIs
116
120
 
117
- CCState is an atomic state management library that provides several simple concepts to help developers better manage application states. And it can be used as an external store to drive UI frameworks like React.
121
+ CCState provides several simple concepts to help developers better manage application states. And it can be used as an external store to drive UI frameworks like React.
118
122
 
119
123
  ### State
120
124
 
@@ -137,7 +141,7 @@ store.set(callback$, () => {
137
141
  store.get(callback$)(); // console log 'awesome ccstate'
138
142
  ```
139
143
 
140
- These examples should be very easy to understand. You might notice a detail in the examples: all variables returned by `state` have a `$` suffix. This is a naming convention used to distinguish an Atom type from other regular types. Atom types must be accessed through the store's get/set methods, and since it's common to convert an Atom type to a regular type using get, the `$` suffix helps avoid naming conflicts.
144
+ These examples should be very easy to understand. You might notice a detail in the examples: all variables returned by `state` have a `$` suffix. This is a naming convention used to distinguish an CCState data type from other regular types. CCState data types must be accessed through the store's get/set methods, and since it's common to convert an CCState data type to a regular type using get, the `$` suffix helps avoid naming conflicts.
141
145
 
142
146
  ### Store
143
147
 
@@ -153,7 +157,7 @@ const otherStore = createStore(); // another new Map()
153
157
  otherStore.get(count$); // anotherMap[$count] ?? $count.init, returns 0
154
158
  ```
155
159
 
156
- This should be easy to understand. If `Store` only needed to support `State` types, a simple Map would be sufficient. However, CCState needs to support two additional atomic types. Next, let's introduce `Computed`, CCState's reactive computation unit.
160
+ This should be easy to understand. If `Store` only needed to support `State` types, a simple Map would be sufficient. However, CCState needs to support two additional data types. Next, let's introduce `Computed`, CCState's reactive computation unit.
157
161
 
158
162
  ### Computed
159
163
 
@@ -184,7 +188,7 @@ In most cases, side-effect free computation logic is extremely useful. They can
184
188
 
185
189
  ### Command
186
190
 
187
- `Command` is CCState's logic unit for organizing side effects. It has both `set` and `get` accessors from the store, allowing it to not only read other Atom values but also modify `State` or call other `Command`.
191
+ `Command` is CCState's logic unit for organizing side effects. It has both `set` and `get` accessors from the store, allowing it to not only read other data types but also modify `State` or call other `Command`.
188
192
 
189
193
  ```typescript
190
194
  import { command, createStore } from 'ccstate';
@@ -303,18 +307,18 @@ All descendant components within the `StoreProvider` will use the provided store
303
307
 
304
308
  You can place the `StoreProvider` inside or outside of `StrictMode`; the functionality is the same.
305
309
 
306
- ### Retrieving Atom Values
310
+ ### Retrieving Values
307
311
 
308
- The most basic usage is to use `useGet` to retrieve the value of an Atom.
312
+ The most basic usage is to use `useGet` to retrieve the value from State or Computed.
309
313
 
310
314
  ```jsx
311
- // atoms/count.ts
315
+ // data/count.ts
312
316
  import { state } from 'ccstate';
313
317
  export const count$ = state(0);
314
318
 
315
319
  // App.tsx
316
320
  import { useGet } from 'ccstate';
317
- import { count$ } from './atoms/count';
321
+ import { count$ } from './data/count';
318
322
 
319
323
  function App() {
320
324
  const count = useGet(count$);
@@ -329,7 +333,7 @@ function App() {
329
333
  Two other useful hooks are available when dealing with `Promise` values. First, we introduce `useLoadable`.
330
334
 
331
335
  ```jsx
332
- // atoms/user.ts
336
+ // data/user.ts
333
337
  import { computed } from 'ccstate';
334
338
 
335
339
  export const user$ = computed(async () => {
@@ -338,7 +342,7 @@ export const user$ = computed(async () => {
338
342
 
339
343
  // App.tsx
340
344
  import { useLoadable } from 'ccstate';
341
- import { user$ } from './atoms/user';
345
+ import { user$ } from './data/user';
342
346
 
343
347
  function App() {
344
348
  const user_ = useLoadable(user$);
@@ -349,7 +353,7 @@ function App() {
349
353
  }
350
354
  ```
351
355
 
352
- `useLoadable` accepts an Atom that returns a `Promise` and wraps the result in a `Loadable` structure.
356
+ `useLoadable` accepts Value/Computed that returns a `Promise` and wraps the result in a `Loadable` structure.
353
357
 
354
358
  ```typescript
355
359
  type Loadable<T> =
@@ -373,7 +377,7 @@ Another useful hook is `useResolved`, which always returns the resolved value of
373
377
  ```jsx
374
378
  // App.tsx
375
379
  import { useResolved } from 'ccstate';
376
- import { user$ } from './atoms/user';
380
+ import { user$ } from './data/user';
377
381
 
378
382
  function App() {
379
383
  const user = useResolved(user$);
@@ -396,11 +400,11 @@ export function useResolved<T>(atom: State<Promise<T>> | Computed<Promise<T>>):
396
400
 
397
401
  ### useLastLoadable & useLastResolved
398
402
 
399
- In some scenarios, we want a refreshable Promise Atom to maintain its previous result during the refresh process instead of showing a loading state. CCState provides `useLastLoadable` and `useLastResolved` to achieve this functionality.
403
+ In some scenarios, we want a refreshable Promise Computed to maintain its previous result during the refresh process instead of showing a loading state. CCState provides `useLastLoadable` and `useLastResolved` to achieve this functionality.
400
404
 
401
405
  ```jsx
402
406
  import { useLoadable } from 'ccstate';
403
- import { user$ } from './atoms/user';
407
+ import { user$ } from './data/user';
404
408
 
405
409
  function App() {
406
410
  const user_ = useLastLoadable(user$); // Keep the previous result during new user$ request, without triggering loading state
@@ -413,14 +417,14 @@ function App() {
413
417
 
414
418
  `useLastResolved` behaves similarly - it always returns the last resolved value from a Promise Atom and won't reset to `undefined` when a new Promise is generated.
415
419
 
416
- ### Updating Atom Values / Triggering Funcs
420
+ ### Updating State / Triggering Command
417
421
 
418
- The `useSet` hook can be used to update the value of an Atom. It returns a function equivalent to `store.set` when called.
422
+ The `useSet` hook can be used to update the value of State, or trigger Command. It returns a function equivalent to `store.set` when called.
419
423
 
420
424
  ```jsx
421
425
  // App.tsx
422
426
  import { useSet } from 'ccstate';
423
- import { count$ } from './atoms/count';
427
+ import { count$ } from './data/count';
424
428
 
425
429
  function App() {
426
430
  const setCount = useSet(count$);
@@ -429,9 +433,9 @@ function App() {
429
433
  }
430
434
  ```
431
435
 
432
- ### Testing & Debugg
436
+ ### Testing & Debugging
433
437
 
434
- Testing Atoms should be as simple as testing a Map.
438
+ Testing Value/Computed should be as simple as testing a Map.
435
439
 
436
440
  ```typescript
437
441
  // counter.test.ts
@@ -453,22 +457,12 @@ Here are some tips to help you better debug during testing.
453
457
  Use `ConsoleInterceptor` to log most store behaviors to the console during testing:
454
458
 
455
459
  ```typescript
456
- import { ConsoleInterceptor, createDebugStore, state, computed, command } from 'ccstate';
460
+ import { createConsoleDebugStore, state, computed, command } from 'ccstate';
457
461
 
458
462
  const base$ = state(1, { debugLabel: 'base$' });
459
463
  const derived$ = computed((get) => get(base$) * 2);
460
464
 
461
- const interceptor = new ConsoleInterceptor([
462
- {
463
- target: base$,
464
- actions: new Set(['set']), // will only log set actions
465
- },
466
- {
467
- target: derived$, // will log all actions
468
- },
469
- ]);
470
-
471
- const store = createDebugStore(interceptor);
465
+ const store = createConsoleDebugStore([base$, 'derived'], ['set', 'sub']); // log sub & set actions
472
466
  store.set(base$, 1); // console: SET [V0:base$] 1
473
467
  store.sub(
474
468
  derived$,
@@ -484,9 +478,9 @@ CCState is inspired by Jotai. While Jotai is a great state management solution t
484
478
  - Should reduce reactive capabilities, especially the `onMount` capability - the framework shouldn't provide this ability
485
479
  - Some implicit magic operations, especially Promise wrapping, make the application execution process less transparent
486
480
 
487
- To address these issues, I created CCState to express my thoughts on state management. Before detailing the differences from Jotai, we need to understand CCState's Atom types and subscription system.
481
+ To address these issues, I created CCState to express my thoughts on state management. Before detailing the differences from Jotai, we need to understand CCState's data types and subscription system.
488
482
 
489
- ### More Semantic Atom Types
483
+ ### More semantic data types
490
484
 
491
485
  Like Jotai, CCState is also an Atom State solution. However, unlike Jotai, CCState doesn't expose Raw Atom, instead dividing Atoms into three types:
492
486
 
@@ -507,7 +501,7 @@ export const userIdChange$ = command(({ get, set }) => {
507
501
  });
508
502
 
509
503
  // ...
510
- import { userId$, userIdChange$ } from './atoms';
504
+ import { userId$, userIdChange$ } from './data';
511
505
 
512
506
  function setupPage() {
513
507
  const store = createStore();
@@ -556,7 +550,7 @@ export function App() {
556
550
  When designing CCState, we wanted the trigger points for value changes to be completely detached from React's Mount/Unmount lifecycle and completely decoupled from React's rendering behavior.
557
551
 
558
552
  ```jsx
559
- // atoms.js
553
+ // data.js
560
554
  export const userId$ = state(0)
561
555
  export const init$ = command(({set}) => {
562
556
  const userId = // ... parse userId from location search
@@ -587,32 +581,6 @@ root.render(
587
581
  );
588
582
  ```
589
583
 
590
- ## Practices
591
-
592
- ### Naming
593
-
594
- Add the suffix `$` to atoms. Since we often need to get values from Atoms in many scenarios, adding the suffix after Atom can avoid naming conflicts.
595
-
596
- ```typescript
597
- const count$ = state(0);
598
- const double$ = computed((get) => get(count$) * 2);
599
- const updateCount$ = command(({ get, set }, val) => {
600
- set(count$, val);
601
- });
602
-
603
- // ...
604
- const count = get(count$) // will not conflict with normal value
605
-
606
- // in react component
607
- const updateCount = useSet(updateCount$) // Command suffix is useful for this
608
-
609
- return <button onClick={() => updateCount(10)}>update</button>
610
- ```
611
-
612
- ### Internal Atom
613
-
614
- Feel free to create internal Atom. Atom is very lightweight. Creating an Atom should be just like creating a variable. Atoms don't necessarily need to be persisted or defined in the top-level scope - it's perfectly fine to create Atoms inside closures or pass new Atoms through containers.
615
-
616
584
  ## Changelog & TODO
617
585
 
618
586
  [Changelog](packages/ccstate/CHANGELOG.md)
package/debug/index.cjs CHANGED
@@ -1175,13 +1175,18 @@ var ConsoleInterceptor = /*#__PURE__*/_createClass(function ConsoleInterceptor(w
1175
1175
  _classCallCheck(this, ConsoleInterceptor);
1176
1176
  _defineProperty(this, "shouldLog", function (atom, action) {
1177
1177
  return _this.watches.some(function (watch) {
1178
+ var atomMatched = false;
1178
1179
  if (typeof watch.target === 'string') {
1179
- return atom.toString().includes(watch.target);
1180
+ atomMatched = atom.toString().includes(watch.target);
1181
+ } else if (watch.target instanceof RegExp) {
1182
+ atomMatched = watch.target.test(atom.toString());
1183
+ } else {
1184
+ atomMatched = watch.target === atom;
1180
1185
  }
1181
- if (watch.target instanceof RegExp) {
1182
- return watch.target.test(atom.toString());
1186
+ if (!atomMatched) {
1187
+ return false;
1183
1188
  }
1184
- return watch.target === atom && (!watch.actions || watch.actions.has(action));
1189
+ return !watch.actions || watch.actions.has(action);
1185
1190
  });
1186
1191
  });
1187
1192
  _defineProperty(this, "get", function (atom$, fn) {
@@ -1256,6 +1261,25 @@ var ConsoleInterceptor = /*#__PURE__*/_createClass(function ConsoleInterceptor(w
1256
1261
  });
1257
1262
  this.watches = watches;
1258
1263
  });
1264
+ function createConsoleDebugStore(watches, defaultActions) {
1265
+ var parsedWatches = watches.map(function (watch) {
1266
+ if (typeof watch === 'string' || watch instanceof RegExp) {
1267
+ return {
1268
+ target: watch,
1269
+ actions: defaultActions ? new Set(defaultActions) : undefined
1270
+ };
1271
+ }
1272
+ if ('target' in watch) {
1273
+ return watch;
1274
+ }
1275
+ return {
1276
+ target: watch,
1277
+ actions: defaultActions ? new Set(defaultActions) : undefined
1278
+ };
1279
+ });
1280
+ var interceptor = new ConsoleInterceptor(parsedWatches);
1281
+ return createDebugStore(interceptor);
1282
+ }
1259
1283
 
1260
1284
  var StoreEvent = /*#__PURE__*/function (_Event) {
1261
1285
  function StoreEvent(type, eventId, targetAtom, state, time, args, result) {
@@ -1422,6 +1446,7 @@ exports.ConsoleInterceptor = ConsoleInterceptor;
1422
1446
  exports.EventInterceptor = EventInterceptor;
1423
1447
  exports.GLOBAL_CCSTATE_INTERCEPED_KEY = GLOBAL_CCSTATE_INTERCEPED_KEY;
1424
1448
  exports.StoreEvent = StoreEvent;
1449
+ exports.createConsoleDebugStore = createConsoleDebugStore;
1425
1450
  exports.createDebugStore = createDebugStore;
1426
1451
  exports.nestedAtomToString = nestedAtomToString;
1427
1452
  exports.setupDevtoolsInterceptor = setupDevtoolsInterceptor;
package/debug/index.d.cts CHANGED
@@ -94,6 +94,7 @@ declare class ConsoleInterceptor implements StoreInterceptor {
94
94
  unmount: <T>(atom$: State<T> | Computed<T>) => void;
95
95
  notify: <T>(callback$: CallbackFunc<T>, fn: () => T) => void;
96
96
  }
97
+ declare function createConsoleDebugStore(watches: (AtomWatch | string | RegExp | State<unknown> | Computed<unknown> | Command<unknown, unknown[]>)[], defaultActions?: StoreEventType[]): DebugStore;
97
98
 
98
99
  declare class StoreEvent extends Event {
99
100
  readonly eventId: number;
@@ -130,4 +131,4 @@ interface DevToolsHookMessage {
130
131
  declare const GLOBAL_CCSTATE_INTERCEPED_KEY = "__CCSTATE_INTERCEPED__";
131
132
  declare function setupDevtoolsInterceptor(targetWindow: Window, signal?: AbortSignal): EventInterceptor;
132
133
 
133
- export { ConsoleInterceptor, type DebugStore, type DevToolsHookMessage, EventInterceptor, GLOBAL_CCSTATE_INTERCEPED_KEY, type PackedEventMessage, StoreEvent, type StoreEventType, type StoreInterceptor, createDebugStore, nestedAtomToString, setupDevtoolsInterceptor };
134
+ export { ConsoleInterceptor, type DebugStore, type DevToolsHookMessage, EventInterceptor, GLOBAL_CCSTATE_INTERCEPED_KEY, type PackedEventMessage, StoreEvent, type StoreEventType, type StoreInterceptor, createConsoleDebugStore, createDebugStore, nestedAtomToString, setupDevtoolsInterceptor };
package/debug/index.d.ts CHANGED
@@ -94,6 +94,7 @@ declare class ConsoleInterceptor implements StoreInterceptor {
94
94
  unmount: <T>(atom$: State<T> | Computed<T>) => void;
95
95
  notify: <T>(callback$: CallbackFunc<T>, fn: () => T) => void;
96
96
  }
97
+ declare function createConsoleDebugStore(watches: (AtomWatch | string | RegExp | State<unknown> | Computed<unknown> | Command<unknown, unknown[]>)[], defaultActions?: StoreEventType[]): DebugStore;
97
98
 
98
99
  declare class StoreEvent extends Event {
99
100
  readonly eventId: number;
@@ -130,4 +131,4 @@ interface DevToolsHookMessage {
130
131
  declare const GLOBAL_CCSTATE_INTERCEPED_KEY = "__CCSTATE_INTERCEPED__";
131
132
  declare function setupDevtoolsInterceptor(targetWindow: Window, signal?: AbortSignal): EventInterceptor;
132
133
 
133
- export { ConsoleInterceptor, type DebugStore, type DevToolsHookMessage, EventInterceptor, GLOBAL_CCSTATE_INTERCEPED_KEY, type PackedEventMessage, StoreEvent, type StoreEventType, type StoreInterceptor, createDebugStore, nestedAtomToString, setupDevtoolsInterceptor };
134
+ export { ConsoleInterceptor, type DebugStore, type DevToolsHookMessage, EventInterceptor, GLOBAL_CCSTATE_INTERCEPED_KEY, type PackedEventMessage, StoreEvent, type StoreEventType, type StoreInterceptor, createConsoleDebugStore, createDebugStore, nestedAtomToString, setupDevtoolsInterceptor };
package/debug/index.js CHANGED
@@ -1173,13 +1173,18 @@ var ConsoleInterceptor = /*#__PURE__*/_createClass(function ConsoleInterceptor(w
1173
1173
  _classCallCheck(this, ConsoleInterceptor);
1174
1174
  _defineProperty(this, "shouldLog", function (atom, action) {
1175
1175
  return _this.watches.some(function (watch) {
1176
+ var atomMatched = false;
1176
1177
  if (typeof watch.target === 'string') {
1177
- return atom.toString().includes(watch.target);
1178
+ atomMatched = atom.toString().includes(watch.target);
1179
+ } else if (watch.target instanceof RegExp) {
1180
+ atomMatched = watch.target.test(atom.toString());
1181
+ } else {
1182
+ atomMatched = watch.target === atom;
1178
1183
  }
1179
- if (watch.target instanceof RegExp) {
1180
- return watch.target.test(atom.toString());
1184
+ if (!atomMatched) {
1185
+ return false;
1181
1186
  }
1182
- return watch.target === atom && (!watch.actions || watch.actions.has(action));
1187
+ return !watch.actions || watch.actions.has(action);
1183
1188
  });
1184
1189
  });
1185
1190
  _defineProperty(this, "get", function (atom$, fn) {
@@ -1254,6 +1259,25 @@ var ConsoleInterceptor = /*#__PURE__*/_createClass(function ConsoleInterceptor(w
1254
1259
  });
1255
1260
  this.watches = watches;
1256
1261
  });
1262
+ function createConsoleDebugStore(watches, defaultActions) {
1263
+ var parsedWatches = watches.map(function (watch) {
1264
+ if (typeof watch === 'string' || watch instanceof RegExp) {
1265
+ return {
1266
+ target: watch,
1267
+ actions: defaultActions ? new Set(defaultActions) : undefined
1268
+ };
1269
+ }
1270
+ if ('target' in watch) {
1271
+ return watch;
1272
+ }
1273
+ return {
1274
+ target: watch,
1275
+ actions: defaultActions ? new Set(defaultActions) : undefined
1276
+ };
1277
+ });
1278
+ var interceptor = new ConsoleInterceptor(parsedWatches);
1279
+ return createDebugStore(interceptor);
1280
+ }
1257
1281
 
1258
1282
  var StoreEvent = /*#__PURE__*/function (_Event) {
1259
1283
  function StoreEvent(type, eventId, targetAtom, state, time, args, result) {
@@ -1416,4 +1440,4 @@ function setupDevtoolsInterceptor(targetWindow, signal) {
1416
1440
  return interceptor;
1417
1441
  }
1418
1442
 
1419
- export { ConsoleInterceptor, EventInterceptor, GLOBAL_CCSTATE_INTERCEPED_KEY, StoreEvent, createDebugStore, nestedAtomToString, setupDevtoolsInterceptor };
1443
+ export { ConsoleInterceptor, EventInterceptor, GLOBAL_CCSTATE_INTERCEPED_KEY, StoreEvent, createConsoleDebugStore, createDebugStore, nestedAtomToString, setupDevtoolsInterceptor };
package/index.cjs CHANGED
@@ -1221,13 +1221,18 @@ var ConsoleInterceptor = /*#__PURE__*/_createClass(function ConsoleInterceptor(w
1221
1221
  _classCallCheck(this, ConsoleInterceptor);
1222
1222
  _defineProperty(this, "shouldLog", function (atom, action) {
1223
1223
  return _this.watches.some(function (watch) {
1224
+ var atomMatched = false;
1224
1225
  if (typeof watch.target === 'string') {
1225
- return atom.toString().includes(watch.target);
1226
+ atomMatched = atom.toString().includes(watch.target);
1227
+ } else if (watch.target instanceof RegExp) {
1228
+ atomMatched = watch.target.test(atom.toString());
1229
+ } else {
1230
+ atomMatched = watch.target === atom;
1226
1231
  }
1227
- if (watch.target instanceof RegExp) {
1228
- return watch.target.test(atom.toString());
1232
+ if (!atomMatched) {
1233
+ return false;
1229
1234
  }
1230
- return watch.target === atom && (!watch.actions || watch.actions.has(action));
1235
+ return !watch.actions || watch.actions.has(action);
1231
1236
  });
1232
1237
  });
1233
1238
  _defineProperty(this, "get", function (atom$, fn) {
@@ -1302,6 +1307,25 @@ var ConsoleInterceptor = /*#__PURE__*/_createClass(function ConsoleInterceptor(w
1302
1307
  });
1303
1308
  this.watches = watches;
1304
1309
  });
1310
+ function createConsoleDebugStore(watches, defaultActions) {
1311
+ var parsedWatches = watches.map(function (watch) {
1312
+ if (typeof watch === 'string' || watch instanceof RegExp) {
1313
+ return {
1314
+ target: watch,
1315
+ actions: defaultActions ? new Set(defaultActions) : undefined
1316
+ };
1317
+ }
1318
+ if ('target' in watch) {
1319
+ return watch;
1320
+ }
1321
+ return {
1322
+ target: watch,
1323
+ actions: defaultActions ? new Set(defaultActions) : undefined
1324
+ };
1325
+ });
1326
+ var interceptor = new ConsoleInterceptor(parsedWatches);
1327
+ return createDebugStore(interceptor);
1328
+ }
1305
1329
 
1306
1330
  var StoreEvent = /*#__PURE__*/function (_Event) {
1307
1331
  function StoreEvent(type, eventId, targetAtom, state, time, args, result) {
@@ -1585,6 +1609,7 @@ exports.StoreEvent = StoreEvent;
1585
1609
  exports.StoreProvider = StoreProvider;
1586
1610
  exports.command = command;
1587
1611
  exports.computed = computed;
1612
+ exports.createConsoleDebugStore = createConsoleDebugStore;
1588
1613
  exports.createDebugStore = createDebugStore;
1589
1614
  exports.createStore = createStore;
1590
1615
  exports.nestedAtomToString = nestedAtomToString;
package/index.d.cts CHANGED
@@ -105,6 +105,7 @@ declare class ConsoleInterceptor implements StoreInterceptor {
105
105
  unmount: <T>(atom$: State<T> | Computed<T>) => void;
106
106
  notify: <T>(callback$: CallbackFunc<T>, fn: () => T) => void;
107
107
  }
108
+ declare function createConsoleDebugStore(watches: (AtomWatch | string | RegExp | State<unknown> | Computed<unknown> | Command<unknown, unknown[]>)[], defaultActions?: StoreEventType[]): DebugStore;
108
109
 
109
110
  declare class StoreEvent extends Event {
110
111
  readonly eventId: number;
@@ -163,4 +164,4 @@ declare function useLastLoadable<T>(atom: State<Promise<T>> | Computed<Promise<T
163
164
 
164
165
  declare const StoreProvider: react.Provider<Store | null>;
165
166
 
166
- export { type Command, type Computed, ConsoleInterceptor, type DebugStore, type DevToolsHookMessage, EventInterceptor, GLOBAL_CCSTATE_INTERCEPED_KEY, type Getter, type PackedEventMessage, type Read, type Setter, type State, type Store, StoreEvent, type StoreEventType, type StoreInterceptor, StoreProvider, type Subscribe, type Updater, type Write, command, computed, createDebugStore, createStore, nestedAtomToString, setupDevtoolsInterceptor, state, useGet, useLastLoadable, useLastResolved, useLoadable, useResolved, useSet };
167
+ export { type Command, type Computed, ConsoleInterceptor, type DebugStore, type DevToolsHookMessage, EventInterceptor, GLOBAL_CCSTATE_INTERCEPED_KEY, type Getter, type PackedEventMessage, type Read, type Setter, type State, type Store, StoreEvent, type StoreEventType, type StoreInterceptor, StoreProvider, type Subscribe, type Updater, type Write, command, computed, createConsoleDebugStore, createDebugStore, createStore, nestedAtomToString, setupDevtoolsInterceptor, state, useGet, useLastLoadable, useLastResolved, useLoadable, useResolved, useSet };
package/index.d.ts CHANGED
@@ -105,6 +105,7 @@ declare class ConsoleInterceptor implements StoreInterceptor {
105
105
  unmount: <T>(atom$: State<T> | Computed<T>) => void;
106
106
  notify: <T>(callback$: CallbackFunc<T>, fn: () => T) => void;
107
107
  }
108
+ declare function createConsoleDebugStore(watches: (AtomWatch | string | RegExp | State<unknown> | Computed<unknown> | Command<unknown, unknown[]>)[], defaultActions?: StoreEventType[]): DebugStore;
108
109
 
109
110
  declare class StoreEvent extends Event {
110
111
  readonly eventId: number;
@@ -163,4 +164,4 @@ declare function useLastLoadable<T>(atom: State<Promise<T>> | Computed<Promise<T
163
164
 
164
165
  declare const StoreProvider: react.Provider<Store | null>;
165
166
 
166
- export { type Command, type Computed, ConsoleInterceptor, type DebugStore, type DevToolsHookMessage, EventInterceptor, GLOBAL_CCSTATE_INTERCEPED_KEY, type Getter, type PackedEventMessage, type Read, type Setter, type State, type Store, StoreEvent, type StoreEventType, type StoreInterceptor, StoreProvider, type Subscribe, type Updater, type Write, command, computed, createDebugStore, createStore, nestedAtomToString, setupDevtoolsInterceptor, state, useGet, useLastLoadable, useLastResolved, useLoadable, useResolved, useSet };
167
+ export { type Command, type Computed, ConsoleInterceptor, type DebugStore, type DevToolsHookMessage, EventInterceptor, GLOBAL_CCSTATE_INTERCEPED_KEY, type Getter, type PackedEventMessage, type Read, type Setter, type State, type Store, StoreEvent, type StoreEventType, type StoreInterceptor, StoreProvider, type Subscribe, type Updater, type Write, command, computed, createConsoleDebugStore, createDebugStore, createStore, nestedAtomToString, setupDevtoolsInterceptor, state, useGet, useLastLoadable, useLastResolved, useLoadable, useResolved, useSet };
package/index.js CHANGED
@@ -1219,13 +1219,18 @@ var ConsoleInterceptor = /*#__PURE__*/_createClass(function ConsoleInterceptor(w
1219
1219
  _classCallCheck(this, ConsoleInterceptor);
1220
1220
  _defineProperty(this, "shouldLog", function (atom, action) {
1221
1221
  return _this.watches.some(function (watch) {
1222
+ var atomMatched = false;
1222
1223
  if (typeof watch.target === 'string') {
1223
- return atom.toString().includes(watch.target);
1224
+ atomMatched = atom.toString().includes(watch.target);
1225
+ } else if (watch.target instanceof RegExp) {
1226
+ atomMatched = watch.target.test(atom.toString());
1227
+ } else {
1228
+ atomMatched = watch.target === atom;
1224
1229
  }
1225
- if (watch.target instanceof RegExp) {
1226
- return watch.target.test(atom.toString());
1230
+ if (!atomMatched) {
1231
+ return false;
1227
1232
  }
1228
- return watch.target === atom && (!watch.actions || watch.actions.has(action));
1233
+ return !watch.actions || watch.actions.has(action);
1229
1234
  });
1230
1235
  });
1231
1236
  _defineProperty(this, "get", function (atom$, fn) {
@@ -1300,6 +1305,25 @@ var ConsoleInterceptor = /*#__PURE__*/_createClass(function ConsoleInterceptor(w
1300
1305
  });
1301
1306
  this.watches = watches;
1302
1307
  });
1308
+ function createConsoleDebugStore(watches, defaultActions) {
1309
+ var parsedWatches = watches.map(function (watch) {
1310
+ if (typeof watch === 'string' || watch instanceof RegExp) {
1311
+ return {
1312
+ target: watch,
1313
+ actions: defaultActions ? new Set(defaultActions) : undefined
1314
+ };
1315
+ }
1316
+ if ('target' in watch) {
1317
+ return watch;
1318
+ }
1319
+ return {
1320
+ target: watch,
1321
+ actions: defaultActions ? new Set(defaultActions) : undefined
1322
+ };
1323
+ });
1324
+ var interceptor = new ConsoleInterceptor(parsedWatches);
1325
+ return createDebugStore(interceptor);
1326
+ }
1303
1327
 
1304
1328
  var StoreEvent = /*#__PURE__*/function (_Event) {
1305
1329
  function StoreEvent(type, eventId, targetAtom, state, time, args, result) {
@@ -1576,4 +1600,4 @@ function useLastResolved(atom) {
1576
1600
  return loadable.state === 'hasData' ? loadable.data : undefined;
1577
1601
  }
1578
1602
 
1579
- export { ConsoleInterceptor, EventInterceptor, GLOBAL_CCSTATE_INTERCEPED_KEY, StoreEvent, StoreProvider, command, computed, createDebugStore, createStore, nestedAtomToString, setupDevtoolsInterceptor, state, useGet, useLastLoadable, useLastResolved, useLoadable, useResolved, useSet };
1603
+ export { ConsoleInterceptor, EventInterceptor, GLOBAL_CCSTATE_INTERCEPED_KEY, StoreEvent, StoreProvider, command, computed, createConsoleDebugStore, createDebugStore, createStore, nestedAtomToString, setupDevtoolsInterceptor, state, useGet, useLastLoadable, useLastResolved, useLoadable, useResolved, useSet };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ccstate",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "CCState Core",
5
5
  "private": false,
6
6
  "repository": {
@@ -10,6 +10,7 @@
10
10
  "license": "MIT",
11
11
  "type": "module",
12
12
  "main": "./index.cjs",
13
+ "module": "./index.js",
13
14
  "exports": {
14
15
  ".": {
15
16
  "import": "./index.js",