@figliolia/galena 2.3.5 → 3.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.
Files changed (144) hide show
  1. package/README.md +172 -476
  2. package/dist/Galena.cjs +102 -0
  3. package/dist/Galena.d.cts +80 -0
  4. package/dist/Galena.d.cts.map +1 -0
  5. package/dist/Galena.d.mts +80 -0
  6. package/dist/Galena.d.mts.map +1 -0
  7. package/dist/Galena.mjs +103 -0
  8. package/dist/Galena.mjs.map +1 -0
  9. package/dist/GalenaProvider.cjs +50 -0
  10. package/dist/GalenaProvider.d.cts +35 -0
  11. package/dist/GalenaProvider.d.cts.map +1 -0
  12. package/dist/GalenaProvider.d.mts +35 -0
  13. package/dist/GalenaProvider.d.mts.map +1 -0
  14. package/dist/GalenaProvider.mjs +52 -0
  15. package/dist/GalenaProvider.mjs.map +1 -0
  16. package/dist/Logger.cjs +46 -0
  17. package/dist/Logger.d.cts +35 -0
  18. package/dist/Logger.d.cts.map +1 -0
  19. package/dist/Logger.d.mts +35 -0
  20. package/dist/Logger.d.mts.map +1 -0
  21. package/dist/Logger.mjs +48 -0
  22. package/dist/Logger.mjs.map +1 -0
  23. package/dist/Middleware.cjs +62 -0
  24. package/dist/Middleware.d.cts +65 -0
  25. package/dist/Middleware.d.cts.map +1 -0
  26. package/dist/Middleware.d.mts +65 -0
  27. package/dist/Middleware.d.mts.map +1 -0
  28. package/dist/Middleware.mjs +64 -0
  29. package/dist/Middleware.mjs.map +1 -0
  30. package/dist/Profiler.cjs +41 -0
  31. package/dist/Profiler.d.cts +31 -0
  32. package/dist/Profiler.d.cts.map +1 -0
  33. package/dist/Profiler.d.mts +31 -0
  34. package/dist/Profiler.d.mts.map +1 -0
  35. package/dist/Profiler.mjs +43 -0
  36. package/dist/Profiler.mjs.map +1 -0
  37. package/dist/State.cjs +147 -0
  38. package/dist/State.d.cts +114 -0
  39. package/dist/State.d.cts.map +1 -0
  40. package/dist/State.d.mts +114 -0
  41. package/dist/State.d.mts.map +1 -0
  42. package/dist/State.mjs +148 -0
  43. package/dist/State.mjs.map +1 -0
  44. package/dist/commonHooks.cjs +17 -0
  45. package/dist/commonHooks.mjs +18 -0
  46. package/dist/commonHooks.mjs.map +1 -0
  47. package/dist/connect-multi.cjs +42 -0
  48. package/dist/connect-multi.d.cts +10 -0
  49. package/dist/connect-multi.d.cts.map +1 -0
  50. package/dist/connect-multi.d.mts +10 -0
  51. package/dist/connect-multi.d.mts.map +1 -0
  52. package/dist/connect-multi.mjs +44 -0
  53. package/dist/connect-multi.mjs.map +1 -0
  54. package/dist/connect.cjs +41 -0
  55. package/dist/connect.d.cts +9 -0
  56. package/dist/connect.d.cts.map +1 -0
  57. package/dist/connect.d.mts +9 -0
  58. package/dist/connect.d.mts.map +1 -0
  59. package/dist/connect.mjs +43 -0
  60. package/dist/connect.mjs.map +1 -0
  61. package/dist/createUseState.cjs +47 -0
  62. package/dist/createUseState.d.cts +46 -0
  63. package/dist/createUseState.d.cts.map +1 -0
  64. package/dist/createUseState.d.mts +46 -0
  65. package/dist/createUseState.d.mts.map +1 -0
  66. package/dist/createUseState.mjs +49 -0
  67. package/dist/createUseState.mjs.map +1 -0
  68. package/dist/index.cjs +23 -0
  69. package/dist/index.d.cts +12 -0
  70. package/dist/index.d.mts +12 -0
  71. package/dist/index.mjs +11 -0
  72. package/dist/types.d.cts +23 -0
  73. package/dist/types.d.cts.map +1 -0
  74. package/dist/types.d.mts +23 -0
  75. package/dist/types.d.mts.map +1 -0
  76. package/dist/useState.cjs +45 -0
  77. package/dist/useState.d.cts +43 -0
  78. package/dist/useState.d.cts.map +1 -0
  79. package/dist/useState.d.mts +43 -0
  80. package/dist/useState.d.mts.map +1 -0
  81. package/dist/useState.mjs +47 -0
  82. package/dist/useState.mjs.map +1 -0
  83. package/media/Logging.png +0 -0
  84. package/media/Profiling.png +0 -0
  85. package/package.json +38 -59
  86. package/src/Galena.ts +120 -0
  87. package/src/{Middlewares/Logger.ts → Logger.ts} +15 -14
  88. package/src/Middleware.ts +62 -0
  89. package/src/Profiler.ts +53 -0
  90. package/src/State.ts +167 -0
  91. package/src/index.ts +6 -3
  92. package/src/types.ts +28 -0
  93. package/dist/cjs/Galena/Galena.js +0 -223
  94. package/dist/cjs/Galena/Guards.js +0 -40
  95. package/dist/cjs/Galena/Scheduler.js +0 -84
  96. package/dist/cjs/Galena/State.js +0 -314
  97. package/dist/cjs/Galena/index.js +0 -22
  98. package/dist/cjs/Galena/types.js +0 -9
  99. package/dist/cjs/Middleware/Middleware.js +0 -46
  100. package/dist/cjs/Middleware/index.js +0 -20
  101. package/dist/cjs/Middleware/types.js +0 -8
  102. package/dist/cjs/Middlewares/Logger.js +0 -51
  103. package/dist/cjs/Middlewares/Profiler.js +0 -38
  104. package/dist/cjs/Middlewares/index.js +0 -7
  105. package/dist/cjs/index.js +0 -19
  106. package/dist/cjs/package.json +0 -3
  107. package/dist/mjs/Galena/Galena.js +0 -218
  108. package/dist/mjs/Galena/Guards.js +0 -36
  109. package/dist/mjs/Galena/Scheduler.js +0 -79
  110. package/dist/mjs/Galena/State.js +0 -313
  111. package/dist/mjs/Galena/index.js +0 -3
  112. package/dist/mjs/Galena/types.js +0 -6
  113. package/dist/mjs/Middleware/Middleware.js +0 -42
  114. package/dist/mjs/Middleware/index.js +0 -2
  115. package/dist/mjs/Middleware/types.js +0 -5
  116. package/dist/mjs/Middlewares/Logger.js +0 -44
  117. package/dist/mjs/Middlewares/Profiler.js +0 -35
  118. package/dist/mjs/Middlewares/index.js +0 -2
  119. package/dist/mjs/index.js +0 -3
  120. package/dist/mjs/package.json +0 -4
  121. package/dist/types/Galena/Galena.d.ts +0 -160
  122. package/dist/types/Galena/Guards.d.ts +0 -29
  123. package/dist/types/Galena/Scheduler.d.ts +0 -51
  124. package/dist/types/Galena/State.d.ts +0 -235
  125. package/dist/types/Galena/index.d.ts +0 -3
  126. package/dist/types/Galena/types.d.ts +0 -13
  127. package/dist/types/Middleware/Middleware.d.ts +0 -43
  128. package/dist/types/Middleware/index.d.ts +0 -2
  129. package/dist/types/Middleware/types.d.ts +0 -4
  130. package/dist/types/Middlewares/Logger.d.ts +0 -27
  131. package/dist/types/Middlewares/Profiler.d.ts +0 -22
  132. package/dist/types/Middlewares/index.d.ts +0 -2
  133. package/dist/types/index.d.ts +0 -3
  134. package/src/Galena/Galena.ts +0 -252
  135. package/src/Galena/Guards.ts +0 -49
  136. package/src/Galena/Scheduler.ts +0 -85
  137. package/src/Galena/State.ts +0 -344
  138. package/src/Galena/index.ts +0 -3
  139. package/src/Galena/types.ts +0 -18
  140. package/src/Middleware/Middleware.ts +0 -45
  141. package/src/Middleware/index.ts +0 -2
  142. package/src/Middleware/types.ts +0 -4
  143. package/src/Middlewares/Profiler.ts +0 -41
  144. package/src/Middlewares/index.ts +0 -2
@@ -1,223 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Galena = void 0;
4
- const event_emitter_1 = require("@figliolia/event-emitter");
5
- const State_1 = require("./State");
6
- const Guards_1 = require("./Guards");
7
- /**
8
- * ## Galena
9
- *
10
- * A performant global state solution that scales
11
- *
12
- * ### Creating State
13
- *
14
- * ```typescript
15
- * // AppState.ts
16
- * import { Galena } from "@figliolia/galena";
17
- *
18
- * const AppState = new Galena([...middleware]);
19
- *
20
- * const NavigationState = AppState.composeState("navigation", {
21
- * currentRoute: "/",
22
- * userID: "12345",
23
- * permittedRoutes: ["/*"]
24
- * });
25
- * ```
26
- *
27
- * ### Subscribing to State Changes
28
- * #### Using the Galena Instance
29
- * ```typescript
30
- * import { AppState } from "./AppState";
31
- *
32
- * AppState.subscribe(appState => {
33
- * const navState = appState.get("navigation");
34
- * const { currentRoute } = navState.state;
35
- * // do something with state changes!
36
- * });
37
- * ```
38
- * #### Using the State Instance
39
- * ```typescript
40
- * NavigationState.subscribe(navigation => {
41
- * const { currentRoute } = navigation
42
- * // do something with state changes!
43
- * });
44
- * ```
45
- *
46
- * #### Using Global Subscriptions
47
- * ```typescript
48
- * NavigationState.subscribeAll(nextState => {
49
- * const { currentRoute } = nextState.navigation
50
- * // do something with state changes!
51
- * });
52
- * ```
53
- *
54
- * ### Mutating State
55
- * ```typescript
56
- * NavigationState.update(state => {
57
- * state.currentRoute = "/profile";
58
- * // You can mutate state without creating new objects!
59
- * });
60
- * ```
61
- */
62
- class Galena extends Guards_1.Guards {
63
- constructor(middleware = []) {
64
- super();
65
- this.state = {};
66
- this.middleware = [];
67
- this.IDs = new event_emitter_1.AutoIncrementingID();
68
- this.subscriptions = new Map();
69
- this.middleware = middleware;
70
- }
71
- /**
72
- * Compose State
73
- *
74
- * Creates a new `State` instance and returns it. Your new state
75
- * becomes immediately available on your `Galena` instance and
76
- * is wired into your middleware. All existing subscriptions to
77
- * state will automatically receive updates when your new unit of
78
- * state updates
79
- */
80
- composeState(name, initialState, Model) {
81
- this.guardDuplicateStates(name, this.state);
82
- const StateModel = Model || (State_1.State);
83
- const state = new StateModel(name, initialState);
84
- state.registerMiddleware(...this.middleware);
85
- this.mutable[name] = state;
86
- this.reIndexSubscriptions(name);
87
- return state;
88
- }
89
- /**
90
- * Get State
91
- *
92
- * Returns a mutable state instance
93
- */
94
- getState() {
95
- return this.state;
96
- }
97
- /**
98
- * Get
99
- *
100
- * Returns a unit of `State` by name
101
- */
102
- get(name) {
103
- this.warnForUndefinedStates(name, this.state);
104
- return this.state[name];
105
- }
106
- /**
107
- * Mutable
108
- *
109
- * Returns a mutable state instance
110
- */
111
- get mutable() {
112
- return this.state;
113
- }
114
- /**
115
- * Update
116
- *
117
- * Runs a mutation on the specified unit of state
118
- */
119
- update(name, mutation) {
120
- return this.get(name).update(mutation);
121
- }
122
- /**
123
- * Background Update
124
- *
125
- * Runs a higher priority mutation on the specified unit of
126
- * state
127
- */
128
- backgroundUpdate(name, mutation) {
129
- return this.get(name).backgroundUpdate(mutation);
130
- }
131
- /**
132
- * Priority Update
133
- *
134
- * Runs an immediate priority mutation on the specified unit
135
- * of state
136
- */
137
- priorityUpdate(name, mutation) {
138
- return this.get(name).priorityUpdate(mutation);
139
- }
140
- /**
141
- * Subscribe
142
- *
143
- * Given the name of a unit of state, this method registers
144
- * a subscription on the target state instance. The callback
145
- * you provide will execute each time state changes. Returns
146
- * a unique identifier for your subscription. To clean up your
147
- * subscription, call `Galena.unsubscribe()` with the ID returned
148
- * by this method
149
- */
150
- subscribe(name, callback) {
151
- return this.get(name).subscribe(callback);
152
- }
153
- /**
154
- * Unsubscribe
155
- *
156
- * Given a subscription ID returned from the `subscribe` method,
157
- * this method removes and cleans up the corresponding subscription
158
- */
159
- unsubscribe(name, ID) {
160
- return this.get(name).unsubscribe(ID);
161
- }
162
- /**
163
- * Subscribe All
164
- *
165
- * Registers a callback on each registered `State` instance and
166
- * is invoked each time your state changes. Using `Galena`'s
167
- * `subscribeAll` method, although performant, can be less
168
- * performant than subscribing directly to a target `State`
169
- * instance using `Galena.subscribe()`. To clean up your
170
- * subscription, call `Galena.unsubscribeAll()` with the ID
171
- * returned
172
- */
173
- subscribeAll(callback) {
174
- const stateSubscriptions = [];
175
- for (const key in this.state) {
176
- stateSubscriptions.push([
177
- key,
178
- this.state[key].subscribe(() => {
179
- void callback(this.state);
180
- }),
181
- ]);
182
- }
183
- const subscriptionID = this.IDs.get();
184
- this.subscriptions.set(subscriptionID, stateSubscriptions);
185
- return subscriptionID;
186
- }
187
- /**
188
- * Unsubscribe
189
- *
190
- * Given a subscription ID returned from the `subscribeAll()` method,
191
- * this method removes and cleans up the corresponding subscription
192
- */
193
- unsubscribeAll(ID) {
194
- const IDs = this.subscriptions.get(ID);
195
- if (IDs) {
196
- for (const [state, ID] of IDs) {
197
- this.state[state].unsubscribe(ID);
198
- }
199
- this.subscriptions.delete(ID);
200
- }
201
- }
202
- /**
203
- * ReIndex Subscriptions
204
- *
205
- * When units of state are created lazily, this method updates
206
- * each existing subscription to receive mutations occurring on
207
- * recently created `State` instances that post-date prior
208
- * subscriptions
209
- */
210
- reIndexSubscriptions(name) {
211
- var _a, _b;
212
- for (const [ID, unitSubscriptions] of this.subscriptions) {
213
- const [stateName, listenerID] = unitSubscriptions[0];
214
- const subscriptions = this.state[stateName]["emitter"].storage.get(stateName);
215
- const listener = (_b = (_a = subscriptions === null || subscriptions === void 0 ? void 0 : subscriptions.storage) === null || _a === void 0 ? void 0 : _a.get) === null || _b === void 0 ? void 0 : _b.call(_a, listenerID);
216
- if (listener) {
217
- unitSubscriptions.push([name, this.state[name].subscribe(listener)]);
218
- this.subscriptions.set(ID, unitSubscriptions);
219
- }
220
- }
221
- }
222
- }
223
- exports.Galena = Galena;
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Guards = void 0;
4
- /**
5
- * Guards
6
- *
7
- * Development-only warnings and runtime errors designed to
8
- * guard developers against possible pitfalls when using
9
- * Galena. This interface provides composable error and
10
- * warning methods that can be used to prevent invalid usage
11
- * of the library
12
- */
13
- class Guards {
14
- /**
15
- * Warn For Undefined States
16
- *
17
- * In Galena, it's normal to lazy initialize a unit of state
18
- * in attached to a `Galena` instance. This warning lets
19
- * developers know that they are attempting to manipulate a
20
- * unit of state that has not yet been initialized
21
- */
22
- warnForUndefinedStates(name, state) {
23
- if (!(name in state)) {
24
- console.warn(`A unit of state with the name "${name}" does not yet exist on this Galena instance. If this is expected, you can ignore this warning`);
25
- }
26
- }
27
- /**
28
- * Guard Duplicate States
29
- *
30
- * Throws an error if a developer attempts to create
31
- * more than one state with the same name on a single
32
- * `Galena` instance
33
- */
34
- guardDuplicateStates(name, state) {
35
- if (name in state) {
36
- console.warn(`A unit of state with the name "${name}" already exists on this Galena instance. Please re-name this new unit of state to something unique`);
37
- }
38
- }
39
- }
40
- exports.Guards = Guards;
@@ -1,84 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Scheduler = void 0;
4
- const types_1 = require("./types");
5
- /**
6
- * Scheduler
7
- *
8
- * Scheduling dispatched events to state consumers is how Galena
9
- * out-performs just about every state management library out there.
10
- * The scheduler offers the ability to dispatch state updates on 3
11
- * priorities:
12
- *
13
- * 1. Immediate - Immediate synchronous task execution and propagation of
14
- * changes to consumers
15
- * 2. Microtask - Immediate task execution and scheduled propagation of
16
- * changes to consumers
17
- * 3. Batched - Immediate task execution and batched propagation of
18
- * changes to consumers
19
- *
20
- * This module manages the propagation of changes to State consumers
21
- * by implementing the three priorities outlined above
22
- */
23
- class Scheduler {
24
- constructor() {
25
- this.task = null;
26
- this.schedule = null;
27
- this.executeTasks = this.executeTasks.bind(this);
28
- }
29
- /**
30
- * Schedule Task
31
- *
32
- * Given a task (the emission of state changes to consumers)
33
- * and a priority, this method executes the task on the priority
34
- * level specified
35
- */
36
- scheduleTask(task, priority) {
37
- this.task = task;
38
- switch (priority) {
39
- case types_1.Priority.IMMEDIATE:
40
- return this.executeTasks();
41
- case types_1.Priority.MICROTASK:
42
- return Promise.resolve().then(() => {
43
- return this.executeTasks();
44
- });
45
- case types_1.Priority.BATCHED:
46
- default:
47
- if (!this.schedule) {
48
- this.createSchedule();
49
- }
50
- }
51
- }
52
- /**
53
- * Create Schedule
54
- *
55
- * Schedules the execution of the current task after 5 milliseconds
56
- */
57
- createSchedule() {
58
- this.clearSchedule();
59
- this.schedule = setTimeout(this.executeTasks, 5);
60
- }
61
- /**
62
- * Clear Schedule
63
- *
64
- * Clears the schedule if it exists
65
- */
66
- clearSchedule() {
67
- if (this.schedule !== null) {
68
- clearTimeout(this.schedule);
69
- this.schedule = null;
70
- }
71
- }
72
- /**
73
- * Execute Tasks
74
- *
75
- * Clears the schedule if it exists and executes the current task
76
- */
77
- executeTasks() {
78
- var _a;
79
- this.clearSchedule();
80
- (_a = this.task) === null || _a === void 0 ? void 0 : _a.call(this);
81
- this.task = null;
82
- }
83
- }
84
- exports.Scheduler = Scheduler;
@@ -1,314 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.State = void 0;
4
- const event_emitter_1 = require("@figliolia/event-emitter");
5
- const types_1 = require("../Middleware/types");
6
- const Scheduler_1 = require("./Scheduler");
7
- const types_2 = require("./types");
8
- /**
9
- * ### State
10
- *
11
- * The root of all reactivity in Galena. State instances can
12
- * operate in isolation by calling `new State(...args)` or as
13
- * part of your application's larger global state by using
14
- * `new Galena().composeState()`.
15
- *
16
- * `State` instances operate on the premise of pub-sub and mutability.
17
- * This provides significant performance improvement over more traditional
18
- * state management tools because
19
- *
20
- * 1. Mutations can occur in O(1) space
21
- * 2. Mutations can be batched when dispatching updates to subscribers
22
- *
23
- * When deciding how many `State` instances are required for your
24
- * applications needs, we suggest creating and organizing state in
25
- * accordance with your application logic. Meaning, you might have a
26
- * `State` instance for navigation/routing, another `State` instance
27
- * for storing user information, and so on. Performance can improve
28
- * significantly when state is dispersed amongst multiple instances
29
- *
30
- * #### Creating State Instances
31
- *
32
- * ```typescript
33
- * const MyState = new State("MyState", {
34
- * someData: true,
35
- * listItems: [1, 2, 3, 4];
36
- * // ...etc
37
- * });
38
- * ```
39
- *
40
- * #### Updating State
41
- * ##### Synchronous updates
42
- * ```typescript
43
- * MyState.update((state) => {
44
- * state.listItems.push(5);
45
- * });
46
- * ```
47
- * ##### Asynchronous updates
48
- * ```typescript
49
- * MyState.update(async (state) => {
50
- * const listItems = await fetch("/list-items");
51
- * state.listItems = listItems;
52
- * });
53
- * ```
54
- *
55
- * #### Subscribing to State Changes
56
- * ```typescript
57
- * MyState.subscribe((state) => {
58
- * const { listItems } = state
59
- * // Do something with your list items!
60
- * });
61
- * ```
62
- */
63
- class State extends Scheduler_1.Scheduler {
64
- constructor(name, initialState) {
65
- super();
66
- this.middleware = [];
67
- this.emitter = new event_emitter_1.EventEmitter();
68
- /**
69
- * Update
70
- *
71
- * Mutates state and notifies any open subscriptions. This method
72
- * by default uses task batching for optimized performance. In almost
73
- * every use-case, this method is the correct way to mutate state. If
74
- * you need to bypass batching for higher-priority state updates, you
75
- * can use `State.priorityUpdate()` or `State.backgroundUpdate()`
76
- *
77
- * ##### Synchronous updates
78
- * ```typescript
79
- * MyState.update((state, initialState) => {
80
- * state.listItems.push(5);
81
- * });
82
- * ```
83
- * ##### Asynchronous updates
84
- * ```typescript
85
- * MyState.update(async (state, initialState) => {
86
- * const listItems = await fetch("/list-items");
87
- * state.listItems = listItems;
88
- * });
89
- * ```
90
- */
91
- this.update = this.mutation((func) => {
92
- return func(this.state, this.initialState);
93
- }, types_2.Priority.BATCHED);
94
- /**
95
- * Background Update
96
- *
97
- * Mutates state and notifies any open subscriptions. This method
98
- * bypasses Galena's internal task batching for a more immediate
99
- * state update and propagation of state to consumers. It utilizes
100
- * a micro-task that allows for the current call stack to clear
101
- * ahead of propagating state updates to consumers
102
- *
103
- * ##### Synchronous updates
104
- * ```typescript
105
- * MyState.backgroundUpdate((state, initialState) => {
106
- * state.listItems.push(5);
107
- * });
108
- * ```
109
- * ##### Asynchronous updates
110
- * ```typescript
111
- * MyState.backgroundUpdate(async (state, initialState) => {
112
- * const listItems = await fetch("/list-items");
113
- * state.listItems = listItems;
114
- * });
115
- * ```
116
- */
117
- this.backgroundUpdate = this.mutation((func) => {
118
- return func(this.state, this.initialState);
119
- }, types_2.Priority.MICROTASK);
120
- /**
121
- * Priority Update
122
- *
123
- * Mutates state and notifies any open subscriptions. This method
124
- * bypasses optimizations for task batching and scheduling. This means
125
- * that state updates made with this method propagate to subscriptions
126
- * as immediately as possible. Overusing this method can cause your
127
- * state updates to perform slower in certain cases. The usage of this
128
- * method should be conserved for state mutations that need to occur
129
- * at a certain frame rate
130
- *
131
- * ##### Synchronous updates
132
- * ```typescript
133
- * MyState.priorityUpdate((state, initialState) => {
134
- * state.listItems.push(5);
135
- * });
136
- * ```
137
- * ##### Asynchronous updates
138
- * ```typescript
139
- * MyState.priorityUpdate(async (state, initialState) => {
140
- * const listItems = await fetch("/list-items");
141
- * state.listItems = listItems;
142
- * });
143
- * ```
144
- */
145
- this.priorityUpdate = this.mutation((func) => {
146
- return func(this.state, this.initialState);
147
- }, types_2.Priority.IMMEDIATE);
148
- /**
149
- * Reset
150
- *
151
- * Resets the current state to its initial state
152
- */
153
- this.reset = this.mutation(() => {
154
- this.state = State.clone(this.initialState);
155
- });
156
- this.name = name;
157
- this.state = initialState;
158
- this.initialState = State.clone(initialState);
159
- }
160
- /**
161
- * Get State
162
- *
163
- * Returns a readonly snapshot of the current state
164
- */
165
- getState() {
166
- return this.state;
167
- }
168
- /**
169
- * Mutation
170
- *
171
- * This method can be used to wrap arbitrary functions that when invoked
172
- * will:
173
- * 1. Notify your subscriptions with the latest state
174
- * 2. Execute any registered middleware (such as loggers or profiling tools)
175
- *
176
- * Using this method, developers can compose and extend `Galena`'s internal
177
- * infrastructure for state mutations to create proprietary models for your
178
- * state
179
- *
180
- * ```typescript
181
- * import { State } from "@figliolia/galena";
182
- *
183
- * // Extend of Galena State
184
- * class MyState extends State {
185
- * addListItem = mutation((newListItem) => {
186
- * this.state.list.push(newListItem);
187
- * });
188
- * }
189
- *
190
- * // Create an instance
191
- * const myState = new MyState("myState", { list: [] });
192
- *
193
- * // Invoke your custom mutation method
194
- * myState.addListItem("new-item");
195
- * ```
196
- */
197
- mutation(func, priority = types_2.Priority.BATCHED) {
198
- return (...args) => {
199
- this.lifeCycleEvent(types_1.MiddlewareEvents.onBeforeUpdate);
200
- const returnValue = func(...args);
201
- if (returnValue instanceof Promise) {
202
- return returnValue.then(v => {
203
- this.scheduleUpdate(priority);
204
- return v;
205
- });
206
- }
207
- this.scheduleUpdate(priority);
208
- return returnValue;
209
- };
210
- }
211
- /**
212
- * Schedule Update
213
- *
214
- * Schedules an update to State subscribers and emits the
215
- * `onUpdate` lifecycle hook
216
- */
217
- scheduleUpdate(priority) {
218
- this.lifeCycleEvent(types_1.MiddlewareEvents.onUpdate);
219
- void this.scheduleTask(() => this.emitter.emit(this.name, this.state), priority);
220
- }
221
- /**
222
- * Register Middleware
223
- *
224
- * Caches a `Middleware` instance and invokes its
225
- * lifecycle subscriptions on all state transitions
226
- */
227
- registerMiddleware(...middleware) {
228
- this.middleware.push(...middleware);
229
- }
230
- /**
231
- * Subscribe
232
- *
233
- * Registers a subscription on the state instance. The
234
- * callback you provide will execute each time state changes.
235
- * Returns a unique identifier for your subscription
236
- */
237
- subscribe(callback) {
238
- return this.emitter.on(this.name, callback);
239
- }
240
- /**
241
- * Unsubscribe
242
- *
243
- * Given a subscription ID, removes a registered subscription
244
- * from the `State` instance
245
- */
246
- unsubscribe(ID) {
247
- return this.emitter.off(this.name, ID);
248
- }
249
- /**
250
- * Clear All Subscriptions
251
- *
252
- * Removes all open subscriptions to the `State` instance
253
- */
254
- clearAllSubscriptions() {
255
- return this.emitter.storage.clear();
256
- }
257
- /**
258
- * Life Cycle Event
259
- *
260
- * Triggers a life cycle event for each registered middleware
261
- */
262
- lifeCycleEvent(event) {
263
- const maxIndex = this.middleware.length - 1;
264
- for (let i = maxIndex; i > -1; i--) {
265
- this.middleware[i][event](this);
266
- }
267
- }
268
- /**
269
- * Clone
270
- *
271
- * `State` instances accept any value as a form of reactive
272
- * state. In order to maintain the initial state past any state
273
- * transitions, this method clones the initial values provided
274
- * to the `State` constructor and caches them to allow for
275
- * developers to easily reset their current state back to its
276
- * initial value
277
- */
278
- static clone(state) {
279
- switch (typeof state) {
280
- case "string":
281
- return String(state);
282
- case "bigint":
283
- return BigInt(state);
284
- case "boolean":
285
- return Boolean(state);
286
- case "number":
287
- return Number(state);
288
- case "symbol":
289
- case "function":
290
- return state;
291
- case "undefined":
292
- return undefined;
293
- case "object":
294
- default:
295
- if (!state) {
296
- return null;
297
- }
298
- if (Array.isArray(state)) {
299
- return [...state];
300
- }
301
- if (state instanceof Set) {
302
- return new Set(state);
303
- }
304
- if (state instanceof Map) {
305
- return new Map(state);
306
- }
307
- if (state && typeof state === "object") {
308
- return Object.assign({}, state);
309
- }
310
- return state;
311
- }
312
- }
313
- }
314
- exports.State = State;
@@ -1,22 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.State = exports.Galena = void 0;
18
- var Galena_1 = require("./Galena");
19
- Object.defineProperty(exports, "Galena", { enumerable: true, get: function () { return Galena_1.Galena; } });
20
- var State_1 = require("./State");
21
- Object.defineProperty(exports, "State", { enumerable: true, get: function () { return State_1.State; } });
22
- __exportStar(require("./types"), exports);
@@ -1,9 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Priority = void 0;
4
- var Priority;
5
- (function (Priority) {
6
- Priority[Priority["IMMEDIATE"] = 1] = "IMMEDIATE";
7
- Priority[Priority["MICROTASK"] = 2] = "MICROTASK";
8
- Priority[Priority["BATCHED"] = 3] = "BATCHED";
9
- })(Priority || (exports.Priority = Priority = {}));