fractostate 1.0.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/LICENSE +13 -0
- package/README.md +83 -0
- package/docs/api-reference.md +46 -0
- package/docs/architecture.md +27 -0
- package/docs/getting-started.md +94 -0
- package/package.json +37 -0
- package/src/index.ts +82 -0
- package/src/proxy.ts +313 -0
- package/src/store.ts +324 -0
- package/src/types.ts +126 -0
- package/test/README.md +73 -0
- package/test/eslint.config.js +23 -0
- package/test/index.html +13 -0
- package/test/package.json +47 -0
- package/test/postcss.config.mjs +7 -0
- package/test/public/vite.svg +1 -0
- package/test/src/App.css +42 -0
- package/test/src/App.tsx +44 -0
- package/test/src/assets/react.svg +1 -0
- package/test/src/components/CartDrawer.tsx +79 -0
- package/test/src/components/Navbar.tsx +48 -0
- package/test/src/components/Notifications.tsx +27 -0
- package/test/src/components/ProductList.tsx +56 -0
- package/test/src/flows.ts +7 -0
- package/test/src/index.css +33 -0
- package/test/src/layout/Layout.tsx +68 -0
- package/test/src/layout/ProtectedRoute.tsx +19 -0
- package/test/src/main.tsx +10 -0
- package/test/src/pages/LoginPage.tsx +86 -0
- package/test/src/pages/ProfilePage.tsx +48 -0
- package/test/src/pages/ShopPage.tsx +54 -0
- package/test/src/store/auth.ts +39 -0
- package/test/src/store/flows.ts +74 -0
- package/test/tsconfig.app.json +31 -0
- package/test/tsconfig.json +7 -0
- package/test/tsconfig.node.json +29 -0
- package/test/vite.config.ts +16 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
NEHONIX Open Source License (NOSL) v1.0
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 NEHONIX - www.nehonix.com
|
|
4
|
+
|
|
5
|
+
This License governs the use, modification, and distribution of software provided by NEHONIX under its open source projects. NEHONIX is committed to fostering collaborative innovation while strictly protecting its intellectual property rights. Violation of any term of this License will result in immediate termination of all granted rights and may subject the violator to legal action.
|
|
6
|
+
|
|
7
|
+
The full version of this license is available at: https://dll.nehonix.com/licenses/NOSL
|
|
8
|
+
|
|
9
|
+
> **DISCLAIMER OF WARRANTY**
|
|
10
|
+
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
|
|
11
|
+
|
|
12
|
+
> **LIMITATION OF LIABILITY**
|
|
13
|
+
> IN NO EVENT SHALL NEHONIX BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ARISING FROM THE USE OR INABILITY TO USE THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
package/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# FractoState: Think Fractal. Code Simple.
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://dll.nehonix.com/assets/FractoState/logo.png" alt="FractoState Logo" width="600" />
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
FractoState is a high-performance, decentralized state management library for React. It is engineered to provide surgical state updates with zero boilerplate, absolute type safety, and an architecture that exists independently of the React component tree.
|
|
8
|
+
|
|
9
|
+
## See it in Action
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<video
|
|
13
|
+
src="https://dll.nehonix.com/assets/FractoState/fracto_demo.mp4"
|
|
14
|
+
width="100%"
|
|
15
|
+
controls
|
|
16
|
+
loop
|
|
17
|
+
muted
|
|
18
|
+
></video>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
> ⚠️ **GitHub Limitation**
|
|
22
|
+
> Autoplay is disabled on GitHub. Click the link below to view the demo video.
|
|
23
|
+
|
|
24
|
+
<p align="center">
|
|
25
|
+
<a href="https://dll.nehonix.com/assets/FractoState/fracto_demo.mp4">
|
|
26
|
+
▶️ <strong>Watch the FractoState Demo (MP4)</strong>
|
|
27
|
+
</a>
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
## The Problem
|
|
31
|
+
|
|
32
|
+
Traditional state management solutions often suffer from specific architectural bottlenecks:
|
|
33
|
+
|
|
34
|
+
1. **Prop-Drilling & Context Overhead**: Managing shared state requires wrapping the application in multiple providers, often leading to unnecessary re-renders of the entire sub-tree when a small value changes.
|
|
35
|
+
2. **Boilerplate Complexity**: Redux and similar libraries introduce a heavy cognitive load with actions, reducers, and selectors for even the simplest state transitions.
|
|
36
|
+
3. **Performance Degit**: JavaScript's standard object handling for deep state often forces developers into expensive deep-cloning patterns for every modification.
|
|
37
|
+
4. **Security Risks**: Application state is often stored in plain objects easily accessible via browser dev tools or memory dumps.
|
|
38
|
+
|
|
39
|
+
## The Solution
|
|
40
|
+
|
|
41
|
+
FractoState transforms state management into a "Side-Car" service through three core innovations:
|
|
42
|
+
|
|
43
|
+
- **Secure Memory Vault**: State is isolated in a private JavaScript instance. Data is stored in an obfuscated format to prevent easy inspection and is protected against unauthorized global access.
|
|
44
|
+
- **Surgical Proxy Mutations**: Instead of manually handling immutability, FractoState uses recursive Proxies. You interact with state as if it were a direct object, while the engine performs atomic, immuable updates under the hood.
|
|
45
|
+
- **Provider-less Decoupling**: Components subscribe directly to the Vault. This eliminates the need for context providers and ensures that state updates only trigger re-renders in the exact components that consume the modified data.
|
|
46
|
+
|
|
47
|
+
## Quick Example
|
|
48
|
+
|
|
49
|
+
Setting up a shared ecommerce cart state:
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { defineFlow, useFlow } from "fractostate";
|
|
53
|
+
|
|
54
|
+
// 1. Define the business logic flow
|
|
55
|
+
const CartFlow = defineFlow("cart", { items: [], total: 0 });
|
|
56
|
+
|
|
57
|
+
// 2. Consume and modify in any component
|
|
58
|
+
function AddToCartButton({ product }) {
|
|
59
|
+
const [, { ops }] = useFlow(CartFlow);
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<button onClick={() => ops.self.items.push(product)}>Add to Cart</button>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 3. React to updates elsewhere
|
|
67
|
+
function CartIcon() {
|
|
68
|
+
const [cart] = useFlow(CartFlow);
|
|
69
|
+
return <span>{cart.items.length} items</span>;
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Documentation
|
|
74
|
+
|
|
75
|
+
For detailed information on the library, please refer to the modular documentation files:
|
|
76
|
+
|
|
77
|
+
- [Architecture Overview](./docs/architecture.md): Deep dive into the Vault and Proxy engine.
|
|
78
|
+
- [Getting Started](./docs/getting-started.md): Installation and basic setup guide.
|
|
79
|
+
- [API Reference](./docs/api-reference.md): Detailed documentation of hooks and operations.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
FractoState - Engineered for Performance. Created for Developers.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
A detailed breakdown of the FractoState interface.
|
|
4
|
+
|
|
5
|
+
## defineFlow<T>(key, initialValue, options?)
|
|
6
|
+
|
|
7
|
+
Creates a reusable definition for a state flow.
|
|
8
|
+
|
|
9
|
+
- **key**: A unique string identifying the flow in the global vault.
|
|
10
|
+
- **initialValue**: The default state structure.
|
|
11
|
+
- **options**: Configuration object (timeTravel, debounce, middleware).
|
|
12
|
+
|
|
13
|
+
Returns a `FlowDefinition<T>`.
|
|
14
|
+
|
|
15
|
+
## useFlow<T>(identifier, initialValue?, options?)
|
|
16
|
+
|
|
17
|
+
The primary hook to interact with the state vault.
|
|
18
|
+
|
|
19
|
+
- **identifier**: Either a string `key` or a `FlowDefinition`.
|
|
20
|
+
- **initialValue**: Required only if identifier is a string and the flow hasn't been initialized.
|
|
21
|
+
- **options**: Overrides for the flow configuration.
|
|
22
|
+
|
|
23
|
+
Returns `[state, toolbox]`.
|
|
24
|
+
|
|
25
|
+
### The Toolbox Object
|
|
26
|
+
|
|
27
|
+
The second element returned by `useFlow` provides powerful control:
|
|
28
|
+
|
|
29
|
+
- **ops.self**: A recursive proxy providing type-aware methods:
|
|
30
|
+
- **Numbers**: `increment()`, `decrement()`, `add()`, `multiply()`, `divide()`, `set()`.
|
|
31
|
+
- **Strings**: `append()`, `prepend()`, `uppercase()`, `replace()`, `set()`.
|
|
32
|
+
- **Arrays**: `push()`, `pop()`, `filter()`, `map()`, `insertAt()`, `removeAt()`, `set()`.
|
|
33
|
+
- **Objects**: `merge()`, `delete()`, `set()`.
|
|
34
|
+
- **set(value | fn)**: Manually sets the entire state or applies a transformation function.
|
|
35
|
+
- **undo()**: Reverts to the previous state.
|
|
36
|
+
- **redo()**: Restores the previously undone state.
|
|
37
|
+
- **history**: The full history buffer of the flow.
|
|
38
|
+
- **canUndo / canRedo**: Boolean flags for UI control.
|
|
39
|
+
- **reset()**: Restores the state to its defined initial value.
|
|
40
|
+
|
|
41
|
+
## FlowOptions
|
|
42
|
+
|
|
43
|
+
- **timeTravel**: Enable undo/redo functionality (default: false).
|
|
44
|
+
- **maxHistory**: Maximum number of states maintained in the circular buffer (default: 100).
|
|
45
|
+
- **debounce**: Delay in milliseconds before state updates are applied.
|
|
46
|
+
- **middleware**: Array of functions `(state) => state` to intercept and transform values during updates.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Architecture: Secure Memory Vault
|
|
2
|
+
|
|
3
|
+
FractoState operates on a paradigm shift in state management. Instead of relying on a hierarchical data flow injected through component trees, it utilizes a decentralized, side-car architecture.
|
|
4
|
+
|
|
5
|
+
## The Memory Vault
|
|
6
|
+
|
|
7
|
+
At the core of FractoState is the SecureVault. This is a pure JavaScript singleton that exists independently of the React lifecycle. It holds the application state in a protected memory space.
|
|
8
|
+
|
|
9
|
+
### Security and Isolation
|
|
10
|
+
|
|
11
|
+
Data within the Vault is stored in an obfuscated format. This prevents simple memory inspection and ensures that user data is not readily available in plain text within the browser's RAM. Access is strictly controlled through the FractoState internal engine, returning copies of the data to components to prevent accidental direct mutations.
|
|
12
|
+
|
|
13
|
+
## Proxy-Based Mutation Engine
|
|
14
|
+
|
|
15
|
+
FractoState leverages JavaScript Proxies to provide a surgical update mechanism. When you access `ops.self`, you are interacting with a recursive proxy that maps your state structure to specific atomic operations.
|
|
16
|
+
|
|
17
|
+
### Type-Aware Operations
|
|
18
|
+
|
|
19
|
+
The proxy identifies the data type at any given path (Number, String, Array, or Object) and presents relevant, type-safe methods. This allows for complex state updates—like pushing to a nested array or merging into a deep object—without the need for manual immutability boilerplate.
|
|
20
|
+
|
|
21
|
+
## Decoupled React Integration
|
|
22
|
+
|
|
23
|
+
The `useFlow` hook acts as a high-performance bridge. It subscribes components to specific segments of the Vault.
|
|
24
|
+
|
|
25
|
+
- **Selective Re-rendering**: Components are only notified when the specific key they are watching is updated.
|
|
26
|
+
- **Provider-less Execution**: Since the store is external, there is no need for context providers. This eliminates the "Wrapper Hell" and ensures that any component, at any depth, can access state with zero performance penalty.
|
|
27
|
+
- **Microtask Batching**: Multiple state changes within the same execution cycle are batched into a single microtask, ensuring optimal UI performance and preventing unnecessary render cycles.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Getting Started with FractoState
|
|
2
|
+
|
|
3
|
+
This guide will walk you through the integration of FractoState into a React application.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Ensure you have the library within your project's source directory (currently in development).
|
|
8
|
+
|
|
9
|
+
## Core Concepts
|
|
10
|
+
|
|
11
|
+
FractoState is built around "Flows". A Flow is a reactive stream of data identified by a unique key.
|
|
12
|
+
|
|
13
|
+
### 1. Defining a Flow
|
|
14
|
+
|
|
15
|
+
Centralize your state structure and initial values using `defineFlow`. This promotes reusability and type safety.
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// store/flows.ts
|
|
19
|
+
import { defineFlow } from "fractostate";
|
|
20
|
+
|
|
21
|
+
export const UserFlow = defineFlow("user", {
|
|
22
|
+
name: "Default User",
|
|
23
|
+
settings: { theme: "dark" },
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 2. Using a Flow in a Component
|
|
28
|
+
|
|
29
|
+
Use the `useFlow` hook to connect any component to the state.
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { useFlow } from "fractostate";
|
|
33
|
+
import { UserFlow } from "./store/flows";
|
|
34
|
+
|
|
35
|
+
export default function Profile() {
|
|
36
|
+
const [state, { ops }] = useFlow(UserFlow);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<div>
|
|
40
|
+
<h1>User: {state.name}</h1>
|
|
41
|
+
<button onClick={() => ops.self.name.set("New Name")}>Update Name</button>
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 3. Sharing State Across Components
|
|
48
|
+
|
|
49
|
+
To consume or modify the same state in another component, simply use the same `UserFlow` definition. No providers or context required.
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { useFlow } from "fractostate";
|
|
53
|
+
import { UserFlow } from "./store/flows";
|
|
54
|
+
|
|
55
|
+
export default function Sidebar() {
|
|
56
|
+
const [state] = useFlow(UserFlow); // Automatically synchronizes with the Profile component
|
|
57
|
+
return <aside>Active theme: {state.settings.theme}</aside>;
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 4. Advanced Configuration
|
|
62
|
+
|
|
63
|
+
You can enable features like Time Travel or Middleware directly in the definition or the hook.
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
// Enable Undo/Redo and middleware for logging
|
|
67
|
+
export const CartFlow = defineFlow(
|
|
68
|
+
"cart",
|
|
69
|
+
{ items: [] },
|
|
70
|
+
{
|
|
71
|
+
timeTravel: true,
|
|
72
|
+
middleware: [
|
|
73
|
+
(state) => {
|
|
74
|
+
console.log("Cart updated:", state);
|
|
75
|
+
return state;
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Using Time Travel in a component:
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
function CartControls() {
|
|
86
|
+
const [cart, { undo, redo, canUndo }] = useFlow(CartFlow);
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<button onClick={undo} disabled={!canUndo}>
|
|
90
|
+
Undo Last Item
|
|
91
|
+
</button>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"author": "Nehonix-Team",
|
|
3
|
+
"dependencies": {
|
|
4
|
+
"vite": "^7.3.1"
|
|
5
|
+
},
|
|
6
|
+
"description": "FractoState is a high-performance, decentralized state management library for React. It is engineered to provide surgical state updates with zero boilerplate, absolute type safety, and an architecture that exists independently of the React component tree.",
|
|
7
|
+
"devDependencies": {
|
|
8
|
+
"@types/react": "^19.2.9",
|
|
9
|
+
"react": "^18.0.0",
|
|
10
|
+
"tsup": "^8.0.0",
|
|
11
|
+
"typescript": "^5.0.0",
|
|
12
|
+
"vitest": "^1.0.0"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"react",
|
|
16
|
+
"state",
|
|
17
|
+
"management",
|
|
18
|
+
"fractal",
|
|
19
|
+
"global state",
|
|
20
|
+
"hooks"
|
|
21
|
+
],
|
|
22
|
+
"license": "N",
|
|
23
|
+
"main": "dist/index.js",
|
|
24
|
+
"module": "dist/index.mjs",
|
|
25
|
+
"name": "fractostate",
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"react": ">=16.8.0"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsup src/index.ts --dts --format esm,cjs",
|
|
31
|
+
"dev": "tsup src/index.ts --watch --dts --format esm,cjs",
|
|
32
|
+
"lint": "eslint src",
|
|
33
|
+
"test": "vitest"
|
|
34
|
+
},
|
|
35
|
+
"types": "dist/index.d.ts",
|
|
36
|
+
"version": "1.0.0"
|
|
37
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { useState, useEffect, useCallback, useMemo } from "react";
|
|
2
|
+
import type { FlowOptions, FlowOperations, FlowDefinition } from "./types";
|
|
3
|
+
import { store } from "./store";
|
|
4
|
+
import { createDeepProxy } from "./proxy";
|
|
5
|
+
|
|
6
|
+
export * from "./types";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Defines a flow in a centralized manner.
|
|
10
|
+
* Allows defining the key, initial state, and options in a single reusable object.
|
|
11
|
+
*/
|
|
12
|
+
export function defineFlow<T>(
|
|
13
|
+
key: string,
|
|
14
|
+
initial: T,
|
|
15
|
+
options?: FlowOptions<T>,
|
|
16
|
+
): FlowDefinition<T> {
|
|
17
|
+
return { key, initial, options };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Unique "All-in-One" hook to create or consume a FractoState flow.
|
|
22
|
+
* - If called with a FlowDefinition or an initial value: initializes the flow if it doesn't exist.
|
|
23
|
+
* - If called with just a key: connects to the existing flow.
|
|
24
|
+
*
|
|
25
|
+
* Returns a 2-element array: [state, toolbox]
|
|
26
|
+
* where toolbox contains { ops, set, undo, redo, history, ... }
|
|
27
|
+
*/
|
|
28
|
+
export function useFlow<T>(
|
|
29
|
+
keyOrDef: string | FlowDefinition<T>,
|
|
30
|
+
maybeInitialValue?: T,
|
|
31
|
+
options: FlowOptions<T> = {},
|
|
32
|
+
): [T, FlowOperations<T>] {
|
|
33
|
+
// Argument analysis to unify initialization and consumption
|
|
34
|
+
const isDef = typeof keyOrDef !== "string";
|
|
35
|
+
const key = isDef ? keyOrDef.key : keyOrDef;
|
|
36
|
+
|
|
37
|
+
// Initial data comes either from the definition or the direct argument
|
|
38
|
+
const initialValue = isDef ? keyOrDef.initial : maybeInitialValue;
|
|
39
|
+
|
|
40
|
+
// Merge options
|
|
41
|
+
const opt = isDef ? { ...keyOrDef.options, ...options } : options;
|
|
42
|
+
|
|
43
|
+
// Store access: store.get handles initialization if initialValue is present
|
|
44
|
+
const [state, setState] = useState(() => store.get(key, initialValue));
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
// Subscribe to store changes
|
|
48
|
+
const unsub = store.subscribe(key, () => {
|
|
49
|
+
setState(store.get(key, initialValue));
|
|
50
|
+
});
|
|
51
|
+
return unsub;
|
|
52
|
+
}, [key, initialValue]);
|
|
53
|
+
|
|
54
|
+
const setManual = useCallback(
|
|
55
|
+
(val: T | ((prev: T) => T)) => {
|
|
56
|
+
const current = store.get(key, initialValue);
|
|
57
|
+
const next = typeof val === "function" ? (val as any)(current) : val;
|
|
58
|
+
store.set(key, next, opt);
|
|
59
|
+
},
|
|
60
|
+
[key, initialValue, opt],
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const toolbox = useMemo((): FlowOperations<T> => {
|
|
64
|
+
return {
|
|
65
|
+
ops: {
|
|
66
|
+
get self() {
|
|
67
|
+
return createDeepProxy<T>(key, [], store.get(key, initialValue), opt);
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
set: setManual,
|
|
71
|
+
undo: () => store.undo(key),
|
|
72
|
+
redo: () => store.redo(key),
|
|
73
|
+
history: store.getHistory(key),
|
|
74
|
+
canUndo: store.getHistory(key).length > 1,
|
|
75
|
+
canRedo: store.getRedoStack(key).length > 0,
|
|
76
|
+
reset: () => store.reset(key),
|
|
77
|
+
cf: opt,
|
|
78
|
+
};
|
|
79
|
+
}, [key, opt, state, initialValue, setManual]);
|
|
80
|
+
|
|
81
|
+
return [state, toolbox];
|
|
82
|
+
}
|