totally-tubular 0.3.3 → 0.4.1
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 +82 -37
- package/dist/object.d.ts +3 -0
- package/dist/object.js +9 -0
- package/dist/react.d.ts +23 -0
- package/dist/react.js +25 -0
- package/dist/totally-tubular.d.ts +7 -0
- package/dist/totally-tubular.js +29 -9
- package/dist/types.d.ts +2 -2
- package/package.json +23 -17
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ npm i totally-tubular --save
|
|
|
18
18
|
|
|
19
19
|
## Core concepts
|
|
20
20
|
|
|
21
|
-
A `Tubular` instance wraps an object and gives you
|
|
21
|
+
A `Tubular` instance wraps an object and gives you five things:
|
|
22
22
|
|
|
23
23
|
| Method | What it does |
|
|
24
24
|
|---|---|
|
|
@@ -26,6 +26,7 @@ A `Tubular` instance wraps an object and gives you four things:
|
|
|
26
26
|
| `update(path, fn)` | Calls `fn` with the current value, stores the return value, then notifies all observers |
|
|
27
27
|
| `observe(path, fn)` | Registers a callback that fires whenever `path` is updated |
|
|
28
28
|
| `unobserve(path, fn)` | Removes a previously registered callback |
|
|
29
|
+
| `reset()` | Restores every key to its initial value and notifies all observers of each change |
|
|
29
30
|
|
|
30
31
|
Paths are fully type-checked. TypeScript knows every valid dot-path into your state shape, so you get autocomplete and a compile error if you mistype a key.
|
|
31
32
|
|
|
@@ -63,6 +64,30 @@ store.update("meta.title", (prev) => `Supreme ${prev}`);
|
|
|
63
64
|
console.info(store.read("meta.title")); // "Supreme Director"
|
|
64
65
|
```
|
|
65
66
|
|
|
67
|
+
## Resetting state
|
|
68
|
+
|
|
69
|
+
Call `reset()` to restore your entire state back to the value you passed to the constructor. Every updated key is restored and every registered observer fires with the new (initial) value.
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
const store = new Tubular({
|
|
73
|
+
name: "Alice",
|
|
74
|
+
count: 0,
|
|
75
|
+
settings: { theme: "light" },
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
store.update("name", () => "Bob");
|
|
79
|
+
store.update("count", (prev) => prev + 1);
|
|
80
|
+
store.update("settings.theme", () => "dark");
|
|
81
|
+
|
|
82
|
+
store.observe("name", (newVal, oldVal) => {
|
|
83
|
+
console.log(`name: ${oldVal} -> ${newVal}`);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
store.reset();
|
|
87
|
+
// Logs: name: Bob -> Alice
|
|
88
|
+
// Reads back: "Alice", 0, { theme: "light" }
|
|
89
|
+
```
|
|
90
|
+
|
|
66
91
|
## React
|
|
67
92
|
|
|
68
93
|
Import `useTubular` from `totally-tubular/react`. It works exactly like React's
|
|
@@ -115,6 +140,24 @@ setCount((prev) => (prev ?? 0) + 1);
|
|
|
115
140
|
`useTubular` automatically unsubscribes when the component unmounts, so you
|
|
116
141
|
don't need to manage cleanup yourself.
|
|
117
142
|
|
|
143
|
+
### Resetting from React
|
|
144
|
+
|
|
145
|
+
Import `useTubularReset` from `totally-tubular/react`. It returns a stable
|
|
146
|
+
callback that restores the store to its initial state. Every `useTubular` hook
|
|
147
|
+
watching the store re-renders with the restored value.
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
import { useTubularReset } from "totally-tubular/react";
|
|
151
|
+
|
|
152
|
+
function ResetButton() {
|
|
153
|
+
const handleReset = useTubularReset(store);
|
|
154
|
+
return <button onClick={handleReset}>Reset</button>;
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The callback identity never changes, so it's safe to pass directly as an event
|
|
159
|
+
handler or as a dependency to `useEffect`.
|
|
160
|
+
|
|
118
161
|
## Things you should know
|
|
119
162
|
|
|
120
163
|
- **Arrays and nested objects are observed at their path, not their contents.**
|
|
@@ -125,53 +168,55 @@ don't need to manage cleanup yourself.
|
|
|
125
168
|
|
|
126
169
|
## Performance benchmarks
|
|
127
170
|
|
|
171
|
+
All benchmarks were run with Node.js 26.5.0 using the `tsx` TypeScript interpreter.
|
|
172
|
+
|
|
128
173
|
### Apple M3 Max · 36 GB RAM · macOS Sequoia 15.5
|
|
129
174
|
|
|
130
175
|
```
|
|
131
176
|
-----shallow state object-----
|
|
132
177
|
|
|
133
|
-
1,000 updates to "name" string val with 10 observers: 0.
|
|
134
|
-
1,000 updates to "name" string val with 100 observers: 0.
|
|
135
|
-
1,000 updates to "name" string val with 1000 observers: 0.
|
|
136
|
-
10,000 updates to "name" string val with 10 observers: 0.
|
|
137
|
-
10,000 updates to "name" string val with 100 observers: 0.
|
|
138
|
-
10,000 updates to "name" string val with 1000 observers: 0.
|
|
139
|
-
100,000 updates to "name" string val with 10 observers: 0.
|
|
140
|
-
100,000 updates to "name" string val with 100 observers: 0.
|
|
141
|
-
100,000 updates to "name" string val with 1000 observers: 0.
|
|
142
|
-
1,000,000 updates to "name" string val with 10 observers: 0.
|
|
143
|
-
1,000,000 updates to "name" string val with 100 observers: 0.
|
|
144
|
-
1,000,000 updates to "name" string val with 1000 observers:
|
|
178
|
+
1,000 updates to "name" string val with 10 observers: 0.0005343750000000114s
|
|
179
|
+
1,000 updates to "name" string val with 100 observers: 0.0006880840000000035s
|
|
180
|
+
1,000 updates to "name" string val with 1000 observers: 0.002814292000000023s
|
|
181
|
+
10,000 updates to "name" string val with 10 observers: 0.0007928750000000377s
|
|
182
|
+
10,000 updates to "name" string val with 100 observers: 0.0017347500000000195s
|
|
183
|
+
10,000 updates to "name" string val with 1000 observers: 0.007635916000000009s
|
|
184
|
+
100,000 updates to "name" string val with 10 observers: 0.01587337500000001s
|
|
185
|
+
100,000 updates to "name" string val with 100 observers: 0.020373334s
|
|
186
|
+
100,000 updates to "name" string val with 1000 observers: 0.12892133400000005s
|
|
187
|
+
1,000,000 updates to "name" string val with 10 observers: 0.14660462499999993s
|
|
188
|
+
1,000,000 updates to "name" string val with 100 observers: 0.20982341600000007s
|
|
189
|
+
1,000,000 updates to "name" string val with 1000 observers: 0.8595329590000002s
|
|
145
190
|
|
|
146
191
|
-----medium state object-----
|
|
147
192
|
|
|
148
|
-
1,000 updates to "user.settings.theme" string val with 10 observers: 0.
|
|
149
|
-
1,000 updates to "user.settings.theme" string val with 100 observers: 0.
|
|
150
|
-
1,000 updates to "user.settings.theme" string val with 1000 observers: 0.
|
|
151
|
-
10,000 updates to "user.settings.theme" string val with 10 observers: 0.
|
|
152
|
-
10,000 updates to "user.settings.theme" string val with 100 observers: 0.
|
|
153
|
-
10,000 updates to "user.settings.theme" string val with 1000 observers: 0.
|
|
154
|
-
100,000 updates to "user.settings.theme" string val with 10 observers: 0.
|
|
155
|
-
100,000 updates to "user.settings.theme" string val with 100 observers: 0.
|
|
156
|
-
100,000 updates to "user.settings.theme" string val with 1000 observers: 0.
|
|
157
|
-
1,000,000 updates to "user.settings.theme" string val with 10 observers: 0.
|
|
158
|
-
1,000,000 updates to "user.settings.theme" string val with 100 observers: 0.
|
|
159
|
-
1,000,000 updates to "user.settings.theme" string val with 1000 observers:
|
|
193
|
+
1,000 updates to "user.settings.theme" string val with 10 observers: 0.0011529580000001261s
|
|
194
|
+
1,000 updates to "user.settings.theme" string val with 100 observers: 0.002206040999999914s
|
|
195
|
+
1,000 updates to "user.settings.theme" string val with 1000 observers: 0.006846457999999984s
|
|
196
|
+
10,000 updates to "user.settings.theme" string val with 10 observers: 0.01919616700000006s
|
|
197
|
+
10,000 updates to "user.settings.theme" string val with 100 observers: 0.007707957999999963s
|
|
198
|
+
10,000 updates to "user.settings.theme" string val with 1000 observers: 0.014114458000000014s
|
|
199
|
+
100,000 updates to "user.settings.theme" string val with 10 observers: 0.012900958000000174s
|
|
200
|
+
100,000 updates to "user.settings.theme" string val with 100 observers: 0.018197167000000035s
|
|
201
|
+
100,000 updates to "user.settings.theme" string val with 1000 observers: 0.09116387499999973s
|
|
202
|
+
1,000,000 updates to "user.settings.theme" string val with 10 observers: 0.18448416599999973s
|
|
203
|
+
1,000,000 updates to "user.settings.theme" string val with 100 observers: 0.24980879200000028s
|
|
204
|
+
1,000,000 updates to "user.settings.theme" string val with 1000 observers: 0.8701055419999998s
|
|
160
205
|
|
|
161
206
|
-----deep state object-----
|
|
162
207
|
|
|
163
|
-
1,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 10 observers: 0.
|
|
164
|
-
1,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 100 observers: 0.
|
|
165
|
-
1,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 1000 observers: 0.
|
|
166
|
-
10,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 10 observers: 0.
|
|
167
|
-
10,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 100 observers: 0.
|
|
168
|
-
10,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 1000 observers: 0.
|
|
169
|
-
100,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 10 observers: 0.
|
|
170
|
-
100,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 100 observers: 0.
|
|
171
|
-
100,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 1000 observers: 0.
|
|
172
|
-
1,000,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 10 observers: 0.
|
|
173
|
-
1,000,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 100 observers: 0.
|
|
174
|
-
1,000,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 1000 observers:
|
|
208
|
+
1,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 10 observers: 0.0002052080000003116s
|
|
209
|
+
1,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 100 observers: 0.0002497920000000704s
|
|
210
|
+
1,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 1000 observers: 0.001332209000000148s
|
|
211
|
+
10,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 10 observers: 0.0018820000000000618s
|
|
212
|
+
10,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 100 observers: 0.0024639170000000377s
|
|
213
|
+
10,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 1000 observers: 0.014082249999999932s
|
|
214
|
+
100,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 10 observers: 0.021280209000000015s
|
|
215
|
+
100,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 100 observers: 0.02714695800000027s
|
|
216
|
+
100,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 1000 observers: 0.09046704200000022s
|
|
217
|
+
1,000,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 10 observers: 0.2687363329999998s
|
|
218
|
+
1,000,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 100 observers: 0.3244868329999999s
|
|
219
|
+
1,000,000 updates to "zdeepSettings.level1.level2.level3.level4.level5.level6.currentValue" string val with 1000 observers: 0.9486893330000002s
|
|
175
220
|
```
|
|
176
221
|
|
|
177
222
|
### Intel i9-13900HX · 32 GB RAM · Windows 11
|
package/dist/object.d.ts
ADDED
package/dist/object.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function isArray(thing) {
|
|
2
|
+
return Array.isArray(thing);
|
|
3
|
+
}
|
|
4
|
+
export function isObject(thing) {
|
|
5
|
+
return typeof thing === 'object';
|
|
6
|
+
}
|
|
7
|
+
export function isNullOrUndefined(thing) {
|
|
8
|
+
return thing === null || thing === undefined || typeof thing === 'undefined';
|
|
9
|
+
}
|
package/dist/react.d.ts
CHANGED
|
@@ -28,3 +28,26 @@ import type { AllObjectKeys, PropType } from './types.js';
|
|
|
28
28
|
* ```
|
|
29
29
|
*/
|
|
30
30
|
export declare function useTubular<T extends object, K extends string>(tubular: Tubular<T>, key: K & AllObjectKeys<T>): readonly [PropType<T, K> | null, (newValOrCallback: PropType<T, K> | ((prevVal: PropType<T, K> | null) => PropType<T, K>)) => void];
|
|
31
|
+
/**
|
|
32
|
+
* A React hook that returns a stable callback to reset a {@link Tubular} store
|
|
33
|
+
* back to its initial state.
|
|
34
|
+
*
|
|
35
|
+
* Every key in the store is restored to the value originally passed to the
|
|
36
|
+
* constructor, and every registered observer (including {@link useTubular}
|
|
37
|
+
* hooks) is notified of each change.
|
|
38
|
+
*
|
|
39
|
+
* The returned callback is stable across re-renders.
|
|
40
|
+
* It never changes its identity, so it is safe to pass as a dependency to `useEffect` or as a prop
|
|
41
|
+
* to memoized components.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```tsx
|
|
45
|
+
* const store = new Tubular({ name: 'Alice', count: 0 });
|
|
46
|
+
*
|
|
47
|
+
* function ResetButton() {
|
|
48
|
+
* const handleReset = useTubularReset(store);
|
|
49
|
+
* return <button onClick={handleReset}>Reset</button>;
|
|
50
|
+
* }
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function useTubularReset<T extends object>(tubular: Tubular<T>): () => void;
|
package/dist/react.js
CHANGED
|
@@ -52,3 +52,28 @@ export function useTubular(tubular, key) {
|
|
|
52
52
|
}, [tubular, key]);
|
|
53
53
|
return [val, handleUpdateVal];
|
|
54
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* A React hook that returns a stable callback to reset a {@link Tubular} store
|
|
57
|
+
* back to its initial state.
|
|
58
|
+
*
|
|
59
|
+
* Every key in the store is restored to the value originally passed to the
|
|
60
|
+
* constructor, and every registered observer (including {@link useTubular}
|
|
61
|
+
* hooks) is notified of each change.
|
|
62
|
+
*
|
|
63
|
+
* The returned callback is stable across re-renders.
|
|
64
|
+
* It never changes its identity, so it is safe to pass as a dependency to `useEffect` or as a prop
|
|
65
|
+
* to memoized components.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```tsx
|
|
69
|
+
* const store = new Tubular({ name: 'Alice', count: 0 });
|
|
70
|
+
*
|
|
71
|
+
* function ResetButton() {
|
|
72
|
+
* const handleReset = useTubularReset(store);
|
|
73
|
+
* return <button onClick={handleReset}>Reset</button>;
|
|
74
|
+
* }
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export function useTubularReset(tubular) {
|
|
78
|
+
return useCallback(() => tubular.reset(), [tubular]);
|
|
79
|
+
}
|
|
@@ -8,6 +8,7 @@ import type { AllObjectKeys, ObservationCallback, PropType } from './types.js';
|
|
|
8
8
|
export declare class Tubular<T extends object> {
|
|
9
9
|
private observationCallbacks;
|
|
10
10
|
private state;
|
|
11
|
+
private initialStateClone;
|
|
11
12
|
constructor(initialState: T);
|
|
12
13
|
private doSomethingToPath;
|
|
13
14
|
private getPortionOfStateByPath;
|
|
@@ -19,6 +20,12 @@ export declare class Tubular<T extends object> {
|
|
|
19
20
|
* reads a portion of your state
|
|
20
21
|
*/
|
|
21
22
|
read<K extends string>(readPath: K & AllObjectKeys<T>): PropType<T, K> | null;
|
|
23
|
+
private resetImpl;
|
|
24
|
+
/**
|
|
25
|
+
* resets the state back to its initial value
|
|
26
|
+
* (the value you provided to the constructor)
|
|
27
|
+
*/
|
|
28
|
+
reset(): void;
|
|
22
29
|
/**
|
|
23
30
|
* disconnects an observer callback from totally tubular
|
|
24
31
|
*/
|
package/dist/totally-tubular.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isArray, isNullOrUndefined, isObject } from './object.js';
|
|
1
2
|
/**
|
|
2
3
|
* A totally tubular instance that tracks a top-level
|
|
3
4
|
* set of keys and values.
|
|
@@ -7,14 +8,13 @@
|
|
|
7
8
|
export class Tubular {
|
|
8
9
|
observationCallbacks = new Map();
|
|
9
10
|
state;
|
|
11
|
+
initialStateClone;
|
|
10
12
|
constructor(initialState) {
|
|
11
13
|
this.state = initialState;
|
|
14
|
+
this.initialStateClone = globalThis.structuredClone(this.state);
|
|
12
15
|
}
|
|
13
16
|
doSomethingToPath(readPath, doSomething) {
|
|
14
17
|
let thing = this.state;
|
|
15
|
-
if (typeof readPath !== 'string') {
|
|
16
|
-
return this.getPortionOfStateByPath(thing[readPath]);
|
|
17
|
-
}
|
|
18
18
|
const splitPath = readPath.split('.');
|
|
19
19
|
const len = splitPath.length;
|
|
20
20
|
for (let i = 0; i < len; i++) {
|
|
@@ -26,15 +26,9 @@ export class Tubular {
|
|
|
26
26
|
else
|
|
27
27
|
thing = thing?.[p];
|
|
28
28
|
}
|
|
29
|
-
for (const p of splitPath) {
|
|
30
|
-
thing = thing?.[p];
|
|
31
|
-
}
|
|
32
29
|
}
|
|
33
30
|
getPortionOfStateByPath(readPath) {
|
|
34
31
|
let thing = this.state;
|
|
35
|
-
if (typeof readPath !== 'string') {
|
|
36
|
-
return this.getPortionOfStateByPath(thing[readPath]);
|
|
37
|
-
}
|
|
38
32
|
const splitPath = readPath.split('.');
|
|
39
33
|
for (const p of splitPath) {
|
|
40
34
|
thing = thing?.[p];
|
|
@@ -54,6 +48,32 @@ export class Tubular {
|
|
|
54
48
|
read(readPath) {
|
|
55
49
|
return this.getPortionOfStateByPath(readPath);
|
|
56
50
|
}
|
|
51
|
+
resetImpl(parentKey) {
|
|
52
|
+
let sourceObj = this.initialStateClone;
|
|
53
|
+
if (parentKey) {
|
|
54
|
+
for (const p of parentKey.split('.')) {
|
|
55
|
+
sourceObj = sourceObj?.[p];
|
|
56
|
+
}
|
|
57
|
+
if (isNullOrUndefined(sourceObj) || !isObject(sourceObj))
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
for (const [key, val] of Object.entries(sourceObj)) {
|
|
61
|
+
const childKey = parentKey ? `${parentKey}.${key}` : key;
|
|
62
|
+
if (!isNullOrUndefined(val) && isObject(val) && !isArray(val)) {
|
|
63
|
+
this.resetImpl(childKey);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
this.update(childKey, () => val);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* resets the state back to its initial value
|
|
72
|
+
* (the value you provided to the constructor)
|
|
73
|
+
*/
|
|
74
|
+
reset() {
|
|
75
|
+
this.resetImpl();
|
|
76
|
+
}
|
|
57
77
|
/**
|
|
58
78
|
* disconnects an observer callback from totally tubular
|
|
59
79
|
*/
|
package/dist/types.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ type IsCollection<T> = T extends readonly any[] | Map<any, any> | Set<any> ? tru
|
|
|
8
8
|
/**
|
|
9
9
|
* Produces every dot-separated key path into T as a string union.
|
|
10
10
|
*
|
|
11
|
-
* - The `Depth` tuple acts as a recursion counter: when its length reaches
|
|
11
|
+
* - The `Depth` tuple acts as a recursion counter: when its length reaches 10 the
|
|
12
12
|
* type resolves to `never`, which caps the union size and prevents the language
|
|
13
13
|
* server from hanging on deeply-nested or self-referential shapes.
|
|
14
14
|
* - Top-level keys are included as bare strings (`K`), so this type supersedes
|
|
@@ -18,7 +18,7 @@ type IsCollection<T> = T extends readonly any[] | Map<any, any> | Set<any> ? tru
|
|
|
18
18
|
* - Returning `never` (not `''`) from every terminal branch avoids the need for
|
|
19
19
|
* a secondary `Extract<D, string>` pass over the full union.
|
|
20
20
|
*/
|
|
21
|
-
export type DotNestedKeys<T, Depth extends 1[] = []> = Depth['length'] extends
|
|
21
|
+
export type DotNestedKeys<T, Depth extends 1[] = []> = Depth['length'] extends 10 ? never : T extends object ? IsCollection<T> extends true ? never : {
|
|
22
22
|
[K in keyof T & string]: IsCollection<T[K]> extends true ? K : T[K] extends object ? K | `${K}.${DotNestedKeys<T[K], [...Depth, 1]>}` : K;
|
|
23
23
|
}[keyof T & string] : never;
|
|
24
24
|
/**
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "A completely framework-agnostic, JavaScript / TypeScript state management and update broadcasting library wit zero dependencies, solid performance and a micro file size.",
|
|
4
4
|
"name": "totally-tubular",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.4.1",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"state",
|
|
9
9
|
"management",
|
|
@@ -26,25 +26,24 @@
|
|
|
26
26
|
"files": [
|
|
27
27
|
"dist/"
|
|
28
28
|
],
|
|
29
|
-
"scripts": {
|
|
30
|
-
"build": "rm -rf dist/ && tsc --project ./tsconfig.build.json",
|
|
31
|
-
"clean": "rm -rf dist/",
|
|
32
|
-
"test": "bun test",
|
|
33
|
-
"test:watch": "bun test --watch"
|
|
34
|
-
},
|
|
35
29
|
"devDependencies": {
|
|
36
30
|
"@better-builds/lets-version": "^1.6.0",
|
|
37
|
-
"@biomejs/biome": "^2.4.
|
|
38
|
-
"@commitlint/cli": "^20.5.
|
|
39
|
-
"@commitlint/config-conventional": "^20.5.
|
|
40
|
-
"@happy-dom/global-registrator": "^20.9.0",
|
|
31
|
+
"@biomejs/biome": "^2.4.16",
|
|
32
|
+
"@commitlint/cli": "^20.5.3",
|
|
33
|
+
"@commitlint/config-conventional": "^20.5.3",
|
|
41
34
|
"@testing-library/react": "^16.3.2",
|
|
42
35
|
"@testing-library/user-event": "^14.6.1",
|
|
43
|
-
"@types/
|
|
44
|
-
"@types/
|
|
45
|
-
"
|
|
46
|
-
"react": "
|
|
47
|
-
"
|
|
36
|
+
"@types/react": "^19.2.17",
|
|
37
|
+
"@types/node": "^26.1.1",
|
|
38
|
+
"@types/react-dom": "^19.2.3",
|
|
39
|
+
"@vitejs/plugin-react": "^6.0.3",
|
|
40
|
+
"happy-dom": "^20.10.2",
|
|
41
|
+
"react": "^19.2.7",
|
|
42
|
+
"react-dom": "^19.2.7",
|
|
43
|
+
"tsx": "^4.23.0",
|
|
44
|
+
"typescript": "^5.9.3",
|
|
45
|
+
"vite": "^8.1.4",
|
|
46
|
+
"vitest": "^4.1.10"
|
|
48
47
|
},
|
|
49
48
|
"peerDependencies": {
|
|
50
49
|
"react": ">=18"
|
|
@@ -72,5 +71,12 @@
|
|
|
72
71
|
"default": "./dist/types.js"
|
|
73
72
|
},
|
|
74
73
|
"./package.json": "./package.json"
|
|
74
|
+
},
|
|
75
|
+
"scripts": {
|
|
76
|
+
"build": "rm -rf dist/ && tsc --project ./tsconfig.build.json",
|
|
77
|
+
"clean": "rm -rf dist/",
|
|
78
|
+
"test": "vitest test",
|
|
79
|
+
"test:performance": "tsx ./performanceTests.ts",
|
|
80
|
+
"test:watch": "vitest test --watch"
|
|
75
81
|
}
|
|
76
|
-
}
|
|
82
|
+
}
|