@inglorious/store 9.5.3 → 10.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/README.md CHANGED
@@ -118,8 +118,8 @@ const types = {
118
118
 
119
119
  // Define initial entities
120
120
  const entities = {
121
- work: { type: "todoList", todos: [] },
122
- personal: { type: "todoList", todos: [] },
121
+ work: { type: "TodoList", todos: [] },
122
+ personal: { type: "TodoList", todos: [] },
123
123
  }
124
124
 
125
125
  // Create store
@@ -171,9 +171,9 @@ const types = {
171
171
  }
172
172
 
173
173
  const entities = {
174
- workTodos: { type: "todoList", todos: [], priority: "high" },
175
- personalTodos: { type: "todoList", todos: [], priority: "low" },
176
- settings: { type: "settings", theme: "dark", language: "en" },
174
+ workTodos: { type: "TodoList", todos: [], priority: "high" },
175
+ personalTodos: { type: "TodoList", todos: [], priority: "low" },
176
+ settings: { type: "Settings", theme: "dark", language: "en" },
177
177
  }
178
178
  ```
179
179
 
@@ -241,7 +241,7 @@ const types = {
241
241
 
242
242
  // 2. Define initial entities
243
243
  const entities = {
244
- counter1: { type: "counter", value: 0 },
244
+ counter1: { type: "Counter", value: 0 },
245
245
  }
246
246
 
247
247
  // 3. Create the store
@@ -352,12 +352,12 @@ const types = {
352
352
  }
353
353
 
354
354
  const entities = {
355
- counter1: { type: "counter", value: 0 },
356
- counter2: { type: "counter", value: 0 },
357
- counter3: { type: "counter", value: 0 },
355
+ counter1: { type: "Counter", value: 0 },
356
+ counter2: { type: "Counter", value: 0 },
357
+ counter3: { type: "Counter", value: 0 },
358
358
  }
359
359
 
360
- store.notify("add", { id: "counter4", type: "counter", value: 0 })
360
+ store.notify("add", { id: "counter4", type: "Counter", value: 0 })
361
361
  ```
362
362
 
363
363
  Inglorious Store has a few built-in events that you can use:
@@ -707,7 +707,7 @@ function increment(entity, payload, api) {
707
707
 
708
708
  // Test it
709
709
  const { entity, events } = trigger(
710
- { type: "counter", id: "counter1", value: 99 },
710
+ { type: "Counter", id: "counter1", value: 99 },
711
711
  increment,
712
712
  { amount: 5 },
713
713
  )
@@ -725,8 +725,8 @@ import { createMockApi, trigger } from "@inglorious/store/test"
725
725
 
726
726
  // Create a mock API with some initial entities
727
727
  const api = createMockApi({
728
- counter1: { type: "counter", value: 10 },
729
- counter2: { type: "counter", value: 20 },
728
+ counter1: { type: "Counter", value: 10 },
729
+ counter2: { type: "Counter", value: 20 },
730
730
  })
731
731
 
732
732
  // A handler that copies a value from another entity
@@ -737,7 +737,7 @@ function copyValue(entity, payload, api) {
737
737
 
738
738
  // Trigger the handler with the custom mock API
739
739
  const { entity } = trigger(
740
- { type: "counter", id: "counter2", value: 20 },
740
+ { type: "Counter", id: "counter2", value: 20 },
741
741
  copyValue,
742
742
  { sourceId: "counter1" },
743
743
  api,
@@ -1042,15 +1042,15 @@ const types = {
1042
1042
 
1043
1043
  // Without autoCreateEntities (default)
1044
1044
  const entities = {
1045
- settings: { type: "settings", theme: "dark" },
1046
- analytics: { type: "analytics", events: [] },
1045
+ settings: { type: "Settings", theme: "dark" },
1046
+ analytics: { type: "Analytics", events: [] },
1047
1047
  }
1048
1048
 
1049
1049
  // With autoCreateEntities: true
1050
1050
  const entities = {
1051
1051
  // settings and analytics will be auto-created as:
1052
- // settings: { type: "settings" }
1053
- // analytics: { type: "analytics" }
1052
+ // settings: { type: "Settings" }
1053
+ // analytics: { type: "Analytics" }
1054
1054
  }
1055
1055
 
1056
1056
  const store = createStore({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inglorious/store",
3
- "version": "9.5.3",
3
+ "version": "10.0.0",
4
4
  "description": "A state manager for real-time, collaborative apps, inspired by game development patterns and compatible with Redux.",
5
5
  "author": "IceOnFire <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
6
6
  "license": "MIT",
@@ -56,10 +56,10 @@
56
56
  "sideEffects": false,
57
57
  "dependencies": {
58
58
  "mutative": "^1.3.0",
59
- "@inglorious/utils": "3.7.3"
59
+ "@inglorious/utils": "3.8.0"
60
60
  },
61
61
  "peerDependencies": {
62
- "@inglorious/utils": "3.7.3"
62
+ "@inglorious/utils": "3.8.0"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@reduxjs/toolkit": "^2.11.2",
package/src/api.js CHANGED
@@ -19,10 +19,22 @@ export function createApi(store, extras) {
19
19
  */
20
20
  setType: store.setType,
21
21
  /**
22
- * Retrieves the full entities state.
23
- * @returns {Object}
22
+ * Retrieves entities.
23
+ * If `typeName` is omitted, returns the full entities state object.
24
+ * If `typeName` is provided, returns an array of entities of that type.
25
+ * @param {string} [typeName]
26
+ * @returns {Object|Object[]}
24
27
  */
25
- getEntities: store.getState,
28
+ getEntities: (typeName) => {
29
+ const entities = store.getState()
30
+ if (typeName == null) {
31
+ return entities
32
+ }
33
+
34
+ return Object.values(entities).filter(
35
+ (entity) => entity.type === typeName,
36
+ )
37
+ },
26
38
  /**
27
39
  * Retrieves a single entity by ID.
28
40
  * @param {string} id
package/src/store.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { toCamelCase } from "@inglorious/utils/data-structures/string.js"
1
2
  import { create } from "mutative"
2
3
 
3
4
  import { createApi } from "./api.js"
@@ -118,8 +119,19 @@ export function createStore({
118
119
  const type = types[entity.type]
119
120
  const handle = type[handlerName]
120
121
 
121
- if (handle) {
122
- handle(entity, event.payload, api)
122
+ handle?.(entity, event.payload, api)
123
+ }
124
+
125
+ if (event.type.endsWith(":destroy")) {
126
+ const [target] = event.type.split(":")
127
+ const [, id] = target.split("#")
128
+ const entity = draft[id]
129
+ if (entity) {
130
+ const type = types[entity.type]
131
+ const typeName = entity.type
132
+ delete draft[id]
133
+
134
+ eventMap.removeEntity(id, type, typeName)
123
135
  }
124
136
  }
125
137
 
@@ -197,9 +209,10 @@ export function createStore({
197
209
  }
198
210
  }
199
211
 
200
- if (autoCreateEntities && !state[typeName]) {
212
+ const entityId = toCamelCase(typeName)
213
+ if (autoCreateEntities && !state[entityId]) {
201
214
  notify("add", {
202
- id: typeName,
215
+ id: entityId,
203
216
  type: typeName,
204
217
  })
205
218
  }
@@ -248,12 +261,13 @@ export function createStore({
248
261
 
249
262
  if (autoCreateEntities) {
250
263
  for (const typeName of Object.keys(types)) {
264
+ const entityId = toCamelCase(typeName)
251
265
  const hasEntity = Object.values(state).some(
252
266
  (entity) => entity.type === typeName,
253
267
  )
254
268
 
255
269
  if (!hasEntity) {
256
- addEntity(state, { id: typeName, type: typeName })
270
+ addEntity(state, { id: entityId, type: typeName })
257
271
  }
258
272
  }
259
273
  }
@@ -277,12 +291,7 @@ export function createStore({
277
291
 
278
292
  function removeEntity(draft, payload) {
279
293
  const id = payload
280
- const entity = draft[id]
281
- const type = types[entity.type]
282
- const typeName = entity.type
283
- delete draft[id]
284
294
 
285
- eventMap.removeEntity(id, type, typeName)
286
295
  incomingEvents.unshift({ type: `#${id}:destroy` })
287
296
  }
288
297
  }
package/src/test.js CHANGED
@@ -12,6 +12,7 @@ import { create } from "mutative"
12
12
  *
13
13
  * @returns {Object} A mock API object with methods:
14
14
  * - `getEntities()`: Returns all entities (frozen)
15
+ * - `getEntities(typeName)`: Returns entities matching that type (frozen array)
15
16
  * - `getEntity(id)`: Returns a specific entity by ID (frozen)
16
17
  * - `select(selector)`: Runs a selector against the entities
17
18
  * - `dispatch(event)`: Records an event (for assertions)
@@ -37,8 +38,14 @@ export function createMockApi(entities) {
37
38
  const events = []
38
39
 
39
40
  return {
40
- getEntities() {
41
- return frozenEntities
41
+ getEntities(typeName) {
42
+ if (typeName == null) {
43
+ return frozenEntities
44
+ }
45
+
46
+ return Object.values(frozenEntities).filter(
47
+ (entity) => entity.type === typeName,
48
+ )
42
49
  },
43
50
  getEntity(id) {
44
51
  return frozenEntities[id]
package/types/api.d.ts CHANGED
@@ -17,7 +17,10 @@ export interface Api<
17
17
  getTypes: () => TypesConfig<TEntity>
18
18
  getType: (typeName: string) => EntityType<TEntity>
19
19
  setType: (typeName: string, type: EntityType<TEntity>) => void
20
- getEntities: () => TState
20
+ getEntities: {
21
+ (): TState
22
+ (typeName: string): TEntity[]
23
+ }
21
24
  getEntity: (id: string) => TEntity | undefined
22
25
  select: <TResult>(selector: (state: TState) => TResult) => TResult
23
26
  dispatch: (event: Event) => void
package/types/test.d.ts CHANGED
@@ -7,7 +7,10 @@ export interface MockApi<
7
7
  TEntity extends BaseEntity = BaseEntity,
8
8
  TState extends EntitiesState<TEntity> = EntitiesState<TEntity>,
9
9
  > {
10
- getEntities: () => TState
10
+ getEntities: {
11
+ (): TState
12
+ (typeName: string): TEntity[]
13
+ }
11
14
  getEntity: (id: string) => TEntity | undefined
12
15
  select: <TResult>(selector: (state: TState) => TResult) => TResult
13
16
  dispatch: (event: Event) => void