@nexigen/entity-normalizer 0.1.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.
Files changed (3) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +268 -0
  3. package/package.json +49 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 negixenjs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,268 @@
1
+ # Nexigen
2
+
3
+ **Entity-Normalized State Management for MobX**
4
+
5
+ Nexigen is an open-source, domain-level state management engine built on top of MobX.
6
+ It provides a strict **entity-first architecture** for managing normalized data,
7
+ relationships, collections, and async workflows in complex applications.
8
+
9
+ Nexigen is designed for applications where:
10
+
11
+ - data has long lifecycles
12
+ - entities are shared across multiple screens
13
+ - consistency and identity stability matter
14
+ - simple stores are no longer enough
15
+
16
+ > Nexigen brings backend-style data modeling and lifecycle guarantees to the client.
17
+
18
+ ---
19
+
20
+ ## Why Nexigen Exists
21
+
22
+ Most client-side state solutions treat data as:
23
+
24
+ - flat objects
25
+ - screen-scoped state
26
+ - short-lived responses
27
+
28
+ This approach breaks down when:
29
+
30
+ - the same entity appears in multiple places
31
+ - pagination, details, and updates overlap
32
+ - memory usage grows over time
33
+ - async logic becomes tangled with UI state
34
+
35
+ Nexigen solves this by treating **entities as first-class citizens**.
36
+
37
+ ---
38
+
39
+ ## Core Goals
40
+
41
+ - **Stable Entity Identity**
42
+ One entity = one model instance across the entire app.
43
+
44
+ - **Normalized Graph**
45
+ All data lives in a single normalized entity graph.
46
+
47
+ - **Deterministic Lifecycle**
48
+ Entities exist only while referenced.
49
+
50
+ - **Explicit Async Commands**
51
+ Async logic is modeled as commands, not state.
52
+
53
+ - **MobX-native Reactivity**
54
+ No selectors, no memoization, no manual wiring.
55
+
56
+ ---
57
+
58
+ ## Mental Model (Read First)
59
+
60
+ Before using Nexigen, you must understand its mental model.
61
+
62
+ 📘 **[Mental Model](docs/docs/01-mental-model.md)**
63
+ Defines the rules and invariants of the system. Mandatory reading.
64
+
65
+ ---
66
+
67
+ ## Architecture Overview
68
+
69
+ Nexigen is composed of several orthogonal layers:
70
+
71
+ - Entity Schemas
72
+ - Normalized Entity Store
73
+ - Records & Collections
74
+ - Async Ducks
75
+ - Dependency Injection (StoreDeps)
76
+ - React Hooks
77
+
78
+ 📘 **[Architecture Overview](docs/docs/02-architecture-overview.md)**
79
+
80
+ ---
81
+
82
+ ## Installation
83
+
84
+ ```bash
85
+ pnpm add @nexigen/entity-normalizer mobx mobx-react-lite
86
+ ```
87
+
88
+ or
89
+
90
+ ```bash
91
+ npm install @nexigen/entity-normalizer mobx mobx-react-lite
92
+ ```
93
+
94
+ or
95
+
96
+ ```bash
97
+ yarn add @nexigen/entity-normalizer mobx mobx-react-lite
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Application Setup
103
+
104
+ ### 1. Create Entity Keys
105
+
106
+ ```ts
107
+ export const ENTITY_KEY = {
108
+ VIEWER: 'viewers',
109
+ POST: 'posts',
110
+ } as const;
111
+ ```
112
+
113
+ ---
114
+
115
+ ### 2. Define Schemas
116
+
117
+ ```ts
118
+ export const viewerSchema = createEntitySchema(
119
+ ENTITY_KEY.VIEWER,
120
+ {},
121
+ { model: ViewerModel }
122
+ );
123
+ ```
124
+
125
+ ```ts
126
+ export const postSchema = createEntitySchema(
127
+ ENTITY_KEY.POST,
128
+ {
129
+ viewer: viewerSchema,
130
+ viewers: [viewerSchema],
131
+ },
132
+ { model: PostModel }
133
+ );
134
+ ```
135
+
136
+ ---
137
+
138
+ ### 3. Register Schema Map
139
+
140
+ ```ts
141
+ export const schemaMap = {
142
+ [ENTITY_KEY.VIEWER]: viewerSchema,
143
+ [ENTITY_KEY.POST]: postSchema,
144
+ };
145
+ ```
146
+
147
+ ---
148
+
149
+ ## Models
150
+
151
+ Models wrap DTOs and define behavior.
152
+ They never own related entities directly.
153
+
154
+ ```ts
155
+ export class PostModel {
156
+ constructor(dto, get) {
157
+ this.id = dto.id;
158
+ this.viewerId = dto.viewerId;
159
+ this.title = dto.title;
160
+ makeAutoObservable(this);
161
+ }
162
+
163
+ get viewer() {
164
+ return this.get(ENTITY_KEY.VIEWER, this.viewerId);
165
+ }
166
+ }
167
+ ```
168
+
169
+ ---
170
+
171
+ ## Stores
172
+
173
+ Stores orchestrate behavior.
174
+ They never store entity data directly.
175
+
176
+ ```ts
177
+ export class PostsStore {
178
+ lists;
179
+
180
+ constructor(deps) {
181
+ this.lists = deps.core.entities.createMultiCollection({
182
+ entityKey: ENTITY_KEY.POST,
183
+ collectionId: 'posts',
184
+ limit: 20,
185
+ });
186
+
187
+ makeAutoObservable(this);
188
+ }
189
+
190
+ fetchPosts = createDuck(async ({ group }) => {
191
+ const res = await deps.api.Posts.getPosts({ group });
192
+ this.lists[group].set(res);
193
+ });
194
+ }
195
+ ```
196
+
197
+ ---
198
+
199
+ ## Root Store Initialization
200
+
201
+ ```ts
202
+ export const rootStore = createRootStore({
203
+ api: Api,
204
+ schemaMap,
205
+ stores: {
206
+ posts: PostsStore,
207
+ viewer: ViewerStore,
208
+ },
209
+ services: {
210
+ bootstrap: BootstrapService,
211
+ },
212
+ });
213
+ ```
214
+
215
+ ```ts
216
+ registerRootStore(rootStore);
217
+ ```
218
+
219
+ ---
220
+
221
+ ## React Integration
222
+
223
+ ```ts
224
+ export const { useStores, useServices, useCore } =
225
+ createStoreHooks<typeof rootStore>();
226
+ ```
227
+
228
+ ```tsx
229
+ const PostsScreen = observer(() => {
230
+ const { posts } = useStores();
231
+
232
+ useEffect(() => {
233
+ posts.fetchPosts.run({ group: 'active' });
234
+ }, []);
235
+
236
+ return <List data={posts.lists.active.getList} />;
237
+ });
238
+ ```
239
+
240
+ ---
241
+
242
+ ## Documentation Index
243
+
244
+ - EntitiesStore
245
+ - EntityRecord
246
+ - EntityCollection
247
+ - MultiEntityCollection
248
+ - Schemas
249
+ - Models
250
+ - Async Ducks
251
+ - StoreDeps
252
+ - Core API
253
+ - React Hooks
254
+ - Anti-patterns
255
+ - Testing
256
+
257
+ ---
258
+
259
+ ## Status
260
+
261
+ - Actively developed.
262
+ - Core logic is thoroughly covered by tests.
263
+
264
+ ---
265
+
266
+ ## License
267
+
268
+ MIT
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@nexigen/entity-normalizer",
3
+ "version": "0.1.1",
4
+ "description": "Reactive entity infrastructure for complex client applications, built on MobX.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "lint": "eslint src",
14
+ "lint:fix": "eslint src --fix",
15
+ "test": "jest",
16
+ "test:watch": "jest --watch",
17
+ "typecheck": "tsc --noEmit",
18
+ "build": "tsc"
19
+ },
20
+ "lint-staged": {
21
+ "*.{ts,tsx}": [
22
+ "eslint --fix"
23
+ ]
24
+ },
25
+ "peerDependencies": {
26
+ "mobx": ">=6.12 <7"
27
+ },
28
+ "devDependencies": {
29
+ "@types/jest": "^30.0.0",
30
+ "@types/node": "^25.0.2",
31
+ "@typescript-eslint/eslint-plugin": "^8.31.1",
32
+ "@typescript-eslint/parser": "^8.31.1",
33
+ "eslint": "^9.26.0",
34
+ "eslint-config-prettier": "^10.1.8",
35
+ "eslint-import-resolver-typescript": "^4.4.4",
36
+ "eslint-plugin-import": "^2.31.0",
37
+ "husky": "^9.1.7",
38
+ "jest": "^30.2.0",
39
+ "lint-staged": "^16.2.7",
40
+ "mobx": "^6.13.7",
41
+ "prettier": "^3.7.4",
42
+ "ts-jest": "^29.4.6",
43
+ "ts-node": "^10.9.2",
44
+ "typescript": "^5.8.3"
45
+ },
46
+ "engines": {
47
+ "node": ">=20"
48
+ }
49
+ }