@ngstato/core 0.1.2 → 0.2.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 +17 -3
- package/dist/index.d.mts +28 -2
- package/dist/index.d.ts +28 -2
- package/dist/index.js +211 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +211 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +22 -3
package/README.md
CHANGED
|
@@ -23,14 +23,21 @@ const store = createStore({
|
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
selectors: {
|
|
27
27
|
total: (state) => state.users.length
|
|
28
|
-
}
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
effects: [
|
|
31
|
+
[
|
|
32
|
+
(state) => state.users.length,
|
|
33
|
+
(count) => console.log('Total users:', count)
|
|
34
|
+
]
|
|
35
|
+
]
|
|
29
36
|
})
|
|
30
37
|
|
|
31
38
|
await store.loadUsers()
|
|
32
39
|
console.log(store.users) // User[]
|
|
33
|
-
console.log(store.total) // number
|
|
40
|
+
console.log(store.total) // number (selector memoïzé)
|
|
34
41
|
```
|
|
35
42
|
|
|
36
43
|
## Helpers
|
|
@@ -43,6 +50,13 @@ console.log(store.total) // number
|
|
|
43
50
|
| `retryable()` | Retry avec backoff fixe ou exponentiel |
|
|
44
51
|
| `fromStream()` | Realtime — WebSocket, Firebase, Supabase |
|
|
45
52
|
| `optimistic()` | Optimistic update + rollback automatique |
|
|
53
|
+
| `withPersist()` | Persistance localStorage/sessionStorage + migration |
|
|
54
|
+
|
|
55
|
+
## Nouvautés v0.2
|
|
56
|
+
|
|
57
|
+
- `selectors` memoïzés (recalcul seulement quand les dépendances changent)
|
|
58
|
+
- `effects` réactifs explicites avec cleanup automatique
|
|
59
|
+
- `withPersist()` pour hydrater/persister le state
|
|
46
60
|
|
|
47
61
|
## Documentation
|
|
48
62
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
type StateSlice<T> = Omit<T, 'actions' | 'computed' | 'hooks'>;
|
|
1
|
+
type StateSlice<T> = Omit<T, 'actions' | 'computed' | 'selectors' | 'hooks'>;
|
|
2
2
|
type Action<S> = (state: S, ...args: any[]) => void | Promise<void> | (() => void);
|
|
3
3
|
type ActionsMap<S> = Record<string, Action<S>>;
|
|
4
4
|
type ComputedFn<S> = (state: S) => unknown;
|
|
5
|
+
type SelectorFn<S> = (state: S) => unknown;
|
|
6
|
+
type EffectDepsFn<S> = (state: S) => unknown | unknown[];
|
|
7
|
+
type EffectCleanup = void | (() => void);
|
|
8
|
+
type EffectRunner<S> = (depsValue: unknown | unknown[], ctx: {
|
|
9
|
+
state: Readonly<S>;
|
|
10
|
+
store: any;
|
|
11
|
+
prevDepsValue?: unknown | unknown[];
|
|
12
|
+
}) => EffectCleanup | Promise<EffectCleanup>;
|
|
13
|
+
type EffectEntry<S> = [EffectDepsFn<S>, EffectRunner<S>];
|
|
5
14
|
interface StatoHooks<S> {
|
|
6
15
|
onInit?: (store: S) => void | Promise<void>;
|
|
7
16
|
onDestroy?: (store: S) => void | Promise<void>;
|
|
@@ -13,6 +22,8 @@ interface StatoHooks<S> {
|
|
|
13
22
|
interface StatoStoreConfig<S extends object> {
|
|
14
23
|
actions?: ActionsMap<StateSlice<S>>;
|
|
15
24
|
computed?: Record<string, ComputedFn<StateSlice<S>> | unknown[]>;
|
|
25
|
+
selectors?: Record<string, SelectorFn<StateSlice<S>> | unknown[]>;
|
|
26
|
+
effects?: EffectEntry<StateSlice<S>>[];
|
|
16
27
|
hooks?: StatoHooks<any>;
|
|
17
28
|
[key: string]: unknown;
|
|
18
29
|
}
|
|
@@ -95,6 +106,21 @@ declare function fromStream<S, T>(setupFn: (state: S) => StatoObservable<T>, upd
|
|
|
95
106
|
|
|
96
107
|
declare function optimistic<S, A extends unknown[]>(immediate: (state: S, ...args: A) => void, confirm: (state: S, ...args: A) => Promise<void>): (state: S, ...args: A) => Promise<void>;
|
|
97
108
|
|
|
109
|
+
interface PersistStorage {
|
|
110
|
+
getItem(key: string): string | null;
|
|
111
|
+
setItem(key: string, value: string): void;
|
|
112
|
+
removeItem(key: string): void;
|
|
113
|
+
}
|
|
114
|
+
interface PersistOptions<S extends object> {
|
|
115
|
+
key: string;
|
|
116
|
+
version?: number;
|
|
117
|
+
storage?: PersistStorage;
|
|
118
|
+
pick?: (keyof S)[];
|
|
119
|
+
migrate?: (data: unknown, fromVersion: number) => Partial<S>;
|
|
120
|
+
onError?: (error: Error) => void;
|
|
121
|
+
}
|
|
122
|
+
declare function withPersist<S extends object>(config: S & StatoStoreConfig<S>, options: PersistOptions<StateSlice<S>>): S & StatoStoreConfig<S>;
|
|
123
|
+
|
|
98
124
|
interface ActionLog {
|
|
99
125
|
id: number;
|
|
100
126
|
name: string;
|
|
@@ -124,4 +150,4 @@ declare function createDevTools(maxLogs?: number): DevToolsInstance;
|
|
|
124
150
|
declare const devTools: DevToolsInstance;
|
|
125
151
|
declare function connectDevTools(store: any, storeName: string): void;
|
|
126
152
|
|
|
127
|
-
export { type ActionLog, type DevToolsInstance, type DevToolsState, type RequestOptions, type StatoConfig, type StatoHooks, StatoHttp, StatoHttpError, type StatoStoreConfig, type StatoStoreInstance, abortable, configureHttp, connectDevTools, createDevTools, createHttp, createStore, debounced, devTools, fromStream, http, optimistic, retryable, throttled };
|
|
153
|
+
export { type ActionLog, type DevToolsInstance, type DevToolsState, type EffectDepsFn, type EffectEntry, type EffectRunner, type PersistOptions, type PersistStorage, type RequestOptions, type StatoConfig, type StatoHooks, StatoHttp, StatoHttpError, type StatoStoreConfig, type StatoStoreInstance, abortable, configureHttp, connectDevTools, createDevTools, createHttp, createStore, debounced, devTools, fromStream, http, optimistic, retryable, throttled, withPersist };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
type StateSlice<T> = Omit<T, 'actions' | 'computed' | 'hooks'>;
|
|
1
|
+
type StateSlice<T> = Omit<T, 'actions' | 'computed' | 'selectors' | 'hooks'>;
|
|
2
2
|
type Action<S> = (state: S, ...args: any[]) => void | Promise<void> | (() => void);
|
|
3
3
|
type ActionsMap<S> = Record<string, Action<S>>;
|
|
4
4
|
type ComputedFn<S> = (state: S) => unknown;
|
|
5
|
+
type SelectorFn<S> = (state: S) => unknown;
|
|
6
|
+
type EffectDepsFn<S> = (state: S) => unknown | unknown[];
|
|
7
|
+
type EffectCleanup = void | (() => void);
|
|
8
|
+
type EffectRunner<S> = (depsValue: unknown | unknown[], ctx: {
|
|
9
|
+
state: Readonly<S>;
|
|
10
|
+
store: any;
|
|
11
|
+
prevDepsValue?: unknown | unknown[];
|
|
12
|
+
}) => EffectCleanup | Promise<EffectCleanup>;
|
|
13
|
+
type EffectEntry<S> = [EffectDepsFn<S>, EffectRunner<S>];
|
|
5
14
|
interface StatoHooks<S> {
|
|
6
15
|
onInit?: (store: S) => void | Promise<void>;
|
|
7
16
|
onDestroy?: (store: S) => void | Promise<void>;
|
|
@@ -13,6 +22,8 @@ interface StatoHooks<S> {
|
|
|
13
22
|
interface StatoStoreConfig<S extends object> {
|
|
14
23
|
actions?: ActionsMap<StateSlice<S>>;
|
|
15
24
|
computed?: Record<string, ComputedFn<StateSlice<S>> | unknown[]>;
|
|
25
|
+
selectors?: Record<string, SelectorFn<StateSlice<S>> | unknown[]>;
|
|
26
|
+
effects?: EffectEntry<StateSlice<S>>[];
|
|
16
27
|
hooks?: StatoHooks<any>;
|
|
17
28
|
[key: string]: unknown;
|
|
18
29
|
}
|
|
@@ -95,6 +106,21 @@ declare function fromStream<S, T>(setupFn: (state: S) => StatoObservable<T>, upd
|
|
|
95
106
|
|
|
96
107
|
declare function optimistic<S, A extends unknown[]>(immediate: (state: S, ...args: A) => void, confirm: (state: S, ...args: A) => Promise<void>): (state: S, ...args: A) => Promise<void>;
|
|
97
108
|
|
|
109
|
+
interface PersistStorage {
|
|
110
|
+
getItem(key: string): string | null;
|
|
111
|
+
setItem(key: string, value: string): void;
|
|
112
|
+
removeItem(key: string): void;
|
|
113
|
+
}
|
|
114
|
+
interface PersistOptions<S extends object> {
|
|
115
|
+
key: string;
|
|
116
|
+
version?: number;
|
|
117
|
+
storage?: PersistStorage;
|
|
118
|
+
pick?: (keyof S)[];
|
|
119
|
+
migrate?: (data: unknown, fromVersion: number) => Partial<S>;
|
|
120
|
+
onError?: (error: Error) => void;
|
|
121
|
+
}
|
|
122
|
+
declare function withPersist<S extends object>(config: S & StatoStoreConfig<S>, options: PersistOptions<StateSlice<S>>): S & StatoStoreConfig<S>;
|
|
123
|
+
|
|
98
124
|
interface ActionLog {
|
|
99
125
|
id: number;
|
|
100
126
|
name: string;
|
|
@@ -124,4 +150,4 @@ declare function createDevTools(maxLogs?: number): DevToolsInstance;
|
|
|
124
150
|
declare const devTools: DevToolsInstance;
|
|
125
151
|
declare function connectDevTools(store: any, storeName: string): void;
|
|
126
152
|
|
|
127
|
-
export { type ActionLog, type DevToolsInstance, type DevToolsState, type RequestOptions, type StatoConfig, type StatoHooks, StatoHttp, StatoHttpError, type StatoStoreConfig, type StatoStoreInstance, abortable, configureHttp, connectDevTools, createDevTools, createHttp, createStore, debounced, devTools, fromStream, http, optimistic, retryable, throttled };
|
|
153
|
+
export { type ActionLog, type DevToolsInstance, type DevToolsState, type EffectDepsFn, type EffectEntry, type EffectRunner, type PersistOptions, type PersistStorage, type RequestOptions, type StatoConfig, type StatoHooks, StatoHttp, StatoHttpError, type StatoStoreConfig, type StatoStoreInstance, abortable, configureHttp, connectDevTools, createDevTools, createHttp, createStore, debounced, devTools, fromStream, http, optimistic, retryable, throttled, withPersist };
|
package/dist/index.js
CHANGED
|
@@ -10,12 +10,44 @@ var StatoStore = class {
|
|
|
10
10
|
_actions = {};
|
|
11
11
|
// Les computed enregistrés
|
|
12
12
|
_computed = {};
|
|
13
|
+
_selectors = {};
|
|
13
14
|
// Les cleanups à appeler à la destruction
|
|
14
15
|
_cleanups = [];
|
|
15
16
|
// Les hooks lifecycle
|
|
16
17
|
_hooks;
|
|
18
|
+
_publicStore = null;
|
|
19
|
+
_effects = [];
|
|
20
|
+
_createMemoizedSelector(fn) {
|
|
21
|
+
let initialized = false;
|
|
22
|
+
let cachedResult;
|
|
23
|
+
let trackedKeys = [];
|
|
24
|
+
let trackedValues = [];
|
|
25
|
+
return () => {
|
|
26
|
+
if (initialized && trackedKeys.length) {
|
|
27
|
+
const unchanged = trackedKeys.every(
|
|
28
|
+
(key, index) => Object.is(this._state[key], trackedValues[index])
|
|
29
|
+
);
|
|
30
|
+
if (unchanged) return cachedResult;
|
|
31
|
+
}
|
|
32
|
+
const reads = /* @__PURE__ */ new Set();
|
|
33
|
+
const trackingState = new Proxy(this._state, {
|
|
34
|
+
get: (target, prop, receiver) => {
|
|
35
|
+
if (typeof prop === "string" && prop in target) {
|
|
36
|
+
reads.add(prop);
|
|
37
|
+
}
|
|
38
|
+
return Reflect.get(target, prop, receiver);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
const result = fn(trackingState);
|
|
42
|
+
trackedKeys = Array.from(reads);
|
|
43
|
+
trackedValues = trackedKeys.map((key) => this._state[key]);
|
|
44
|
+
cachedResult = result;
|
|
45
|
+
initialized = true;
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
17
49
|
constructor(config) {
|
|
18
|
-
const { actions, computed, hooks, ...initialState } = config;
|
|
50
|
+
const { actions, computed, selectors, effects, hooks, ...initialState } = config;
|
|
19
51
|
this._state = initialState;
|
|
20
52
|
this._hooks = hooks ?? {};
|
|
21
53
|
if (actions) {
|
|
@@ -30,6 +62,27 @@ var StatoStore = class {
|
|
|
30
62
|
}
|
|
31
63
|
}
|
|
32
64
|
}
|
|
65
|
+
if (selectors) {
|
|
66
|
+
for (const [name, fn] of Object.entries(selectors)) {
|
|
67
|
+
if (typeof fn === "function") {
|
|
68
|
+
this._selectors[name] = this._createMemoizedSelector(fn);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (effects) {
|
|
73
|
+
for (const entry of effects) {
|
|
74
|
+
const [deps, run] = entry;
|
|
75
|
+
if (typeof deps === "function" && typeof run === "function") {
|
|
76
|
+
this._effects.push({
|
|
77
|
+
deps,
|
|
78
|
+
run,
|
|
79
|
+
hasRun: false,
|
|
80
|
+
running: false,
|
|
81
|
+
rerunRequested: false
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
33
86
|
}
|
|
34
87
|
// ── Lire le state ──────────────────────────────────
|
|
35
88
|
getState() {
|
|
@@ -38,8 +91,56 @@ var StatoStore = class {
|
|
|
38
91
|
// ── Modifier le state — usage interne uniquement ───
|
|
39
92
|
_setState(partial) {
|
|
40
93
|
this._state = { ...this._state, ...partial };
|
|
94
|
+
this._runEffects();
|
|
41
95
|
this._notify();
|
|
42
96
|
}
|
|
97
|
+
_normalizeDeps(value) {
|
|
98
|
+
return Array.isArray(value) ? value : [value];
|
|
99
|
+
}
|
|
100
|
+
_depsChanged(prev, next) {
|
|
101
|
+
if (!prev) return true;
|
|
102
|
+
if (prev.length !== next.length) return true;
|
|
103
|
+
for (let i = 0; i < next.length; i++) {
|
|
104
|
+
if (!Object.is(prev[i], next[i])) return true;
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
_runEffects(force = false) {
|
|
109
|
+
for (const effect of this._effects) {
|
|
110
|
+
const depsValue = effect.deps(this._state);
|
|
111
|
+
const depsArray = this._normalizeDeps(depsValue);
|
|
112
|
+
const shouldRun = force || this._depsChanged(effect.prevDeps, depsArray);
|
|
113
|
+
if (!shouldRun) continue;
|
|
114
|
+
const execute = async () => {
|
|
115
|
+
if (effect.running) {
|
|
116
|
+
effect.rerunRequested = true;
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
effect.running = true;
|
|
120
|
+
effect.rerunRequested = false;
|
|
121
|
+
const prevDepsValue = effect.prevDeps;
|
|
122
|
+
effect.prevDeps = depsArray;
|
|
123
|
+
try {
|
|
124
|
+
effect.cleanup?.();
|
|
125
|
+
const maybeCleanup = await effect.run(depsValue, {
|
|
126
|
+
state: { ...this._state },
|
|
127
|
+
store: this._publicStore,
|
|
128
|
+
prevDepsValue
|
|
129
|
+
});
|
|
130
|
+
effect.cleanup = typeof maybeCleanup === "function" ? maybeCleanup : void 0;
|
|
131
|
+
effect.hasRun = true;
|
|
132
|
+
} catch (error) {
|
|
133
|
+
this._hooks.onError?.(error, "effect");
|
|
134
|
+
} finally {
|
|
135
|
+
effect.running = false;
|
|
136
|
+
if (effect.rerunRequested) {
|
|
137
|
+
this._runEffects();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
void execute();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
43
144
|
// ── Notifier tous les abonnés ──────────────────────
|
|
44
145
|
_notify() {
|
|
45
146
|
for (const subscriber of this._subscribers) {
|
|
@@ -82,16 +183,34 @@ var StatoStore = class {
|
|
|
82
183
|
if (!fn) throw new Error(`[Stato] Computed "${name}" introuvable`);
|
|
83
184
|
return fn();
|
|
84
185
|
}
|
|
186
|
+
getSelector(name) {
|
|
187
|
+
const fn = this._selectors[name];
|
|
188
|
+
if (!fn) throw new Error(`[Stato] Selector "${name}" introuvable`);
|
|
189
|
+
return fn();
|
|
190
|
+
}
|
|
85
191
|
// ── Enregistrer un cleanup (pour fromStream) ───────
|
|
86
192
|
registerCleanup(fn) {
|
|
87
193
|
this._cleanups.push(fn);
|
|
88
194
|
}
|
|
195
|
+
hydrate(partial) {
|
|
196
|
+
this._setState(partial);
|
|
197
|
+
}
|
|
198
|
+
setPublicStore(publicStore) {
|
|
199
|
+
this._publicStore = publicStore;
|
|
200
|
+
this._runEffects(true);
|
|
201
|
+
}
|
|
89
202
|
// ── Lifecycle — appelé par l'adaptateur Angular ────
|
|
90
203
|
init(publicStore) {
|
|
204
|
+
this._publicStore = publicStore;
|
|
91
205
|
this._hooks.onInit?.(publicStore);
|
|
206
|
+
this._runEffects(true);
|
|
92
207
|
}
|
|
93
208
|
destroy(publicStore) {
|
|
94
209
|
this._hooks.onDestroy?.(publicStore);
|
|
210
|
+
for (const effect of this._effects) {
|
|
211
|
+
effect.cleanup?.();
|
|
212
|
+
effect.cleanup = void 0;
|
|
213
|
+
}
|
|
95
214
|
for (const cleanup of this._cleanups) {
|
|
96
215
|
cleanup();
|
|
97
216
|
}
|
|
@@ -119,7 +238,7 @@ function createStore(config) {
|
|
|
119
238
|
configurable: true
|
|
120
239
|
});
|
|
121
240
|
}
|
|
122
|
-
const { actions, computed } = config;
|
|
241
|
+
const { actions, computed, selectors } = config;
|
|
123
242
|
if (actions) {
|
|
124
243
|
for (const name of Object.keys(actions)) {
|
|
125
244
|
publicStore[name] = (...args) => store.dispatch(name, ...args);
|
|
@@ -134,6 +253,16 @@ function createStore(config) {
|
|
|
134
253
|
});
|
|
135
254
|
}
|
|
136
255
|
}
|
|
256
|
+
if (selectors) {
|
|
257
|
+
for (const name of Object.keys(selectors)) {
|
|
258
|
+
Object.defineProperty(publicStore, name, {
|
|
259
|
+
get: () => store.getSelector(name),
|
|
260
|
+
enumerable: true,
|
|
261
|
+
configurable: true
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
store.setPublicStore(publicStore);
|
|
137
266
|
return publicStore;
|
|
138
267
|
}
|
|
139
268
|
|
|
@@ -366,6 +495,85 @@ function optimistic(immediate, confirm) {
|
|
|
366
495
|
};
|
|
367
496
|
}
|
|
368
497
|
|
|
498
|
+
// src/helpers/with-persist.ts
|
|
499
|
+
function resolveStorage(custom) {
|
|
500
|
+
if (custom) return custom;
|
|
501
|
+
if (typeof window === "undefined") return null;
|
|
502
|
+
try {
|
|
503
|
+
return window.localStorage;
|
|
504
|
+
} catch {
|
|
505
|
+
return null;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
function pickState(state, keys) {
|
|
509
|
+
if (!keys?.length) return state;
|
|
510
|
+
const picked = {};
|
|
511
|
+
for (const key of keys) {
|
|
512
|
+
picked[key] = state[key];
|
|
513
|
+
}
|
|
514
|
+
return picked;
|
|
515
|
+
}
|
|
516
|
+
function withPersist(config, options) {
|
|
517
|
+
const {
|
|
518
|
+
key,
|
|
519
|
+
version = 1,
|
|
520
|
+
storage: customStorage,
|
|
521
|
+
pick,
|
|
522
|
+
migrate,
|
|
523
|
+
onError
|
|
524
|
+
} = options;
|
|
525
|
+
const storage = resolveStorage(customStorage);
|
|
526
|
+
const userHooks = config.hooks ?? {};
|
|
527
|
+
const mergedHooks = {
|
|
528
|
+
...userHooks,
|
|
529
|
+
onInit(store) {
|
|
530
|
+
try {
|
|
531
|
+
if (!storage) return userHooks.onInit?.(store);
|
|
532
|
+
const raw = storage.getItem(key);
|
|
533
|
+
if (!raw) return userHooks.onInit?.(store);
|
|
534
|
+
const parsed = JSON.parse(raw);
|
|
535
|
+
const data = parsed.v === version ? parsed.data : migrate ? migrate(parsed.data, parsed.v) : parsed.data;
|
|
536
|
+
if (data && typeof data === "object") {
|
|
537
|
+
store.__store__?.hydrate?.(data);
|
|
538
|
+
}
|
|
539
|
+
} catch (error) {
|
|
540
|
+
onError?.(error);
|
|
541
|
+
}
|
|
542
|
+
return userHooks.onInit?.(store);
|
|
543
|
+
},
|
|
544
|
+
onStateChange(prev, next) {
|
|
545
|
+
try {
|
|
546
|
+
if (storage) {
|
|
547
|
+
const payload = {
|
|
548
|
+
v: version,
|
|
549
|
+
data: pickState(next, pick)
|
|
550
|
+
};
|
|
551
|
+
storage.setItem(key, JSON.stringify(payload));
|
|
552
|
+
}
|
|
553
|
+
} catch (error) {
|
|
554
|
+
onError?.(error);
|
|
555
|
+
}
|
|
556
|
+
userHooks.onStateChange?.(prev, next);
|
|
557
|
+
},
|
|
558
|
+
onDestroy(store) {
|
|
559
|
+
return userHooks.onDestroy?.(store);
|
|
560
|
+
},
|
|
561
|
+
onAction(name, args) {
|
|
562
|
+
return userHooks.onAction?.(name, args);
|
|
563
|
+
},
|
|
564
|
+
onActionDone(name, duration) {
|
|
565
|
+
return userHooks.onActionDone?.(name, duration);
|
|
566
|
+
},
|
|
567
|
+
onError(error, actionName) {
|
|
568
|
+
return userHooks.onError?.(error, actionName);
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
return {
|
|
572
|
+
...config,
|
|
573
|
+
hooks: mergedHooks
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
|
|
369
577
|
// src/devtools.ts
|
|
370
578
|
function createDevTools(maxLogs = 50) {
|
|
371
579
|
let counter = 0;
|
|
@@ -467,5 +675,6 @@ exports.http = http;
|
|
|
467
675
|
exports.optimistic = optimistic;
|
|
468
676
|
exports.retryable = retryable;
|
|
469
677
|
exports.throttled = throttled;
|
|
678
|
+
exports.withPersist = withPersist;
|
|
470
679
|
//# sourceMappingURL=index.js.map
|
|
471
680
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/store.ts","../src/types.ts","../src/http.ts","../src/helpers/abortable.ts","../src/helpers/debounced.ts","../src/helpers/throttled.ts","../src/helpers/retryable.ts","../src/helpers/from-stream.ts","../src/helpers/optimistic.ts","../src/devtools.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// ─────────────────────────────────────────────────────\r\n// @ngstato/core — createStore()\r\n// Le moteur principal de Stato\r\n// ─────────────────────────────────────────────────────\r\n\r\nimport type {\r\n StatoStoreConfig,\r\n StatoHooks,\r\n StateSlice\r\n} from './types'\r\n\r\n// ─────────────────────────────────────────────────────\r\n// CLASSE INTERNE — jamais exposée directement\r\n// ─────────────────────────────────────────────────────\r\n\r\nclass StatoStore<S extends object> {\r\n\r\n // Le state interne — jamais accessible directement\r\n private _state: StateSlice<S>\r\n\r\n // Les abonnés — notifiés à chaque changement\r\n private _subscribers: Set<(state: StateSlice<S>) => void> = new Set()\r\n\r\n // Les actions enregistrées\r\n private _actions: Record<string, Function> = {}\r\n\r\n // Les computed enregistrés\r\n private _computed: Record<string, () => unknown> = {}\r\n\r\n // Les cleanups à appeler à la destruction\r\n private _cleanups: Array<() => void> = []\r\n\r\n // Les hooks lifecycle\r\n private _hooks: StatoHooks<any>\r\n\r\n constructor(config: StatoStoreConfig<S>) {\r\n // 1. Extraire le state initial — tout sauf actions/computed/hooks\r\n const { actions, computed, hooks, ...initialState } = config\r\n this._state = initialState as StateSlice<S>\r\n this._hooks = hooks ?? {}\r\n\r\n // 2. Enregistrer les actions\r\n if (actions) {\r\n for (const [name, fn] of Object.entries(actions)) {\r\n this._actions[name] = fn\r\n }\r\n }\r\n\r\n // 3. Enregistrer les computed\r\n if (computed) {\r\n for (const [name, fn] of Object.entries(computed)) {\r\n if (typeof fn === 'function') {\r\n this._computed[name] = () => (fn as Function)(this._state)\r\n }\r\n }\r\n }\r\n }\r\n\r\n // ── Lire le state ──────────────────────────────────\r\n getState(): Readonly<StateSlice<S>> {\r\n return { ...this._state }\r\n }\r\n\r\n // ── Modifier le state — usage interne uniquement ───\r\n private _setState(partial: Partial<StateSlice<S>>) {\r\n // Copie immutable — on ne modifie jamais l'objet original\r\n this._state = { ...this._state, ...partial }\r\n this._notify()\r\n }\r\n\r\n // ── Notifier tous les abonnés ──────────────────────\r\n private _notify() {\r\n for (const subscriber of this._subscribers) {\r\n subscriber({ ...this._state })\r\n }\r\n }\r\n\r\n // ── S'abonner aux changements ──────────────────────\r\n subscribe(fn: (state: StateSlice<S>) => void): () => void {\r\n this._subscribers.add(fn)\r\n // Retourne une fonction de désabonnement\r\n return () => this._subscribers.delete(fn)\r\n }\r\n\r\n // ── Exécuter une action ────────────────────────────\r\nasync dispatch(actionName: string, ...args: unknown[]) {\r\n const action = this._actions[actionName]\r\n if (!action) {\r\n throw new Error(`[Stato] Action \"${actionName}\" introuvable`)\r\n }\r\n\r\n // Hook onAction — avant l'exécution\r\n this._hooks.onAction?.(actionName, args)\r\n\r\n const start = Date.now()\r\n const prevState = { ...this._state }\r\n\r\n const stateProxy = new Proxy({ ...this._state } as any, {\r\n set: (target, key, value) => {\r\n target[key] = value\r\n this._setState({ [key]: value } as any)\r\n return true\r\n }\r\n })\r\n\r\n try {\r\n await action(stateProxy, ...args)\r\n\r\n // Hook onActionDone — après l'exécution\r\n this._hooks.onActionDone?.(actionName, Date.now() - start)\r\n\r\n // Hook onStateChange — si le state a changé\r\n this._hooks.onStateChange?.(prevState as any, { ...this._state } as any)\r\n\r\n } catch (error) {\r\n // Hook onError — si une erreur est lancée\r\n this._hooks.onError?.(error as Error, actionName)\r\n throw error // on remonte l'erreur quand même\r\n }\r\n}\r\n\r\n // ── Lire une valeur computed ───────────────────────\r\n getComputed(name: string): unknown {\r\n const fn = this._computed[name]\r\n if (!fn) throw new Error(`[Stato] Computed \"${name}\" introuvable`)\r\n return fn()\r\n }\r\n\r\n // ── Enregistrer un cleanup (pour fromStream) ───────\r\n registerCleanup(fn: () => void) {\r\n this._cleanups.push(fn)\r\n }\r\n\r\n // ── Lifecycle — appelé par l'adaptateur Angular ────\r\n init(publicStore: any) {\r\n this._hooks.onInit?.(publicStore)\r\n }\r\n\r\n destroy(publicStore: any) {\r\n this._hooks.onDestroy?.(publicStore)\r\n // Nettoyer tous les streams ouverts\r\n for (const cleanup of this._cleanups) {\r\n cleanup()\r\n }\r\n this._cleanups = []\r\n this._subscribers.clear()\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// FONCTION PUBLIQUE — createStore()\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function createStore<S extends object>(config: S & StatoStoreConfig<S>) {\r\n\r\n // Créer l'instance interne\r\n const store = new StatoStore<S>(config as StatoStoreConfig<S>)\r\n\r\n // Construire l'objet public\r\n // Les propriétés du state sont accessibles directement\r\n // Les actions sont exposées sans le paramètre state\r\n const publicStore: any = {\r\n // Accès au store interne — pour les adaptateurs Angular/React/Vue\r\n __store__: store,\r\n\r\n // S'abonner aux changements\r\n subscribe: store.subscribe.bind(store),\r\n\r\n // Lire le state complet\r\n getState: store.getState.bind(store),\r\n\r\n // Enregistrer un cleanup\r\n registerCleanup: store.registerCleanup.bind(store),\r\n }\r\n\r\n // Exposer chaque propriété du state\r\n const initialState = store.getState()\r\n for (const key of Object.keys(initialState as object)) {\r\n Object.defineProperty(publicStore, key, {\r\n get: () => store.getState()[key as keyof typeof initialState],\r\n enumerable: true,\r\n configurable: true\r\n })\r\n }\r\n\r\n // Exposer chaque action\r\n const { actions, computed } = config as StatoStoreConfig<S>\r\n\r\n if (actions) {\r\n for (const name of Object.keys(actions)) {\r\n publicStore[name] = (...args: unknown[]) => store.dispatch(name, ...args)\r\n }\r\n }\r\n\r\n // Exposer chaque computed\r\n if (computed) {\r\n for (const name of Object.keys(computed)) {\r\n Object.defineProperty(publicStore, name, {\r\n get: () => store.getComputed(name),\r\n enumerable: true,\r\n configurable: true\r\n })\r\n }\r\n }\r\n\r\n return publicStore\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// store.on() — réactions inter-stores\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function on<S extends object>(\r\n sourceAction: Function,\r\n handler: (state: S) => void | Promise<void>\r\n) {\r\n // Sera implémenté dans v0.2\r\n // après que le core soit stable\r\n console.warn('[Stato] store.on() disponible en v0.2')\r\n}","// ─────────────────────────────────────────────────────\r\n// TYPES PUBLICS DE @ngstato/core\r\n// ─────────────────────────────────────────────────────\r\n\r\n// Le state de base — tout sauf actions, computed, hooks\r\nexport type StateSlice<T> = Omit<T, 'actions' | 'computed' | 'hooks'>\r\n\r\n// Une action — sync ou async\r\nexport type Action<S> = (state: S, ...args: any[]) => void | Promise<void> | (() => void)\r\n\r\n// Map d'actions\r\nexport type ActionsMap<S> = Record<string, Action<S>>\r\n\r\n// Computed — dérivé du state local\r\nexport type ComputedFn<S> = (state: S) => unknown\r\n\r\n// Hooks lifecycle\r\nexport interface StatoHooks<S> {\r\n // Lifecycle du store\r\n onInit?: (store: S) => void | Promise<void>\r\n onDestroy?: (store: S) => void | Promise<void>\r\n\r\n // Lifecycle des actions\r\n onAction?: (name: string, args: unknown[]) => void\r\n onActionDone?: (name: string, duration: number) => void\r\n onError?: (error: Error, actionName: string) => void\r\n\r\n // Lifecycle du state\r\n onStateChange?: (prev: S, next: S) => void\r\n}\r\n\r\n// Configuration du store\r\nexport interface StatoStoreConfig<S extends object> {\r\n actions?: ActionsMap<StateSlice<S>>\r\n computed?: Record<string, ComputedFn<StateSlice<S>> | unknown[]>\r\n hooks?: StatoHooks<any>\r\n [key: string]: unknown\r\n}\r\n\r\n// Instance publique du store\r\nexport type StatoStoreInstance<S extends object> = {\r\n // readonly — on ne peut lire, jamais écrire directement\r\n readonly [K in keyof StateSlice<S>]: StateSlice<S>[K]\r\n} & {\r\n // Les actions sont exposées sans le paramètre state\r\n [K in keyof S as S[K] extends Function ? K : never]:\r\n S[K] extends (state: any, ...args: infer A) => infer R\r\n ? (...args: A) => R\r\n : never\r\n}\r\n\r\n// Configuration du client HTTP\r\nexport interface StatoConfig {\r\n baseUrl?: string\r\n timeout?: number\r\n headers?: Record<string, string>\r\n auth?: () => string | null | undefined\r\n}\r\n\r\n// Erreur HTTP\r\nexport class StatoHttpError extends Error {\r\n constructor(\r\n public status: number,\r\n public body: string\r\n ) {\r\n super(`HTTP ${status}: ${body}`)\r\n this.name = 'StatoHttpError'\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — StatoHttp\r\n// Client HTTP natif — fetch + baseUrl + auth + timeout\r\n// Zero dépendance — pas de HttpClient Angular\r\n// ─────────────────────────────────────────────────────\r\n\r\nimport type { StatoConfig } from './types'\r\nimport { StatoHttpError } from './types'\r\n\r\n// ─────────────────────────────────────────────────────\r\n// OPTIONS PAR REQUÊTE\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface RequestOptions {\r\n params?: Record<string, string | number | boolean>\r\n headers?: Record<string, string>\r\n signal?: AbortSignal // pour abortable()\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// CLASSE PRINCIPALE\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport class StatoHttp {\r\n\r\n private _config: StatoConfig\r\n\r\n constructor(config: StatoConfig = {}) {\r\n this._config = config\r\n }\r\n\r\n // ── GET ───────────────────────────────────────────\r\n get<T = unknown>(url: string, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('GET', url, undefined, options)\r\n }\r\n\r\n // ── POST ──────────────────────────────────────────\r\n post<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('POST', url, body, options)\r\n }\r\n\r\n // ── PUT ───────────────────────────────────────────\r\n put<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('PUT', url, body, options)\r\n }\r\n\r\n // ── PATCH ─────────────────────────────────────────\r\n patch<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('PATCH', url, body, options)\r\n }\r\n\r\n // ── DELETE ────────────────────────────────────────\r\n delete<T = unknown>(url: string, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('DELETE', url, undefined, options)\r\n }\r\n\r\n // ── MOTEUR INTERNE ────────────────────────────────\r\n private async _request<T>(\r\n method: string,\r\n url: string,\r\n body?: unknown,\r\n options?: RequestOptions\r\n ): Promise<T> {\r\n\r\n // 1. Construire l'URL complète avec baseUrl + params\r\n const fullUrl = this._buildUrl(url, options?.params)\r\n\r\n // 2. Récupérer le token auth si configuré\r\n const token = this._config.auth?.()\r\n\r\n // 3. Construire les headers\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n ...this._config.headers,\r\n ...options?.headers,\r\n ...(token ? { Authorization: `Bearer ${token}` } : {})\r\n }\r\n\r\n // 4. Configurer le timeout si défini\r\n let signal = options?.signal\r\n let timeoutId: ReturnType<typeof setTimeout> | undefined\r\n\r\n if (this._config.timeout && !signal) {\r\n const controller = new AbortController()\r\n signal = controller.signal\r\n timeoutId = setTimeout(\r\n () => controller.abort(),\r\n this._config.timeout\r\n )\r\n }\r\n\r\n // 5. Exécuter la requête\r\n try {\r\n const response = await fetch(fullUrl, {\r\n method,\r\n headers,\r\n signal,\r\n ...(body !== undefined\r\n ? { body: JSON.stringify(body) }\r\n : {}\r\n )\r\n })\r\n\r\n // 6. Gérer les erreurs HTTP automatiquement\r\n if (!response.ok) {\r\n const errorBody = await response.text()\r\n throw new StatoHttpError(response.status, errorBody)\r\n }\r\n\r\n // 7. Réponse vide — ex: DELETE 204\r\n const contentType = response.headers.get('content-type')\r\n if (\r\n response.status === 204 ||\r\n !contentType?.includes('application/json')\r\n ) {\r\n return undefined as T\r\n }\r\n\r\n // 8. Parser le JSON\r\n return response.json() as Promise<T>\r\n\r\n } finally {\r\n // Toujours nettoyer le timeout\r\n if (timeoutId) clearTimeout(timeoutId)\r\n }\r\n }\r\n\r\n // ── CONSTRUIRE L'URL AVEC PARAMS ──────────────────\r\n private _buildUrl(\r\n path: string,\r\n params?: Record<string, string | number | boolean>\r\n ): string {\r\n\r\n // Si l'URL est absolue — on ne préfixe pas baseUrl\r\n const url = path.startsWith('http')\r\n ? path\r\n : `${this._config.baseUrl ?? ''}${path}`\r\n\r\n // Ajouter les query params si présents\r\n if (!params || Object.keys(params).length === 0) return url\r\n\r\n const qs = new URLSearchParams(\r\n Object.entries(params).map(([k, v]) => [k, String(v)])\r\n ).toString()\r\n\r\n return `${url}?${qs}`\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// FACTORY FUNCTION — createHttp()\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function createHttp(config: StatoConfig = {}): StatoHttp {\r\n return new StatoHttp(config)\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// INSTANCE GLOBALE — http\r\n// Utilisée dans les actions des stores\r\n// Configurée via provideStato()\r\n// ─────────────────────────────────────────────────────\r\n\r\nlet _globalHttp: StatoHttp = new StatoHttp()\r\n\r\nexport function configureHttp(config: StatoConfig): void {\r\n _globalHttp = new StatoHttp(config)\r\n}\r\n\r\n// L'objet http — utilisé dans les actions\r\n// await http.get('/api/users')\r\nexport const http = {\r\n get: <T>(url: string, options?: RequestOptions) =>\r\n _globalHttp.get<T>(url, options),\r\n\r\n post: <T>(url: string, body?: unknown, options?: RequestOptions) =>\r\n _globalHttp.post<T>(url, body, options),\r\n\r\n put: <T>(url: string, body?: unknown, options?: RequestOptions) =>\r\n _globalHttp.put<T>(url, body, options),\r\n\r\n patch: <T>(url: string, body?: unknown, options?: RequestOptions) =>\r\n _globalHttp.patch<T>(url, body, options),\r\n\r\n delete: <T>(url: string, options?: RequestOptions) =>\r\n _globalHttp.delete<T>(url, options),\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — abortable()\r\n// Annule automatiquement la requête précédente\r\n// Remplace switchMap de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface AbortableOptions {\r\n signal: AbortSignal\r\n}\r\n\r\nexport function abortable<S, A extends unknown[]>(\r\n fn: (state: S, ...args: [...A, AbortableOptions]) => Promise<void>\r\n) {\r\n let controller: AbortController | null = null\r\n\r\n return async (state: S, ...args: A): Promise<void> => {\r\n // Annuler la requête précédente si elle tourne encore\r\n if (controller) {\r\n controller.abort()\r\n }\r\n\r\n // Créer un nouveau controller pour cette requête\r\n controller = new AbortController()\r\n const signal = controller.signal\r\n\r\n try {\r\n await fn(state, ...args, { signal } as any)\r\n } catch (error: any) {\r\n // Ignorer silencieusement les erreurs d'annulation\r\n if (error?.name === 'AbortError') return\r\n throw error\r\n } finally {\r\n controller = null\r\n }\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — debounced()\r\n// Attend que l'utilisateur arrête de taper\r\n// Remplace debounceTime de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function debounced<S, A extends unknown[]>(\r\n fn: (state: S, ...args: A) => void | Promise<void>,\r\n ms: number = 300\r\n) {\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n\r\n return (state: S, ...args: A): Promise<void> => {\r\n // Annuler le timer précédent\r\n if (timer) clearTimeout(timer)\r\n\r\n // Retourner une Promise qui se résout après le délai\r\n return new Promise((resolve, reject) => {\r\n timer = setTimeout(async () => {\r\n try {\r\n await fn(state, ...args)\r\n resolve()\r\n } catch (error) {\r\n reject(error)\r\n } finally {\r\n timer = null\r\n }\r\n }, ms)\r\n })\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — throttled()\r\n// Limite la fréquence d'exécution d'une action\r\n// Remplace throttleTime de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function throttled<S, A extends unknown[]>(\r\n fn: (state: S, ...args: A) => void | Promise<void>,\r\n ms: number = 300\r\n) {\r\n let lastCall = 0\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n\r\n return async (state: S, ...args: A): Promise<void> => {\r\n const now = Date.now()\r\n const remaining = ms - (now - lastCall)\r\n\r\n if (remaining <= 0) {\r\n // Assez de temps passé — on exécute immédiatement\r\n lastCall = now\r\n if (timer) {\r\n clearTimeout(timer)\r\n timer = null\r\n }\r\n await fn(state, ...args)\r\n } else {\r\n // Trop tôt — on planifie pour la fin du délai\r\n if (timer) clearTimeout(timer)\r\n return new Promise((resolve, reject) => {\r\n timer = setTimeout(async () => {\r\n lastCall = Date.now()\r\n timer = null\r\n try {\r\n await fn(state, ...args)\r\n resolve()\r\n } catch (error) {\r\n reject(error)\r\n }\r\n }, remaining)\r\n })\r\n }\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — retryable()\r\n// Réessaie automatiquement en cas d'échec\r\n// Remplace retryWhen de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface RetryOptions {\r\n attempts: number // nombre de tentatives\r\n backoff: 'fixed' | 'exponential' // stratégie de délai\r\n delay?: number // délai de base en ms (défaut 1000)\r\n onRetry?: (attempt: number, error: Error) => void // callback optionnel\r\n}\r\n\r\nexport function retryable<S, A extends unknown[]>(\r\n fn: (state: S, ...args: A) => Promise<void>,\r\n options: RetryOptions = {\r\n attempts: 3,\r\n backoff: 'exponential',\r\n delay: 1000\r\n }\r\n) {\r\n return async (state: S, ...args: A): Promise<void> => {\r\n const { attempts, backoff, delay = 1000, onRetry } = options\r\n\r\n for (let i = 0; i < attempts; i++) {\r\n try {\r\n await fn(state, ...args)\r\n return // succès — on sort immédiatement\r\n\r\n } catch (error) {\r\n const isLastAttempt = i === attempts - 1\r\n\r\n // Dernière tentative — on remonte l'erreur\r\n if (isLastAttempt) throw error\r\n\r\n // Calculer le délai avant la prochaine tentative\r\n const waitMs = backoff === 'exponential'\r\n ? delay * Math.pow(2, i) // 1s, 2s, 4s, 8s...\r\n : delay // fixe : toujours 1s\r\n\r\n // Callback optionnel — pour logger ou afficher un message\r\n onRetry?.(i + 1, error as Error)\r\n\r\n // Attendre avant de réessayer\r\n await new Promise(resolve => setTimeout(resolve, waitMs))\r\n }\r\n }\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — fromStream()\r\n// Pont entre un flux Observable/callback et le state\r\n// Pour : Firebase, Supabase, WebSocket, SSE\r\n// RxJS optionnel — pas obligatoire\r\n// ─────────────────────────────────────────────────────\r\n\r\n// Interface minimale d'un Observable\r\n// Compatible RxJS sans l'importer\r\nexport interface StatoObservable<T> {\r\n subscribe(observer: {\r\n next?: (value: T) => void\r\n error?: (error: unknown) => void\r\n complete?: () => void\r\n }): { unsubscribe(): void }\r\n}\r\n\r\nexport interface StreamOptions {\r\n // Appelé quand le stream se termine normalement\r\n onComplete?: () => void\r\n // Appelé quand le stream rencontre une erreur\r\n onError?: (error: unknown) => void\r\n}\r\n\r\nexport function fromStream<S, T>(\r\n // setupFn — retourne l'Observable ou le flux\r\n setupFn: (state: S) => StatoObservable<T>,\r\n // updateFn — appelé à chaque valeur émise\r\n updateFn: (state: S, value: T) => void,\r\n options?: StreamOptions\r\n) {\r\n return (state: S): (() => void) => {\r\n // Démarrer le flux\r\n const stream$ = setupFn(state)\r\n const subscription = stream$.subscribe({\r\n\r\n next: (value: T) => {\r\n // Mettre à jour le state à chaque émission\r\n updateFn(state, value)\r\n },\r\n\r\n error: (error: unknown) => {\r\n options?.onError?.(error)\r\n },\r\n\r\n complete: () => {\r\n options?.onComplete?.()\r\n }\r\n })\r\n\r\n // Retourner la fonction de cleanup\r\n // appelée automatiquement à la destruction du store\r\n return () => subscription.unsubscribe()\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — optimistic()\r\n// Mise à jour optimiste avec rollback automatique\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function optimistic<S, A extends unknown[]>(\r\n // Action immédiate — modifie le state sans attendre\r\n immediate: (state: S, ...args: A) => void,\r\n // Confirmation API — si elle échoue → rollback\r\n confirm: (state: S, ...args: A) => Promise<void>\r\n) {\r\n return async (state: S, ...args: A): Promise<void> => {\r\n // 1. Snapshot du state AVANT la modification\r\n const snapshot = { ...(state as object) } as S\r\n\r\n // 2. Appliquer la modification immédiatement\r\n immediate(state, ...args)\r\n\r\n try {\r\n // 3. Confirmer avec l'API\r\n await confirm(state, ...args)\r\n // Succès — le state optimiste est correct, rien à faire\r\n\r\n } catch (error) {\r\n // 4. Échec — restaurer le state d'avant\r\n Object.assign(state as object, snapshot)\r\n throw error\r\n }\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — DevTools\r\n// Logique pure — pas de dépendance Angular\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface ActionLog {\r\n id: number\r\n name: string\r\n args: unknown[]\r\n duration: number\r\n status: 'success' | 'error'\r\n error?: string\r\n prevState: unknown\r\n nextState: unknown\r\n at: string\r\n}\r\n\r\nexport interface DevToolsState {\r\n logs: ActionLog[]\r\n isOpen: boolean\r\n maxLogs: number\r\n}\r\n\r\nexport interface DevToolsInstance {\r\n state: DevToolsState\r\n logAction: (log: Omit<ActionLog, 'id' | 'at'>) => void\r\n clear: () => void\r\n open: () => void\r\n close: () => void\r\n toggle: () => void\r\n subscribe: (cb: (state: DevToolsState) => void) => () => void\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// FACTORY\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function createDevTools(maxLogs = 50): DevToolsInstance {\r\n let counter = 0\r\n\r\n const state: DevToolsState = {\r\n logs: [],\r\n isOpen: false,\r\n maxLogs\r\n }\r\n\r\n const listeners = new Set<(state: DevToolsState) => void>()\r\n\r\n function notify() {\r\n listeners.forEach(cb => cb({ ...state, logs: [...state.logs] }))\r\n }\r\n\r\n return {\r\n state,\r\n\r\n logAction(log) {\r\n const entry: ActionLog = {\r\n ...log,\r\n id: ++counter,\r\n at: new Date().toISOString()\r\n }\r\n\r\n state.logs = [entry, ...state.logs].slice(0, maxLogs)\r\n notify()\r\n },\r\n\r\n clear() {\r\n state.logs = []\r\n notify()\r\n },\r\n\r\n open() {\r\n state.isOpen = true\r\n notify()\r\n },\r\n\r\n close() {\r\n state.isOpen = false\r\n notify()\r\n },\r\n\r\n toggle() {\r\n state.isOpen = !state.isOpen\r\n notify()\r\n },\r\n\r\n subscribe(cb) {\r\n listeners.add(cb)\r\n return () => listeners.delete(cb)\r\n }\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// INSTANCE GLOBALE — singleton partagé entre tous les stores\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport const devTools = createDevTools()\r\n\r\n// ─────────────────────────────────────────────────────\r\n// PLUGIN — connecte un store aux DevTools\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function connectDevTools(store: any, storeName: string) {\r\n if (!devTools) return\r\n\r\n let prevState: any = {}\r\n\r\n // Accès aux hooks via __store__\r\n const internalStore = store.__store__\r\n\r\n if (!internalStore) return\r\n\r\n // Sauvegarder les hooks existants\r\n const existingHooks = { ...internalStore['_hooks'] }\r\n\r\n // Remplacer les hooks\r\n internalStore['_hooks'] = {\r\n ...existingHooks,\r\n\r\n onAction(name: string, args: unknown[]) {\r\n prevState = store.getState()\r\n existingHooks.onAction?.(name, args)\r\n },\r\n\r\n onActionDone(name: string, duration: number) {\r\n const nextState = store.getState()\r\n devTools.logAction({\r\n name: `[${storeName}] ${name}`,\r\n args: [],\r\n duration,\r\n status: 'success',\r\n prevState: { ...prevState },\r\n nextState: { ...nextState }\r\n })\r\n existingHooks.onActionDone?.(name, duration)\r\n },\r\n\r\n onError(error: Error, actionName: string) {\r\n devTools.logAction({\r\n name: `[${storeName}] ${actionName}`,\r\n args: [],\r\n duration: 0,\r\n status: 'error',\r\n error: error.message,\r\n prevState: { ...prevState },\r\n nextState: { ...prevState }\r\n })\r\n existingHooks.onError?.(error, actionName)\r\n },\r\n\r\n onStateChange: existingHooks.onStateChange\r\n }\r\n}"]}
|
|
1
|
+
{"version":3,"sources":["../src/store.ts","../src/types.ts","../src/http.ts","../src/helpers/abortable.ts","../src/helpers/debounced.ts","../src/helpers/throttled.ts","../src/helpers/retryable.ts","../src/helpers/from-stream.ts","../src/helpers/optimistic.ts","../src/helpers/with-persist.ts","../src/devtools.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// ─────────────────────────────────────────────────────\r\n// @ngstato/core — createStore()\r\n// Le moteur principal de Stato\r\n// ─────────────────────────────────────────────────────\r\n\r\nimport type {\r\n StatoStoreConfig,\r\n StatoHooks,\r\n StateSlice,\r\n EffectEntry\r\n} from './types'\r\n\r\n// ─────────────────────────────────────────────────────\r\n// CLASSE INTERNE — jamais exposée directement\r\n// ─────────────────────────────────────────────────────\r\n\r\nclass StatoStore<S extends object> {\r\n\r\n // Le state interne — jamais accessible directement\r\n private _state: StateSlice<S>\r\n\r\n // Les abonnés — notifiés à chaque changement\r\n private _subscribers: Set<(state: StateSlice<S>) => void> = new Set()\r\n\r\n // Les actions enregistrées\r\n private _actions: Record<string, Function> = {}\r\n\r\n // Les computed enregistrés\r\n private _computed: Record<string, () => unknown> = {}\r\n private _selectors: Record<string, () => unknown> = {}\r\n\r\n // Les cleanups à appeler à la destruction\r\n private _cleanups: Array<() => void> = []\r\n\r\n // Les hooks lifecycle\r\n private _hooks: StatoHooks<any>\r\n private _publicStore: any = null\r\n private _effects: Array<{\r\n deps: (state: StateSlice<S>) => unknown | unknown[]\r\n run: Function\r\n prevDeps?: unknown[]\r\n hasRun: boolean\r\n cleanup?: () => void\r\n running: boolean\r\n rerunRequested: boolean\r\n }> = []\r\n\r\n private _createMemoizedSelector(fn: Function): () => unknown {\r\n let initialized = false\r\n let cachedResult: unknown\r\n let trackedKeys: string[] = []\r\n let trackedValues: unknown[] = []\r\n\r\n return () => {\r\n if (initialized && trackedKeys.length) {\r\n const unchanged = trackedKeys.every((key, index) =>\r\n Object.is((this._state as any)[key], trackedValues[index])\r\n )\r\n if (unchanged) return cachedResult\r\n }\r\n\r\n const reads = new Set<string>()\r\n const trackingState = new Proxy(this._state as any, {\r\n get: (target, prop, receiver) => {\r\n if (typeof prop === 'string' && prop in target) {\r\n reads.add(prop)\r\n }\r\n return Reflect.get(target, prop, receiver)\r\n }\r\n })\r\n\r\n const result = fn(trackingState)\r\n\r\n trackedKeys = Array.from(reads)\r\n trackedValues = trackedKeys.map((key) => (this._state as any)[key])\r\n cachedResult = result\r\n initialized = true\r\n\r\n return result\r\n }\r\n }\r\n\r\n constructor(config: StatoStoreConfig<S>) {\r\n // 1. Extraire le state initial — tout sauf actions/computed/hooks\r\n const { actions, computed, selectors, effects, hooks, ...initialState } = config\r\n this._state = initialState as StateSlice<S>\r\n this._hooks = hooks ?? {}\r\n\r\n // 2. Enregistrer les actions\r\n if (actions) {\r\n for (const [name, fn] of Object.entries(actions)) {\r\n this._actions[name] = fn\r\n }\r\n }\r\n\r\n // 3. Enregistrer les computed\r\n if (computed) {\r\n for (const [name, fn] of Object.entries(computed)) {\r\n if (typeof fn === 'function') {\r\n this._computed[name] = () => (fn as Function)(this._state)\r\n }\r\n }\r\n }\r\n\r\n // 4. Enregistrer les selectors memoïzés\r\n if (selectors) {\r\n for (const [name, fn] of Object.entries(selectors)) {\r\n if (typeof fn === 'function') {\r\n this._selectors[name] = this._createMemoizedSelector(fn as Function)\r\n }\r\n }\r\n }\r\n\r\n if (effects) {\r\n for (const entry of effects) {\r\n const [deps, run] = entry as EffectEntry<StateSlice<S>>\r\n if (typeof deps === 'function' && typeof run === 'function') {\r\n this._effects.push({\r\n deps,\r\n run,\r\n hasRun: false,\r\n running: false,\r\n rerunRequested: false\r\n })\r\n }\r\n }\r\n }\r\n }\r\n\r\n // ── Lire le state ──────────────────────────────────\r\n getState(): Readonly<StateSlice<S>> {\r\n return { ...this._state }\r\n }\r\n\r\n // ── Modifier le state — usage interne uniquement ───\r\n private _setState(partial: Partial<StateSlice<S>>) {\r\n // Copie immutable — on ne modifie jamais l'objet original\r\n this._state = { ...this._state, ...partial }\r\n this._runEffects()\r\n this._notify()\r\n }\r\n\r\n private _normalizeDeps(value: unknown | unknown[]): unknown[] {\r\n return Array.isArray(value) ? value : [value]\r\n }\r\n\r\n private _depsChanged(prev: unknown[] | undefined, next: unknown[]): boolean {\r\n if (!prev) return true\r\n if (prev.length !== next.length) return true\r\n for (let i = 0; i < next.length; i++) {\r\n if (!Object.is(prev[i], next[i])) return true\r\n }\r\n return false\r\n }\r\n\r\n private _runEffects(force = false) {\r\n for (const effect of this._effects) {\r\n const depsValue = effect.deps(this._state)\r\n const depsArray = this._normalizeDeps(depsValue)\r\n const shouldRun = force || this._depsChanged(effect.prevDeps, depsArray)\r\n if (!shouldRun) continue\r\n\r\n const execute = async () => {\r\n if (effect.running) {\r\n effect.rerunRequested = true\r\n return\r\n }\r\n\r\n effect.running = true\r\n effect.rerunRequested = false\r\n const prevDepsValue = effect.prevDeps\r\n effect.prevDeps = depsArray\r\n\r\n try {\r\n effect.cleanup?.()\r\n const maybeCleanup = await effect.run(depsValue, {\r\n state: { ...this._state },\r\n store: this._publicStore,\r\n prevDepsValue\r\n })\r\n effect.cleanup = typeof maybeCleanup === 'function' ? maybeCleanup : undefined\r\n effect.hasRun = true\r\n } catch (error) {\r\n this._hooks.onError?.(error as Error, 'effect')\r\n } finally {\r\n effect.running = false\r\n if (effect.rerunRequested) {\r\n this._runEffects()\r\n }\r\n }\r\n }\r\n\r\n void execute()\r\n }\r\n }\r\n\r\n // ── Notifier tous les abonnés ──────────────────────\r\n private _notify() {\r\n for (const subscriber of this._subscribers) {\r\n subscriber({ ...this._state })\r\n }\r\n }\r\n\r\n // ── S'abonner aux changements ──────────────────────\r\n subscribe(fn: (state: StateSlice<S>) => void): () => void {\r\n this._subscribers.add(fn)\r\n // Retourne une fonction de désabonnement\r\n return () => this._subscribers.delete(fn)\r\n }\r\n\r\n // ── Exécuter une action ────────────────────────────\r\nasync dispatch(actionName: string, ...args: unknown[]) {\r\n const action = this._actions[actionName]\r\n if (!action) {\r\n throw new Error(`[Stato] Action \"${actionName}\" introuvable`)\r\n }\r\n\r\n // Hook onAction — avant l'exécution\r\n this._hooks.onAction?.(actionName, args)\r\n\r\n const start = Date.now()\r\n const prevState = { ...this._state }\r\n\r\n const stateProxy = new Proxy({ ...this._state } as any, {\r\n set: (target, key, value) => {\r\n target[key] = value\r\n this._setState({ [key]: value } as any)\r\n return true\r\n }\r\n })\r\n\r\n try {\r\n await action(stateProxy, ...args)\r\n\r\n // Hook onActionDone — après l'exécution\r\n this._hooks.onActionDone?.(actionName, Date.now() - start)\r\n\r\n // Hook onStateChange — si le state a changé\r\n this._hooks.onStateChange?.(prevState as any, { ...this._state } as any)\r\n\r\n } catch (error) {\r\n // Hook onError — si une erreur est lancée\r\n this._hooks.onError?.(error as Error, actionName)\r\n throw error // on remonte l'erreur quand même\r\n }\r\n}\r\n\r\n // ── Lire une valeur computed ───────────────────────\r\n getComputed(name: string): unknown {\r\n const fn = this._computed[name]\r\n if (!fn) throw new Error(`[Stato] Computed \"${name}\" introuvable`)\r\n return fn()\r\n }\r\n\r\n getSelector(name: string): unknown {\r\n const fn = this._selectors[name]\r\n if (!fn) throw new Error(`[Stato] Selector \"${name}\" introuvable`)\r\n return fn()\r\n }\r\n\r\n // ── Enregistrer un cleanup (pour fromStream) ───────\r\n registerCleanup(fn: () => void) {\r\n this._cleanups.push(fn)\r\n }\r\n\r\n hydrate(partial: Partial<StateSlice<S>>) {\r\n this._setState(partial)\r\n }\r\n\r\n setPublicStore(publicStore: any) {\r\n this._publicStore = publicStore\r\n this._runEffects(true)\r\n }\r\n\r\n // ── Lifecycle — appelé par l'adaptateur Angular ────\r\n init(publicStore: any) {\r\n this._publicStore = publicStore\r\n this._hooks.onInit?.(publicStore)\r\n this._runEffects(true)\r\n }\r\n\r\n destroy(publicStore: any) {\r\n this._hooks.onDestroy?.(publicStore)\r\n for (const effect of this._effects) {\r\n effect.cleanup?.()\r\n effect.cleanup = undefined\r\n }\r\n // Nettoyer tous les streams ouverts\r\n for (const cleanup of this._cleanups) {\r\n cleanup()\r\n }\r\n this._cleanups = []\r\n this._subscribers.clear()\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// FONCTION PUBLIQUE — createStore()\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function createStore<S extends object>(config: S & StatoStoreConfig<S>) {\r\n\r\n // Créer l'instance interne\r\n const store = new StatoStore<S>(config as StatoStoreConfig<S>)\r\n\r\n // Construire l'objet public\r\n // Les propriétés du state sont accessibles directement\r\n // Les actions sont exposées sans le paramètre state\r\n const publicStore: any = {\r\n // Accès au store interne — pour les adaptateurs Angular/React/Vue\r\n __store__: store,\r\n\r\n // S'abonner aux changements\r\n subscribe: store.subscribe.bind(store),\r\n\r\n // Lire le state complet\r\n getState: store.getState.bind(store),\r\n\r\n // Enregistrer un cleanup\r\n registerCleanup: store.registerCleanup.bind(store),\r\n }\r\n\r\n // Exposer chaque propriété du state\r\n const initialState = store.getState()\r\n for (const key of Object.keys(initialState as object)) {\r\n Object.defineProperty(publicStore, key, {\r\n get: () => store.getState()[key as keyof typeof initialState],\r\n enumerable: true,\r\n configurable: true\r\n })\r\n }\r\n\r\n // Exposer chaque action\r\n const { actions, computed, selectors } = config as StatoStoreConfig<S>\r\n\r\n if (actions) {\r\n for (const name of Object.keys(actions)) {\r\n publicStore[name] = (...args: unknown[]) => store.dispatch(name, ...args)\r\n }\r\n }\r\n\r\n // Exposer chaque computed\r\n if (computed) {\r\n for (const name of Object.keys(computed)) {\r\n Object.defineProperty(publicStore, name, {\r\n get: () => store.getComputed(name),\r\n enumerable: true,\r\n configurable: true\r\n })\r\n }\r\n }\r\n\r\n if (selectors) {\r\n for (const name of Object.keys(selectors)) {\r\n Object.defineProperty(publicStore, name, {\r\n get: () => store.getSelector(name),\r\n enumerable: true,\r\n configurable: true\r\n })\r\n }\r\n }\r\n\r\n store.setPublicStore(publicStore)\r\n\r\n return publicStore\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// store.on() — réactions inter-stores\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function on<S extends object>(\r\n sourceAction: Function,\r\n handler: (state: S) => void | Promise<void>\r\n) {\r\n // Sera implémenté dans v0.2\r\n // après que le core soit stable\r\n console.warn('[Stato] store.on() disponible en v0.2')\r\n}","// ─────────────────────────────────────────────────────\r\n// TYPES PUBLICS DE @ngstato/core\r\n// ─────────────────────────────────────────────────────\r\n\r\n// Le state de base — tout sauf actions/computed/selectors/hooks\r\nexport type StateSlice<T> = Omit<T, 'actions' | 'computed' | 'selectors' | 'hooks'>\r\n\r\n// Une action — sync ou async\r\nexport type Action<S> = (state: S, ...args: any[]) => void | Promise<void> | (() => void)\r\n\r\n// Map d'actions\r\nexport type ActionsMap<S> = Record<string, Action<S>>\r\n\r\n// Computed — dérivé du state local\r\nexport type ComputedFn<S> = (state: S) => unknown\r\nexport type SelectorFn<S> = (state: S) => unknown\r\nexport type EffectDepsFn<S> = (state: S) => unknown | unknown[]\r\nexport type EffectCleanup = void | (() => void)\r\nexport type EffectRunner<S> = (\r\n depsValue: unknown | unknown[],\r\n ctx: { state: Readonly<S>; store: any; prevDepsValue?: unknown | unknown[] }\r\n) => EffectCleanup | Promise<EffectCleanup>\r\nexport type EffectEntry<S> = [EffectDepsFn<S>, EffectRunner<S>]\r\n\r\n// Hooks lifecycle\r\nexport interface StatoHooks<S> {\r\n // Lifecycle du store\r\n onInit?: (store: S) => void | Promise<void>\r\n onDestroy?: (store: S) => void | Promise<void>\r\n\r\n // Lifecycle des actions\r\n onAction?: (name: string, args: unknown[]) => void\r\n onActionDone?: (name: string, duration: number) => void\r\n onError?: (error: Error, actionName: string) => void\r\n\r\n // Lifecycle du state\r\n onStateChange?: (prev: S, next: S) => void\r\n}\r\n\r\n// Configuration du store\r\nexport interface StatoStoreConfig<S extends object> {\r\n actions?: ActionsMap<StateSlice<S>>\r\n computed?: Record<string, ComputedFn<StateSlice<S>> | unknown[]>\r\n selectors?: Record<string, SelectorFn<StateSlice<S>> | unknown[]>\r\n effects?: EffectEntry<StateSlice<S>>[]\r\n hooks?: StatoHooks<any>\r\n [key: string]: unknown\r\n}\r\n\r\n// Instance publique du store\r\nexport type StatoStoreInstance<S extends object> = {\r\n // readonly — on ne peut lire, jamais écrire directement\r\n readonly [K in keyof StateSlice<S>]: StateSlice<S>[K]\r\n} & {\r\n // Les actions sont exposées sans le paramètre state\r\n [K in keyof S as S[K] extends Function ? K : never]:\r\n S[K] extends (state: any, ...args: infer A) => infer R\r\n ? (...args: A) => R\r\n : never\r\n}\r\n\r\n// Configuration du client HTTP\r\nexport interface StatoConfig {\r\n baseUrl?: string\r\n timeout?: number\r\n headers?: Record<string, string>\r\n auth?: () => string | null | undefined\r\n}\r\n\r\n// Erreur HTTP\r\nexport class StatoHttpError extends Error {\r\n constructor(\r\n public status: number,\r\n public body: string\r\n ) {\r\n super(`HTTP ${status}: ${body}`)\r\n this.name = 'StatoHttpError'\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — StatoHttp\r\n// Client HTTP natif — fetch + baseUrl + auth + timeout\r\n// Zero dépendance — pas de HttpClient Angular\r\n// ─────────────────────────────────────────────────────\r\n\r\nimport type { StatoConfig } from './types'\r\nimport { StatoHttpError } from './types'\r\n\r\n// ─────────────────────────────────────────────────────\r\n// OPTIONS PAR REQUÊTE\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface RequestOptions {\r\n params?: Record<string, string | number | boolean>\r\n headers?: Record<string, string>\r\n signal?: AbortSignal // pour abortable()\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// CLASSE PRINCIPALE\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport class StatoHttp {\r\n\r\n private _config: StatoConfig\r\n\r\n constructor(config: StatoConfig = {}) {\r\n this._config = config\r\n }\r\n\r\n // ── GET ───────────────────────────────────────────\r\n get<T = unknown>(url: string, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('GET', url, undefined, options)\r\n }\r\n\r\n // ── POST ──────────────────────────────────────────\r\n post<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('POST', url, body, options)\r\n }\r\n\r\n // ── PUT ───────────────────────────────────────────\r\n put<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('PUT', url, body, options)\r\n }\r\n\r\n // ── PATCH ─────────────────────────────────────────\r\n patch<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('PATCH', url, body, options)\r\n }\r\n\r\n // ── DELETE ────────────────────────────────────────\r\n delete<T = unknown>(url: string, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('DELETE', url, undefined, options)\r\n }\r\n\r\n // ── MOTEUR INTERNE ────────────────────────────────\r\n private async _request<T>(\r\n method: string,\r\n url: string,\r\n body?: unknown,\r\n options?: RequestOptions\r\n ): Promise<T> {\r\n\r\n // 1. Construire l'URL complète avec baseUrl + params\r\n const fullUrl = this._buildUrl(url, options?.params)\r\n\r\n // 2. Récupérer le token auth si configuré\r\n const token = this._config.auth?.()\r\n\r\n // 3. Construire les headers\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n ...this._config.headers,\r\n ...options?.headers,\r\n ...(token ? { Authorization: `Bearer ${token}` } : {})\r\n }\r\n\r\n // 4. Configurer le timeout si défini\r\n let signal = options?.signal\r\n let timeoutId: ReturnType<typeof setTimeout> | undefined\r\n\r\n if (this._config.timeout && !signal) {\r\n const controller = new AbortController()\r\n signal = controller.signal\r\n timeoutId = setTimeout(\r\n () => controller.abort(),\r\n this._config.timeout\r\n )\r\n }\r\n\r\n // 5. Exécuter la requête\r\n try {\r\n const response = await fetch(fullUrl, {\r\n method,\r\n headers,\r\n signal,\r\n ...(body !== undefined\r\n ? { body: JSON.stringify(body) }\r\n : {}\r\n )\r\n })\r\n\r\n // 6. Gérer les erreurs HTTP automatiquement\r\n if (!response.ok) {\r\n const errorBody = await response.text()\r\n throw new StatoHttpError(response.status, errorBody)\r\n }\r\n\r\n // 7. Réponse vide — ex: DELETE 204\r\n const contentType = response.headers.get('content-type')\r\n if (\r\n response.status === 204 ||\r\n !contentType?.includes('application/json')\r\n ) {\r\n return undefined as T\r\n }\r\n\r\n // 8. Parser le JSON\r\n return response.json() as Promise<T>\r\n\r\n } finally {\r\n // Toujours nettoyer le timeout\r\n if (timeoutId) clearTimeout(timeoutId)\r\n }\r\n }\r\n\r\n // ── CONSTRUIRE L'URL AVEC PARAMS ──────────────────\r\n private _buildUrl(\r\n path: string,\r\n params?: Record<string, string | number | boolean>\r\n ): string {\r\n\r\n // Si l'URL est absolue — on ne préfixe pas baseUrl\r\n const url = path.startsWith('http')\r\n ? path\r\n : `${this._config.baseUrl ?? ''}${path}`\r\n\r\n // Ajouter les query params si présents\r\n if (!params || Object.keys(params).length === 0) return url\r\n\r\n const qs = new URLSearchParams(\r\n Object.entries(params).map(([k, v]) => [k, String(v)])\r\n ).toString()\r\n\r\n return `${url}?${qs}`\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// FACTORY FUNCTION — createHttp()\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function createHttp(config: StatoConfig = {}): StatoHttp {\r\n return new StatoHttp(config)\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// INSTANCE GLOBALE — http\r\n// Utilisée dans les actions des stores\r\n// Configurée via provideStato()\r\n// ─────────────────────────────────────────────────────\r\n\r\nlet _globalHttp: StatoHttp = new StatoHttp()\r\n\r\nexport function configureHttp(config: StatoConfig): void {\r\n _globalHttp = new StatoHttp(config)\r\n}\r\n\r\n// L'objet http — utilisé dans les actions\r\n// await http.get('/api/users')\r\nexport const http = {\r\n get: <T>(url: string, options?: RequestOptions) =>\r\n _globalHttp.get<T>(url, options),\r\n\r\n post: <T>(url: string, body?: unknown, options?: RequestOptions) =>\r\n _globalHttp.post<T>(url, body, options),\r\n\r\n put: <T>(url: string, body?: unknown, options?: RequestOptions) =>\r\n _globalHttp.put<T>(url, body, options),\r\n\r\n patch: <T>(url: string, body?: unknown, options?: RequestOptions) =>\r\n _globalHttp.patch<T>(url, body, options),\r\n\r\n delete: <T>(url: string, options?: RequestOptions) =>\r\n _globalHttp.delete<T>(url, options),\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — abortable()\r\n// Annule automatiquement la requête précédente\r\n// Remplace switchMap de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface AbortableOptions {\r\n signal: AbortSignal\r\n}\r\n\r\nexport function abortable<S, A extends unknown[]>(\r\n fn: (state: S, ...args: [...A, AbortableOptions]) => Promise<void>\r\n) {\r\n let controller: AbortController | null = null\r\n\r\n return async (state: S, ...args: A): Promise<void> => {\r\n // Annuler la requête précédente si elle tourne encore\r\n if (controller) {\r\n controller.abort()\r\n }\r\n\r\n // Créer un nouveau controller pour cette requête\r\n controller = new AbortController()\r\n const signal = controller.signal\r\n\r\n try {\r\n await fn(state, ...args, { signal } as any)\r\n } catch (error: any) {\r\n // Ignorer silencieusement les erreurs d'annulation\r\n if (error?.name === 'AbortError') return\r\n throw error\r\n } finally {\r\n controller = null\r\n }\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — debounced()\r\n// Attend que l'utilisateur arrête de taper\r\n// Remplace debounceTime de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function debounced<S, A extends unknown[]>(\r\n fn: (state: S, ...args: A) => void | Promise<void>,\r\n ms: number = 300\r\n) {\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n\r\n return (state: S, ...args: A): Promise<void> => {\r\n // Annuler le timer précédent\r\n if (timer) clearTimeout(timer)\r\n\r\n // Retourner une Promise qui se résout après le délai\r\n return new Promise((resolve, reject) => {\r\n timer = setTimeout(async () => {\r\n try {\r\n await fn(state, ...args)\r\n resolve()\r\n } catch (error) {\r\n reject(error)\r\n } finally {\r\n timer = null\r\n }\r\n }, ms)\r\n })\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — throttled()\r\n// Limite la fréquence d'exécution d'une action\r\n// Remplace throttleTime de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function throttled<S, A extends unknown[]>(\r\n fn: (state: S, ...args: A) => void | Promise<void>,\r\n ms: number = 300\r\n) {\r\n let lastCall = 0\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n\r\n return async (state: S, ...args: A): Promise<void> => {\r\n const now = Date.now()\r\n const remaining = ms - (now - lastCall)\r\n\r\n if (remaining <= 0) {\r\n // Assez de temps passé — on exécute immédiatement\r\n lastCall = now\r\n if (timer) {\r\n clearTimeout(timer)\r\n timer = null\r\n }\r\n await fn(state, ...args)\r\n } else {\r\n // Trop tôt — on planifie pour la fin du délai\r\n if (timer) clearTimeout(timer)\r\n return new Promise((resolve, reject) => {\r\n timer = setTimeout(async () => {\r\n lastCall = Date.now()\r\n timer = null\r\n try {\r\n await fn(state, ...args)\r\n resolve()\r\n } catch (error) {\r\n reject(error)\r\n }\r\n }, remaining)\r\n })\r\n }\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — retryable()\r\n// Réessaie automatiquement en cas d'échec\r\n// Remplace retryWhen de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface RetryOptions {\r\n attempts: number // nombre de tentatives\r\n backoff: 'fixed' | 'exponential' // stratégie de délai\r\n delay?: number // délai de base en ms (défaut 1000)\r\n onRetry?: (attempt: number, error: Error) => void // callback optionnel\r\n}\r\n\r\nexport function retryable<S, A extends unknown[]>(\r\n fn: (state: S, ...args: A) => Promise<void>,\r\n options: RetryOptions = {\r\n attempts: 3,\r\n backoff: 'exponential',\r\n delay: 1000\r\n }\r\n) {\r\n return async (state: S, ...args: A): Promise<void> => {\r\n const { attempts, backoff, delay = 1000, onRetry } = options\r\n\r\n for (let i = 0; i < attempts; i++) {\r\n try {\r\n await fn(state, ...args)\r\n return // succès — on sort immédiatement\r\n\r\n } catch (error) {\r\n const isLastAttempt = i === attempts - 1\r\n\r\n // Dernière tentative — on remonte l'erreur\r\n if (isLastAttempt) throw error\r\n\r\n // Calculer le délai avant la prochaine tentative\r\n const waitMs = backoff === 'exponential'\r\n ? delay * Math.pow(2, i) // 1s, 2s, 4s, 8s...\r\n : delay // fixe : toujours 1s\r\n\r\n // Callback optionnel — pour logger ou afficher un message\r\n onRetry?.(i + 1, error as Error)\r\n\r\n // Attendre avant de réessayer\r\n await new Promise(resolve => setTimeout(resolve, waitMs))\r\n }\r\n }\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — fromStream()\r\n// Pont entre un flux Observable/callback et le state\r\n// Pour : Firebase, Supabase, WebSocket, SSE\r\n// RxJS optionnel — pas obligatoire\r\n// ─────────────────────────────────────────────────────\r\n\r\n// Interface minimale d'un Observable\r\n// Compatible RxJS sans l'importer\r\nexport interface StatoObservable<T> {\r\n subscribe(observer: {\r\n next?: (value: T) => void\r\n error?: (error: unknown) => void\r\n complete?: () => void\r\n }): { unsubscribe(): void }\r\n}\r\n\r\nexport interface StreamOptions {\r\n // Appelé quand le stream se termine normalement\r\n onComplete?: () => void\r\n // Appelé quand le stream rencontre une erreur\r\n onError?: (error: unknown) => void\r\n}\r\n\r\nexport function fromStream<S, T>(\r\n // setupFn — retourne l'Observable ou le flux\r\n setupFn: (state: S) => StatoObservable<T>,\r\n // updateFn — appelé à chaque valeur émise\r\n updateFn: (state: S, value: T) => void,\r\n options?: StreamOptions\r\n) {\r\n return (state: S): (() => void) => {\r\n // Démarrer le flux\r\n const stream$ = setupFn(state)\r\n const subscription = stream$.subscribe({\r\n\r\n next: (value: T) => {\r\n // Mettre à jour le state à chaque émission\r\n updateFn(state, value)\r\n },\r\n\r\n error: (error: unknown) => {\r\n options?.onError?.(error)\r\n },\r\n\r\n complete: () => {\r\n options?.onComplete?.()\r\n }\r\n })\r\n\r\n // Retourner la fonction de cleanup\r\n // appelée automatiquement à la destruction du store\r\n return () => subscription.unsubscribe()\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — optimistic()\r\n// Mise à jour optimiste avec rollback automatique\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function optimistic<S, A extends unknown[]>(\r\n // Action immédiate — modifie le state sans attendre\r\n immediate: (state: S, ...args: A) => void,\r\n // Confirmation API — si elle échoue → rollback\r\n confirm: (state: S, ...args: A) => Promise<void>\r\n) {\r\n return async (state: S, ...args: A): Promise<void> => {\r\n // 1. Snapshot du state AVANT la modification\r\n const snapshot = { ...(state as object) } as S\r\n\r\n // 2. Appliquer la modification immédiatement\r\n immediate(state, ...args)\r\n\r\n try {\r\n // 3. Confirmer avec l'API\r\n await confirm(state, ...args)\r\n // Succès — le state optimiste est correct, rien à faire\r\n\r\n } catch (error) {\r\n // 4. Échec — restaurer le state d'avant\r\n Object.assign(state as object, snapshot)\r\n throw error\r\n }\r\n }\r\n}","import type { StateSlice, StatoStoreConfig, StatoHooks } from '../types'\n\nexport interface PersistStorage {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n removeItem(key: string): void\n}\n\nexport interface PersistEnvelope<T> {\n v: number\n data: Partial<T>\n}\n\nexport interface PersistOptions<S extends object> {\n key: string\n version?: number\n storage?: PersistStorage\n pick?: (keyof S)[]\n migrate?: (data: unknown, fromVersion: number) => Partial<S>\n onError?: (error: Error) => void\n}\n\nfunction resolveStorage(custom?: PersistStorage): PersistStorage | null {\n if (custom) return custom\n if (typeof window === 'undefined') return null\n try {\n return window.localStorage\n } catch {\n return null\n }\n}\n\nfunction pickState<S extends object>(state: Partial<S>, keys?: (keyof S)[]) {\n if (!keys?.length) return state\n const picked: Partial<S> = {}\n for (const key of keys) {\n picked[key] = state[key]\n }\n return picked\n}\n\nexport function withPersist<S extends object>(\n config: S & StatoStoreConfig<S>,\n options: PersistOptions<StateSlice<S>>\n): S & StatoStoreConfig<S> {\n const {\n key,\n version = 1,\n storage: customStorage,\n pick,\n migrate,\n onError\n } = options\n\n const storage = resolveStorage(customStorage)\n const userHooks = config.hooks ?? {}\n\n const mergedHooks: StatoHooks<any> = {\n ...userHooks,\n onInit(store: any) {\n try {\n if (!storage) return userHooks.onInit?.(store)\n const raw = storage.getItem(key)\n if (!raw) return userHooks.onInit?.(store)\n\n const parsed = JSON.parse(raw) as PersistEnvelope<StateSlice<S>>\n const data =\n parsed.v === version\n ? parsed.data\n : migrate\n ? migrate(parsed.data, parsed.v)\n : parsed.data\n\n if (data && typeof data === 'object') {\n store.__store__?.hydrate?.(data)\n }\n } catch (error) {\n onError?.(error as Error)\n }\n return userHooks.onInit?.(store)\n },\n\n onStateChange(prev: any, next: any) {\n try {\n if (storage) {\n const payload: PersistEnvelope<StateSlice<S>> = {\n v: version,\n data: pickState(next, pick as (keyof StateSlice<S>)[] | undefined)\n }\n storage.setItem(key, JSON.stringify(payload))\n }\n } catch (error) {\n onError?.(error as Error)\n }\n userHooks.onStateChange?.(prev, next)\n },\n\n onDestroy(store: any) {\n return userHooks.onDestroy?.(store)\n },\n onAction(name: string, args: unknown[]) {\n return userHooks.onAction?.(name, args)\n },\n onActionDone(name: string, duration: number) {\n return userHooks.onActionDone?.(name, duration)\n },\n onError(error: Error, actionName: string) {\n return userHooks.onError?.(error, actionName)\n }\n }\n\n return {\n ...config,\n hooks: mergedHooks\n }\n}\n\n","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — DevTools\r\n// Logique pure — pas de dépendance Angular\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface ActionLog {\r\n id: number\r\n name: string\r\n args: unknown[]\r\n duration: number\r\n status: 'success' | 'error'\r\n error?: string\r\n prevState: unknown\r\n nextState: unknown\r\n at: string\r\n}\r\n\r\nexport interface DevToolsState {\r\n logs: ActionLog[]\r\n isOpen: boolean\r\n maxLogs: number\r\n}\r\n\r\nexport interface DevToolsInstance {\r\n state: DevToolsState\r\n logAction: (log: Omit<ActionLog, 'id' | 'at'>) => void\r\n clear: () => void\r\n open: () => void\r\n close: () => void\r\n toggle: () => void\r\n subscribe: (cb: (state: DevToolsState) => void) => () => void\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// FACTORY\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function createDevTools(maxLogs = 50): DevToolsInstance {\r\n let counter = 0\r\n\r\n const state: DevToolsState = {\r\n logs: [],\r\n isOpen: false,\r\n maxLogs\r\n }\r\n\r\n const listeners = new Set<(state: DevToolsState) => void>()\r\n\r\n function notify() {\r\n listeners.forEach(cb => cb({ ...state, logs: [...state.logs] }))\r\n }\r\n\r\n return {\r\n state,\r\n\r\n logAction(log) {\r\n const entry: ActionLog = {\r\n ...log,\r\n id: ++counter,\r\n at: new Date().toISOString()\r\n }\r\n\r\n state.logs = [entry, ...state.logs].slice(0, maxLogs)\r\n notify()\r\n },\r\n\r\n clear() {\r\n state.logs = []\r\n notify()\r\n },\r\n\r\n open() {\r\n state.isOpen = true\r\n notify()\r\n },\r\n\r\n close() {\r\n state.isOpen = false\r\n notify()\r\n },\r\n\r\n toggle() {\r\n state.isOpen = !state.isOpen\r\n notify()\r\n },\r\n\r\n subscribe(cb) {\r\n listeners.add(cb)\r\n return () => listeners.delete(cb)\r\n }\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// INSTANCE GLOBALE — singleton partagé entre tous les stores\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport const devTools = createDevTools()\r\n\r\n// ─────────────────────────────────────────────────────\r\n// PLUGIN — connecte un store aux DevTools\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function connectDevTools(store: any, storeName: string) {\r\n if (!devTools) return\r\n\r\n let prevState: any = {}\r\n\r\n // Accès aux hooks via __store__\r\n const internalStore = store.__store__\r\n\r\n if (!internalStore) return\r\n\r\n // Sauvegarder les hooks existants\r\n const existingHooks = { ...internalStore['_hooks'] }\r\n\r\n // Remplacer les hooks\r\n internalStore['_hooks'] = {\r\n ...existingHooks,\r\n\r\n onAction(name: string, args: unknown[]) {\r\n prevState = store.getState()\r\n existingHooks.onAction?.(name, args)\r\n },\r\n\r\n onActionDone(name: string, duration: number) {\r\n const nextState = store.getState()\r\n devTools.logAction({\r\n name: `[${storeName}] ${name}`,\r\n args: [],\r\n duration,\r\n status: 'success',\r\n prevState: { ...prevState },\r\n nextState: { ...nextState }\r\n })\r\n existingHooks.onActionDone?.(name, duration)\r\n },\r\n\r\n onError(error: Error, actionName: string) {\r\n devTools.logAction({\r\n name: `[${storeName}] ${actionName}`,\r\n args: [],\r\n duration: 0,\r\n status: 'error',\r\n error: error.message,\r\n prevState: { ...prevState },\r\n nextState: { ...prevState }\r\n })\r\n existingHooks.onError?.(error, actionName)\r\n },\r\n\r\n onStateChange: existingHooks.onStateChange\r\n }\r\n}"]}
|
package/dist/index.mjs
CHANGED
|
@@ -8,12 +8,44 @@ var StatoStore = class {
|
|
|
8
8
|
_actions = {};
|
|
9
9
|
// Les computed enregistrés
|
|
10
10
|
_computed = {};
|
|
11
|
+
_selectors = {};
|
|
11
12
|
// Les cleanups à appeler à la destruction
|
|
12
13
|
_cleanups = [];
|
|
13
14
|
// Les hooks lifecycle
|
|
14
15
|
_hooks;
|
|
16
|
+
_publicStore = null;
|
|
17
|
+
_effects = [];
|
|
18
|
+
_createMemoizedSelector(fn) {
|
|
19
|
+
let initialized = false;
|
|
20
|
+
let cachedResult;
|
|
21
|
+
let trackedKeys = [];
|
|
22
|
+
let trackedValues = [];
|
|
23
|
+
return () => {
|
|
24
|
+
if (initialized && trackedKeys.length) {
|
|
25
|
+
const unchanged = trackedKeys.every(
|
|
26
|
+
(key, index) => Object.is(this._state[key], trackedValues[index])
|
|
27
|
+
);
|
|
28
|
+
if (unchanged) return cachedResult;
|
|
29
|
+
}
|
|
30
|
+
const reads = /* @__PURE__ */ new Set();
|
|
31
|
+
const trackingState = new Proxy(this._state, {
|
|
32
|
+
get: (target, prop, receiver) => {
|
|
33
|
+
if (typeof prop === "string" && prop in target) {
|
|
34
|
+
reads.add(prop);
|
|
35
|
+
}
|
|
36
|
+
return Reflect.get(target, prop, receiver);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
const result = fn(trackingState);
|
|
40
|
+
trackedKeys = Array.from(reads);
|
|
41
|
+
trackedValues = trackedKeys.map((key) => this._state[key]);
|
|
42
|
+
cachedResult = result;
|
|
43
|
+
initialized = true;
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
15
47
|
constructor(config) {
|
|
16
|
-
const { actions, computed, hooks, ...initialState } = config;
|
|
48
|
+
const { actions, computed, selectors, effects, hooks, ...initialState } = config;
|
|
17
49
|
this._state = initialState;
|
|
18
50
|
this._hooks = hooks ?? {};
|
|
19
51
|
if (actions) {
|
|
@@ -28,6 +60,27 @@ var StatoStore = class {
|
|
|
28
60
|
}
|
|
29
61
|
}
|
|
30
62
|
}
|
|
63
|
+
if (selectors) {
|
|
64
|
+
for (const [name, fn] of Object.entries(selectors)) {
|
|
65
|
+
if (typeof fn === "function") {
|
|
66
|
+
this._selectors[name] = this._createMemoizedSelector(fn);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (effects) {
|
|
71
|
+
for (const entry of effects) {
|
|
72
|
+
const [deps, run] = entry;
|
|
73
|
+
if (typeof deps === "function" && typeof run === "function") {
|
|
74
|
+
this._effects.push({
|
|
75
|
+
deps,
|
|
76
|
+
run,
|
|
77
|
+
hasRun: false,
|
|
78
|
+
running: false,
|
|
79
|
+
rerunRequested: false
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
31
84
|
}
|
|
32
85
|
// ── Lire le state ──────────────────────────────────
|
|
33
86
|
getState() {
|
|
@@ -36,8 +89,56 @@ var StatoStore = class {
|
|
|
36
89
|
// ── Modifier le state — usage interne uniquement ───
|
|
37
90
|
_setState(partial) {
|
|
38
91
|
this._state = { ...this._state, ...partial };
|
|
92
|
+
this._runEffects();
|
|
39
93
|
this._notify();
|
|
40
94
|
}
|
|
95
|
+
_normalizeDeps(value) {
|
|
96
|
+
return Array.isArray(value) ? value : [value];
|
|
97
|
+
}
|
|
98
|
+
_depsChanged(prev, next) {
|
|
99
|
+
if (!prev) return true;
|
|
100
|
+
if (prev.length !== next.length) return true;
|
|
101
|
+
for (let i = 0; i < next.length; i++) {
|
|
102
|
+
if (!Object.is(prev[i], next[i])) return true;
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
_runEffects(force = false) {
|
|
107
|
+
for (const effect of this._effects) {
|
|
108
|
+
const depsValue = effect.deps(this._state);
|
|
109
|
+
const depsArray = this._normalizeDeps(depsValue);
|
|
110
|
+
const shouldRun = force || this._depsChanged(effect.prevDeps, depsArray);
|
|
111
|
+
if (!shouldRun) continue;
|
|
112
|
+
const execute = async () => {
|
|
113
|
+
if (effect.running) {
|
|
114
|
+
effect.rerunRequested = true;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
effect.running = true;
|
|
118
|
+
effect.rerunRequested = false;
|
|
119
|
+
const prevDepsValue = effect.prevDeps;
|
|
120
|
+
effect.prevDeps = depsArray;
|
|
121
|
+
try {
|
|
122
|
+
effect.cleanup?.();
|
|
123
|
+
const maybeCleanup = await effect.run(depsValue, {
|
|
124
|
+
state: { ...this._state },
|
|
125
|
+
store: this._publicStore,
|
|
126
|
+
prevDepsValue
|
|
127
|
+
});
|
|
128
|
+
effect.cleanup = typeof maybeCleanup === "function" ? maybeCleanup : void 0;
|
|
129
|
+
effect.hasRun = true;
|
|
130
|
+
} catch (error) {
|
|
131
|
+
this._hooks.onError?.(error, "effect");
|
|
132
|
+
} finally {
|
|
133
|
+
effect.running = false;
|
|
134
|
+
if (effect.rerunRequested) {
|
|
135
|
+
this._runEffects();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
void execute();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
41
142
|
// ── Notifier tous les abonnés ──────────────────────
|
|
42
143
|
_notify() {
|
|
43
144
|
for (const subscriber of this._subscribers) {
|
|
@@ -80,16 +181,34 @@ var StatoStore = class {
|
|
|
80
181
|
if (!fn) throw new Error(`[Stato] Computed "${name}" introuvable`);
|
|
81
182
|
return fn();
|
|
82
183
|
}
|
|
184
|
+
getSelector(name) {
|
|
185
|
+
const fn = this._selectors[name];
|
|
186
|
+
if (!fn) throw new Error(`[Stato] Selector "${name}" introuvable`);
|
|
187
|
+
return fn();
|
|
188
|
+
}
|
|
83
189
|
// ── Enregistrer un cleanup (pour fromStream) ───────
|
|
84
190
|
registerCleanup(fn) {
|
|
85
191
|
this._cleanups.push(fn);
|
|
86
192
|
}
|
|
193
|
+
hydrate(partial) {
|
|
194
|
+
this._setState(partial);
|
|
195
|
+
}
|
|
196
|
+
setPublicStore(publicStore) {
|
|
197
|
+
this._publicStore = publicStore;
|
|
198
|
+
this._runEffects(true);
|
|
199
|
+
}
|
|
87
200
|
// ── Lifecycle — appelé par l'adaptateur Angular ────
|
|
88
201
|
init(publicStore) {
|
|
202
|
+
this._publicStore = publicStore;
|
|
89
203
|
this._hooks.onInit?.(publicStore);
|
|
204
|
+
this._runEffects(true);
|
|
90
205
|
}
|
|
91
206
|
destroy(publicStore) {
|
|
92
207
|
this._hooks.onDestroy?.(publicStore);
|
|
208
|
+
for (const effect of this._effects) {
|
|
209
|
+
effect.cleanup?.();
|
|
210
|
+
effect.cleanup = void 0;
|
|
211
|
+
}
|
|
93
212
|
for (const cleanup of this._cleanups) {
|
|
94
213
|
cleanup();
|
|
95
214
|
}
|
|
@@ -117,7 +236,7 @@ function createStore(config) {
|
|
|
117
236
|
configurable: true
|
|
118
237
|
});
|
|
119
238
|
}
|
|
120
|
-
const { actions, computed } = config;
|
|
239
|
+
const { actions, computed, selectors } = config;
|
|
121
240
|
if (actions) {
|
|
122
241
|
for (const name of Object.keys(actions)) {
|
|
123
242
|
publicStore[name] = (...args) => store.dispatch(name, ...args);
|
|
@@ -132,6 +251,16 @@ function createStore(config) {
|
|
|
132
251
|
});
|
|
133
252
|
}
|
|
134
253
|
}
|
|
254
|
+
if (selectors) {
|
|
255
|
+
for (const name of Object.keys(selectors)) {
|
|
256
|
+
Object.defineProperty(publicStore, name, {
|
|
257
|
+
get: () => store.getSelector(name),
|
|
258
|
+
enumerable: true,
|
|
259
|
+
configurable: true
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
store.setPublicStore(publicStore);
|
|
135
264
|
return publicStore;
|
|
136
265
|
}
|
|
137
266
|
|
|
@@ -364,6 +493,85 @@ function optimistic(immediate, confirm) {
|
|
|
364
493
|
};
|
|
365
494
|
}
|
|
366
495
|
|
|
496
|
+
// src/helpers/with-persist.ts
|
|
497
|
+
function resolveStorage(custom) {
|
|
498
|
+
if (custom) return custom;
|
|
499
|
+
if (typeof window === "undefined") return null;
|
|
500
|
+
try {
|
|
501
|
+
return window.localStorage;
|
|
502
|
+
} catch {
|
|
503
|
+
return null;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
function pickState(state, keys) {
|
|
507
|
+
if (!keys?.length) return state;
|
|
508
|
+
const picked = {};
|
|
509
|
+
for (const key of keys) {
|
|
510
|
+
picked[key] = state[key];
|
|
511
|
+
}
|
|
512
|
+
return picked;
|
|
513
|
+
}
|
|
514
|
+
function withPersist(config, options) {
|
|
515
|
+
const {
|
|
516
|
+
key,
|
|
517
|
+
version = 1,
|
|
518
|
+
storage: customStorage,
|
|
519
|
+
pick,
|
|
520
|
+
migrate,
|
|
521
|
+
onError
|
|
522
|
+
} = options;
|
|
523
|
+
const storage = resolveStorage(customStorage);
|
|
524
|
+
const userHooks = config.hooks ?? {};
|
|
525
|
+
const mergedHooks = {
|
|
526
|
+
...userHooks,
|
|
527
|
+
onInit(store) {
|
|
528
|
+
try {
|
|
529
|
+
if (!storage) return userHooks.onInit?.(store);
|
|
530
|
+
const raw = storage.getItem(key);
|
|
531
|
+
if (!raw) return userHooks.onInit?.(store);
|
|
532
|
+
const parsed = JSON.parse(raw);
|
|
533
|
+
const data = parsed.v === version ? parsed.data : migrate ? migrate(parsed.data, parsed.v) : parsed.data;
|
|
534
|
+
if (data && typeof data === "object") {
|
|
535
|
+
store.__store__?.hydrate?.(data);
|
|
536
|
+
}
|
|
537
|
+
} catch (error) {
|
|
538
|
+
onError?.(error);
|
|
539
|
+
}
|
|
540
|
+
return userHooks.onInit?.(store);
|
|
541
|
+
},
|
|
542
|
+
onStateChange(prev, next) {
|
|
543
|
+
try {
|
|
544
|
+
if (storage) {
|
|
545
|
+
const payload = {
|
|
546
|
+
v: version,
|
|
547
|
+
data: pickState(next, pick)
|
|
548
|
+
};
|
|
549
|
+
storage.setItem(key, JSON.stringify(payload));
|
|
550
|
+
}
|
|
551
|
+
} catch (error) {
|
|
552
|
+
onError?.(error);
|
|
553
|
+
}
|
|
554
|
+
userHooks.onStateChange?.(prev, next);
|
|
555
|
+
},
|
|
556
|
+
onDestroy(store) {
|
|
557
|
+
return userHooks.onDestroy?.(store);
|
|
558
|
+
},
|
|
559
|
+
onAction(name, args) {
|
|
560
|
+
return userHooks.onAction?.(name, args);
|
|
561
|
+
},
|
|
562
|
+
onActionDone(name, duration) {
|
|
563
|
+
return userHooks.onActionDone?.(name, duration);
|
|
564
|
+
},
|
|
565
|
+
onError(error, actionName) {
|
|
566
|
+
return userHooks.onError?.(error, actionName);
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
return {
|
|
570
|
+
...config,
|
|
571
|
+
hooks: mergedHooks
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
367
575
|
// src/devtools.ts
|
|
368
576
|
function createDevTools(maxLogs = 50) {
|
|
369
577
|
let counter = 0;
|
|
@@ -450,6 +658,6 @@ function connectDevTools(store, storeName) {
|
|
|
450
658
|
};
|
|
451
659
|
}
|
|
452
660
|
|
|
453
|
-
export { StatoHttp, StatoHttpError, abortable, configureHttp, connectDevTools, createDevTools, createHttp, createStore, debounced, devTools, fromStream, http, optimistic, retryable, throttled };
|
|
661
|
+
export { StatoHttp, StatoHttpError, abortable, configureHttp, connectDevTools, createDevTools, createHttp, createStore, debounced, devTools, fromStream, http, optimistic, retryable, throttled, withPersist };
|
|
454
662
|
//# sourceMappingURL=index.mjs.map
|
|
455
663
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/store.ts","../src/types.ts","../src/http.ts","../src/helpers/abortable.ts","../src/helpers/debounced.ts","../src/helpers/throttled.ts","../src/helpers/retryable.ts","../src/helpers/from-stream.ts","../src/helpers/optimistic.ts","../src/devtools.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["// ─────────────────────────────────────────────────────\r\n// @ngstato/core — createStore()\r\n// Le moteur principal de Stato\r\n// ─────────────────────────────────────────────────────\r\n\r\nimport type {\r\n StatoStoreConfig,\r\n StatoHooks,\r\n StateSlice\r\n} from './types'\r\n\r\n// ─────────────────────────────────────────────────────\r\n// CLASSE INTERNE — jamais exposée directement\r\n// ─────────────────────────────────────────────────────\r\n\r\nclass StatoStore<S extends object> {\r\n\r\n // Le state interne — jamais accessible directement\r\n private _state: StateSlice<S>\r\n\r\n // Les abonnés — notifiés à chaque changement\r\n private _subscribers: Set<(state: StateSlice<S>) => void> = new Set()\r\n\r\n // Les actions enregistrées\r\n private _actions: Record<string, Function> = {}\r\n\r\n // Les computed enregistrés\r\n private _computed: Record<string, () => unknown> = {}\r\n\r\n // Les cleanups à appeler à la destruction\r\n private _cleanups: Array<() => void> = []\r\n\r\n // Les hooks lifecycle\r\n private _hooks: StatoHooks<any>\r\n\r\n constructor(config: StatoStoreConfig<S>) {\r\n // 1. Extraire le state initial — tout sauf actions/computed/hooks\r\n const { actions, computed, hooks, ...initialState } = config\r\n this._state = initialState as StateSlice<S>\r\n this._hooks = hooks ?? {}\r\n\r\n // 2. Enregistrer les actions\r\n if (actions) {\r\n for (const [name, fn] of Object.entries(actions)) {\r\n this._actions[name] = fn\r\n }\r\n }\r\n\r\n // 3. Enregistrer les computed\r\n if (computed) {\r\n for (const [name, fn] of Object.entries(computed)) {\r\n if (typeof fn === 'function') {\r\n this._computed[name] = () => (fn as Function)(this._state)\r\n }\r\n }\r\n }\r\n }\r\n\r\n // ── Lire le state ──────────────────────────────────\r\n getState(): Readonly<StateSlice<S>> {\r\n return { ...this._state }\r\n }\r\n\r\n // ── Modifier le state — usage interne uniquement ───\r\n private _setState(partial: Partial<StateSlice<S>>) {\r\n // Copie immutable — on ne modifie jamais l'objet original\r\n this._state = { ...this._state, ...partial }\r\n this._notify()\r\n }\r\n\r\n // ── Notifier tous les abonnés ──────────────────────\r\n private _notify() {\r\n for (const subscriber of this._subscribers) {\r\n subscriber({ ...this._state })\r\n }\r\n }\r\n\r\n // ── S'abonner aux changements ──────────────────────\r\n subscribe(fn: (state: StateSlice<S>) => void): () => void {\r\n this._subscribers.add(fn)\r\n // Retourne une fonction de désabonnement\r\n return () => this._subscribers.delete(fn)\r\n }\r\n\r\n // ── Exécuter une action ────────────────────────────\r\nasync dispatch(actionName: string, ...args: unknown[]) {\r\n const action = this._actions[actionName]\r\n if (!action) {\r\n throw new Error(`[Stato] Action \"${actionName}\" introuvable`)\r\n }\r\n\r\n // Hook onAction — avant l'exécution\r\n this._hooks.onAction?.(actionName, args)\r\n\r\n const start = Date.now()\r\n const prevState = { ...this._state }\r\n\r\n const stateProxy = new Proxy({ ...this._state } as any, {\r\n set: (target, key, value) => {\r\n target[key] = value\r\n this._setState({ [key]: value } as any)\r\n return true\r\n }\r\n })\r\n\r\n try {\r\n await action(stateProxy, ...args)\r\n\r\n // Hook onActionDone — après l'exécution\r\n this._hooks.onActionDone?.(actionName, Date.now() - start)\r\n\r\n // Hook onStateChange — si le state a changé\r\n this._hooks.onStateChange?.(prevState as any, { ...this._state } as any)\r\n\r\n } catch (error) {\r\n // Hook onError — si une erreur est lancée\r\n this._hooks.onError?.(error as Error, actionName)\r\n throw error // on remonte l'erreur quand même\r\n }\r\n}\r\n\r\n // ── Lire une valeur computed ───────────────────────\r\n getComputed(name: string): unknown {\r\n const fn = this._computed[name]\r\n if (!fn) throw new Error(`[Stato] Computed \"${name}\" introuvable`)\r\n return fn()\r\n }\r\n\r\n // ── Enregistrer un cleanup (pour fromStream) ───────\r\n registerCleanup(fn: () => void) {\r\n this._cleanups.push(fn)\r\n }\r\n\r\n // ── Lifecycle — appelé par l'adaptateur Angular ────\r\n init(publicStore: any) {\r\n this._hooks.onInit?.(publicStore)\r\n }\r\n\r\n destroy(publicStore: any) {\r\n this._hooks.onDestroy?.(publicStore)\r\n // Nettoyer tous les streams ouverts\r\n for (const cleanup of this._cleanups) {\r\n cleanup()\r\n }\r\n this._cleanups = []\r\n this._subscribers.clear()\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// FONCTION PUBLIQUE — createStore()\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function createStore<S extends object>(config: S & StatoStoreConfig<S>) {\r\n\r\n // Créer l'instance interne\r\n const store = new StatoStore<S>(config as StatoStoreConfig<S>)\r\n\r\n // Construire l'objet public\r\n // Les propriétés du state sont accessibles directement\r\n // Les actions sont exposées sans le paramètre state\r\n const publicStore: any = {\r\n // Accès au store interne — pour les adaptateurs Angular/React/Vue\r\n __store__: store,\r\n\r\n // S'abonner aux changements\r\n subscribe: store.subscribe.bind(store),\r\n\r\n // Lire le state complet\r\n getState: store.getState.bind(store),\r\n\r\n // Enregistrer un cleanup\r\n registerCleanup: store.registerCleanup.bind(store),\r\n }\r\n\r\n // Exposer chaque propriété du state\r\n const initialState = store.getState()\r\n for (const key of Object.keys(initialState as object)) {\r\n Object.defineProperty(publicStore, key, {\r\n get: () => store.getState()[key as keyof typeof initialState],\r\n enumerable: true,\r\n configurable: true\r\n })\r\n }\r\n\r\n // Exposer chaque action\r\n const { actions, computed } = config as StatoStoreConfig<S>\r\n\r\n if (actions) {\r\n for (const name of Object.keys(actions)) {\r\n publicStore[name] = (...args: unknown[]) => store.dispatch(name, ...args)\r\n }\r\n }\r\n\r\n // Exposer chaque computed\r\n if (computed) {\r\n for (const name of Object.keys(computed)) {\r\n Object.defineProperty(publicStore, name, {\r\n get: () => store.getComputed(name),\r\n enumerable: true,\r\n configurable: true\r\n })\r\n }\r\n }\r\n\r\n return publicStore\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// store.on() — réactions inter-stores\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function on<S extends object>(\r\n sourceAction: Function,\r\n handler: (state: S) => void | Promise<void>\r\n) {\r\n // Sera implémenté dans v0.2\r\n // après que le core soit stable\r\n console.warn('[Stato] store.on() disponible en v0.2')\r\n}","// ─────────────────────────────────────────────────────\r\n// TYPES PUBLICS DE @ngstato/core\r\n// ─────────────────────────────────────────────────────\r\n\r\n// Le state de base — tout sauf actions, computed, hooks\r\nexport type StateSlice<T> = Omit<T, 'actions' | 'computed' | 'hooks'>\r\n\r\n// Une action — sync ou async\r\nexport type Action<S> = (state: S, ...args: any[]) => void | Promise<void> | (() => void)\r\n\r\n// Map d'actions\r\nexport type ActionsMap<S> = Record<string, Action<S>>\r\n\r\n// Computed — dérivé du state local\r\nexport type ComputedFn<S> = (state: S) => unknown\r\n\r\n// Hooks lifecycle\r\nexport interface StatoHooks<S> {\r\n // Lifecycle du store\r\n onInit?: (store: S) => void | Promise<void>\r\n onDestroy?: (store: S) => void | Promise<void>\r\n\r\n // Lifecycle des actions\r\n onAction?: (name: string, args: unknown[]) => void\r\n onActionDone?: (name: string, duration: number) => void\r\n onError?: (error: Error, actionName: string) => void\r\n\r\n // Lifecycle du state\r\n onStateChange?: (prev: S, next: S) => void\r\n}\r\n\r\n// Configuration du store\r\nexport interface StatoStoreConfig<S extends object> {\r\n actions?: ActionsMap<StateSlice<S>>\r\n computed?: Record<string, ComputedFn<StateSlice<S>> | unknown[]>\r\n hooks?: StatoHooks<any>\r\n [key: string]: unknown\r\n}\r\n\r\n// Instance publique du store\r\nexport type StatoStoreInstance<S extends object> = {\r\n // readonly — on ne peut lire, jamais écrire directement\r\n readonly [K in keyof StateSlice<S>]: StateSlice<S>[K]\r\n} & {\r\n // Les actions sont exposées sans le paramètre state\r\n [K in keyof S as S[K] extends Function ? K : never]:\r\n S[K] extends (state: any, ...args: infer A) => infer R\r\n ? (...args: A) => R\r\n : never\r\n}\r\n\r\n// Configuration du client HTTP\r\nexport interface StatoConfig {\r\n baseUrl?: string\r\n timeout?: number\r\n headers?: Record<string, string>\r\n auth?: () => string | null | undefined\r\n}\r\n\r\n// Erreur HTTP\r\nexport class StatoHttpError extends Error {\r\n constructor(\r\n public status: number,\r\n public body: string\r\n ) {\r\n super(`HTTP ${status}: ${body}`)\r\n this.name = 'StatoHttpError'\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — StatoHttp\r\n// Client HTTP natif — fetch + baseUrl + auth + timeout\r\n// Zero dépendance — pas de HttpClient Angular\r\n// ─────────────────────────────────────────────────────\r\n\r\nimport type { StatoConfig } from './types'\r\nimport { StatoHttpError } from './types'\r\n\r\n// ─────────────────────────────────────────────────────\r\n// OPTIONS PAR REQUÊTE\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface RequestOptions {\r\n params?: Record<string, string | number | boolean>\r\n headers?: Record<string, string>\r\n signal?: AbortSignal // pour abortable()\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// CLASSE PRINCIPALE\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport class StatoHttp {\r\n\r\n private _config: StatoConfig\r\n\r\n constructor(config: StatoConfig = {}) {\r\n this._config = config\r\n }\r\n\r\n // ── GET ───────────────────────────────────────────\r\n get<T = unknown>(url: string, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('GET', url, undefined, options)\r\n }\r\n\r\n // ── POST ──────────────────────────────────────────\r\n post<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('POST', url, body, options)\r\n }\r\n\r\n // ── PUT ───────────────────────────────────────────\r\n put<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('PUT', url, body, options)\r\n }\r\n\r\n // ── PATCH ─────────────────────────────────────────\r\n patch<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('PATCH', url, body, options)\r\n }\r\n\r\n // ── DELETE ────────────────────────────────────────\r\n delete<T = unknown>(url: string, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('DELETE', url, undefined, options)\r\n }\r\n\r\n // ── MOTEUR INTERNE ────────────────────────────────\r\n private async _request<T>(\r\n method: string,\r\n url: string,\r\n body?: unknown,\r\n options?: RequestOptions\r\n ): Promise<T> {\r\n\r\n // 1. Construire l'URL complète avec baseUrl + params\r\n const fullUrl = this._buildUrl(url, options?.params)\r\n\r\n // 2. Récupérer le token auth si configuré\r\n const token = this._config.auth?.()\r\n\r\n // 3. Construire les headers\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n ...this._config.headers,\r\n ...options?.headers,\r\n ...(token ? { Authorization: `Bearer ${token}` } : {})\r\n }\r\n\r\n // 4. Configurer le timeout si défini\r\n let signal = options?.signal\r\n let timeoutId: ReturnType<typeof setTimeout> | undefined\r\n\r\n if (this._config.timeout && !signal) {\r\n const controller = new AbortController()\r\n signal = controller.signal\r\n timeoutId = setTimeout(\r\n () => controller.abort(),\r\n this._config.timeout\r\n )\r\n }\r\n\r\n // 5. Exécuter la requête\r\n try {\r\n const response = await fetch(fullUrl, {\r\n method,\r\n headers,\r\n signal,\r\n ...(body !== undefined\r\n ? { body: JSON.stringify(body) }\r\n : {}\r\n )\r\n })\r\n\r\n // 6. Gérer les erreurs HTTP automatiquement\r\n if (!response.ok) {\r\n const errorBody = await response.text()\r\n throw new StatoHttpError(response.status, errorBody)\r\n }\r\n\r\n // 7. Réponse vide — ex: DELETE 204\r\n const contentType = response.headers.get('content-type')\r\n if (\r\n response.status === 204 ||\r\n !contentType?.includes('application/json')\r\n ) {\r\n return undefined as T\r\n }\r\n\r\n // 8. Parser le JSON\r\n return response.json() as Promise<T>\r\n\r\n } finally {\r\n // Toujours nettoyer le timeout\r\n if (timeoutId) clearTimeout(timeoutId)\r\n }\r\n }\r\n\r\n // ── CONSTRUIRE L'URL AVEC PARAMS ──────────────────\r\n private _buildUrl(\r\n path: string,\r\n params?: Record<string, string | number | boolean>\r\n ): string {\r\n\r\n // Si l'URL est absolue — on ne préfixe pas baseUrl\r\n const url = path.startsWith('http')\r\n ? path\r\n : `${this._config.baseUrl ?? ''}${path}`\r\n\r\n // Ajouter les query params si présents\r\n if (!params || Object.keys(params).length === 0) return url\r\n\r\n const qs = new URLSearchParams(\r\n Object.entries(params).map(([k, v]) => [k, String(v)])\r\n ).toString()\r\n\r\n return `${url}?${qs}`\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// FACTORY FUNCTION — createHttp()\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function createHttp(config: StatoConfig = {}): StatoHttp {\r\n return new StatoHttp(config)\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// INSTANCE GLOBALE — http\r\n// Utilisée dans les actions des stores\r\n// Configurée via provideStato()\r\n// ─────────────────────────────────────────────────────\r\n\r\nlet _globalHttp: StatoHttp = new StatoHttp()\r\n\r\nexport function configureHttp(config: StatoConfig): void {\r\n _globalHttp = new StatoHttp(config)\r\n}\r\n\r\n// L'objet http — utilisé dans les actions\r\n// await http.get('/api/users')\r\nexport const http = {\r\n get: <T>(url: string, options?: RequestOptions) =>\r\n _globalHttp.get<T>(url, options),\r\n\r\n post: <T>(url: string, body?: unknown, options?: RequestOptions) =>\r\n _globalHttp.post<T>(url, body, options),\r\n\r\n put: <T>(url: string, body?: unknown, options?: RequestOptions) =>\r\n _globalHttp.put<T>(url, body, options),\r\n\r\n patch: <T>(url: string, body?: unknown, options?: RequestOptions) =>\r\n _globalHttp.patch<T>(url, body, options),\r\n\r\n delete: <T>(url: string, options?: RequestOptions) =>\r\n _globalHttp.delete<T>(url, options),\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — abortable()\r\n// Annule automatiquement la requête précédente\r\n// Remplace switchMap de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface AbortableOptions {\r\n signal: AbortSignal\r\n}\r\n\r\nexport function abortable<S, A extends unknown[]>(\r\n fn: (state: S, ...args: [...A, AbortableOptions]) => Promise<void>\r\n) {\r\n let controller: AbortController | null = null\r\n\r\n return async (state: S, ...args: A): Promise<void> => {\r\n // Annuler la requête précédente si elle tourne encore\r\n if (controller) {\r\n controller.abort()\r\n }\r\n\r\n // Créer un nouveau controller pour cette requête\r\n controller = new AbortController()\r\n const signal = controller.signal\r\n\r\n try {\r\n await fn(state, ...args, { signal } as any)\r\n } catch (error: any) {\r\n // Ignorer silencieusement les erreurs d'annulation\r\n if (error?.name === 'AbortError') return\r\n throw error\r\n } finally {\r\n controller = null\r\n }\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — debounced()\r\n// Attend que l'utilisateur arrête de taper\r\n// Remplace debounceTime de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function debounced<S, A extends unknown[]>(\r\n fn: (state: S, ...args: A) => void | Promise<void>,\r\n ms: number = 300\r\n) {\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n\r\n return (state: S, ...args: A): Promise<void> => {\r\n // Annuler le timer précédent\r\n if (timer) clearTimeout(timer)\r\n\r\n // Retourner une Promise qui se résout après le délai\r\n return new Promise((resolve, reject) => {\r\n timer = setTimeout(async () => {\r\n try {\r\n await fn(state, ...args)\r\n resolve()\r\n } catch (error) {\r\n reject(error)\r\n } finally {\r\n timer = null\r\n }\r\n }, ms)\r\n })\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — throttled()\r\n// Limite la fréquence d'exécution d'une action\r\n// Remplace throttleTime de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function throttled<S, A extends unknown[]>(\r\n fn: (state: S, ...args: A) => void | Promise<void>,\r\n ms: number = 300\r\n) {\r\n let lastCall = 0\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n\r\n return async (state: S, ...args: A): Promise<void> => {\r\n const now = Date.now()\r\n const remaining = ms - (now - lastCall)\r\n\r\n if (remaining <= 0) {\r\n // Assez de temps passé — on exécute immédiatement\r\n lastCall = now\r\n if (timer) {\r\n clearTimeout(timer)\r\n timer = null\r\n }\r\n await fn(state, ...args)\r\n } else {\r\n // Trop tôt — on planifie pour la fin du délai\r\n if (timer) clearTimeout(timer)\r\n return new Promise((resolve, reject) => {\r\n timer = setTimeout(async () => {\r\n lastCall = Date.now()\r\n timer = null\r\n try {\r\n await fn(state, ...args)\r\n resolve()\r\n } catch (error) {\r\n reject(error)\r\n }\r\n }, remaining)\r\n })\r\n }\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — retryable()\r\n// Réessaie automatiquement en cas d'échec\r\n// Remplace retryWhen de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface RetryOptions {\r\n attempts: number // nombre de tentatives\r\n backoff: 'fixed' | 'exponential' // stratégie de délai\r\n delay?: number // délai de base en ms (défaut 1000)\r\n onRetry?: (attempt: number, error: Error) => void // callback optionnel\r\n}\r\n\r\nexport function retryable<S, A extends unknown[]>(\r\n fn: (state: S, ...args: A) => Promise<void>,\r\n options: RetryOptions = {\r\n attempts: 3,\r\n backoff: 'exponential',\r\n delay: 1000\r\n }\r\n) {\r\n return async (state: S, ...args: A): Promise<void> => {\r\n const { attempts, backoff, delay = 1000, onRetry } = options\r\n\r\n for (let i = 0; i < attempts; i++) {\r\n try {\r\n await fn(state, ...args)\r\n return // succès — on sort immédiatement\r\n\r\n } catch (error) {\r\n const isLastAttempt = i === attempts - 1\r\n\r\n // Dernière tentative — on remonte l'erreur\r\n if (isLastAttempt) throw error\r\n\r\n // Calculer le délai avant la prochaine tentative\r\n const waitMs = backoff === 'exponential'\r\n ? delay * Math.pow(2, i) // 1s, 2s, 4s, 8s...\r\n : delay // fixe : toujours 1s\r\n\r\n // Callback optionnel — pour logger ou afficher un message\r\n onRetry?.(i + 1, error as Error)\r\n\r\n // Attendre avant de réessayer\r\n await new Promise(resolve => setTimeout(resolve, waitMs))\r\n }\r\n }\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — fromStream()\r\n// Pont entre un flux Observable/callback et le state\r\n// Pour : Firebase, Supabase, WebSocket, SSE\r\n// RxJS optionnel — pas obligatoire\r\n// ─────────────────────────────────────────────────────\r\n\r\n// Interface minimale d'un Observable\r\n// Compatible RxJS sans l'importer\r\nexport interface StatoObservable<T> {\r\n subscribe(observer: {\r\n next?: (value: T) => void\r\n error?: (error: unknown) => void\r\n complete?: () => void\r\n }): { unsubscribe(): void }\r\n}\r\n\r\nexport interface StreamOptions {\r\n // Appelé quand le stream se termine normalement\r\n onComplete?: () => void\r\n // Appelé quand le stream rencontre une erreur\r\n onError?: (error: unknown) => void\r\n}\r\n\r\nexport function fromStream<S, T>(\r\n // setupFn — retourne l'Observable ou le flux\r\n setupFn: (state: S) => StatoObservable<T>,\r\n // updateFn — appelé à chaque valeur émise\r\n updateFn: (state: S, value: T) => void,\r\n options?: StreamOptions\r\n) {\r\n return (state: S): (() => void) => {\r\n // Démarrer le flux\r\n const stream$ = setupFn(state)\r\n const subscription = stream$.subscribe({\r\n\r\n next: (value: T) => {\r\n // Mettre à jour le state à chaque émission\r\n updateFn(state, value)\r\n },\r\n\r\n error: (error: unknown) => {\r\n options?.onError?.(error)\r\n },\r\n\r\n complete: () => {\r\n options?.onComplete?.()\r\n }\r\n })\r\n\r\n // Retourner la fonction de cleanup\r\n // appelée automatiquement à la destruction du store\r\n return () => subscription.unsubscribe()\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — optimistic()\r\n// Mise à jour optimiste avec rollback automatique\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function optimistic<S, A extends unknown[]>(\r\n // Action immédiate — modifie le state sans attendre\r\n immediate: (state: S, ...args: A) => void,\r\n // Confirmation API — si elle échoue → rollback\r\n confirm: (state: S, ...args: A) => Promise<void>\r\n) {\r\n return async (state: S, ...args: A): Promise<void> => {\r\n // 1. Snapshot du state AVANT la modification\r\n const snapshot = { ...(state as object) } as S\r\n\r\n // 2. Appliquer la modification immédiatement\r\n immediate(state, ...args)\r\n\r\n try {\r\n // 3. Confirmer avec l'API\r\n await confirm(state, ...args)\r\n // Succès — le state optimiste est correct, rien à faire\r\n\r\n } catch (error) {\r\n // 4. Échec — restaurer le state d'avant\r\n Object.assign(state as object, snapshot)\r\n throw error\r\n }\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — DevTools\r\n// Logique pure — pas de dépendance Angular\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface ActionLog {\r\n id: number\r\n name: string\r\n args: unknown[]\r\n duration: number\r\n status: 'success' | 'error'\r\n error?: string\r\n prevState: unknown\r\n nextState: unknown\r\n at: string\r\n}\r\n\r\nexport interface DevToolsState {\r\n logs: ActionLog[]\r\n isOpen: boolean\r\n maxLogs: number\r\n}\r\n\r\nexport interface DevToolsInstance {\r\n state: DevToolsState\r\n logAction: (log: Omit<ActionLog, 'id' | 'at'>) => void\r\n clear: () => void\r\n open: () => void\r\n close: () => void\r\n toggle: () => void\r\n subscribe: (cb: (state: DevToolsState) => void) => () => void\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// FACTORY\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function createDevTools(maxLogs = 50): DevToolsInstance {\r\n let counter = 0\r\n\r\n const state: DevToolsState = {\r\n logs: [],\r\n isOpen: false,\r\n maxLogs\r\n }\r\n\r\n const listeners = new Set<(state: DevToolsState) => void>()\r\n\r\n function notify() {\r\n listeners.forEach(cb => cb({ ...state, logs: [...state.logs] }))\r\n }\r\n\r\n return {\r\n state,\r\n\r\n logAction(log) {\r\n const entry: ActionLog = {\r\n ...log,\r\n id: ++counter,\r\n at: new Date().toISOString()\r\n }\r\n\r\n state.logs = [entry, ...state.logs].slice(0, maxLogs)\r\n notify()\r\n },\r\n\r\n clear() {\r\n state.logs = []\r\n notify()\r\n },\r\n\r\n open() {\r\n state.isOpen = true\r\n notify()\r\n },\r\n\r\n close() {\r\n state.isOpen = false\r\n notify()\r\n },\r\n\r\n toggle() {\r\n state.isOpen = !state.isOpen\r\n notify()\r\n },\r\n\r\n subscribe(cb) {\r\n listeners.add(cb)\r\n return () => listeners.delete(cb)\r\n }\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// INSTANCE GLOBALE — singleton partagé entre tous les stores\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport const devTools = createDevTools()\r\n\r\n// ─────────────────────────────────────────────────────\r\n// PLUGIN — connecte un store aux DevTools\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function connectDevTools(store: any, storeName: string) {\r\n if (!devTools) return\r\n\r\n let prevState: any = {}\r\n\r\n // Accès aux hooks via __store__\r\n const internalStore = store.__store__\r\n\r\n if (!internalStore) return\r\n\r\n // Sauvegarder les hooks existants\r\n const existingHooks = { ...internalStore['_hooks'] }\r\n\r\n // Remplacer les hooks\r\n internalStore['_hooks'] = {\r\n ...existingHooks,\r\n\r\n onAction(name: string, args: unknown[]) {\r\n prevState = store.getState()\r\n existingHooks.onAction?.(name, args)\r\n },\r\n\r\n onActionDone(name: string, duration: number) {\r\n const nextState = store.getState()\r\n devTools.logAction({\r\n name: `[${storeName}] ${name}`,\r\n args: [],\r\n duration,\r\n status: 'success',\r\n prevState: { ...prevState },\r\n nextState: { ...nextState }\r\n })\r\n existingHooks.onActionDone?.(name, duration)\r\n },\r\n\r\n onError(error: Error, actionName: string) {\r\n devTools.logAction({\r\n name: `[${storeName}] ${actionName}`,\r\n args: [],\r\n duration: 0,\r\n status: 'error',\r\n error: error.message,\r\n prevState: { ...prevState },\r\n nextState: { ...prevState }\r\n })\r\n existingHooks.onError?.(error, actionName)\r\n },\r\n\r\n onStateChange: existingHooks.onStateChange\r\n }\r\n}"]}
|
|
1
|
+
{"version":3,"sources":["../src/store.ts","../src/types.ts","../src/http.ts","../src/helpers/abortable.ts","../src/helpers/debounced.ts","../src/helpers/throttled.ts","../src/helpers/retryable.ts","../src/helpers/from-stream.ts","../src/helpers/optimistic.ts","../src/helpers/with-persist.ts","../src/devtools.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["// ─────────────────────────────────────────────────────\r\n// @ngstato/core — createStore()\r\n// Le moteur principal de Stato\r\n// ─────────────────────────────────────────────────────\r\n\r\nimport type {\r\n StatoStoreConfig,\r\n StatoHooks,\r\n StateSlice,\r\n EffectEntry\r\n} from './types'\r\n\r\n// ─────────────────────────────────────────────────────\r\n// CLASSE INTERNE — jamais exposée directement\r\n// ─────────────────────────────────────────────────────\r\n\r\nclass StatoStore<S extends object> {\r\n\r\n // Le state interne — jamais accessible directement\r\n private _state: StateSlice<S>\r\n\r\n // Les abonnés — notifiés à chaque changement\r\n private _subscribers: Set<(state: StateSlice<S>) => void> = new Set()\r\n\r\n // Les actions enregistrées\r\n private _actions: Record<string, Function> = {}\r\n\r\n // Les computed enregistrés\r\n private _computed: Record<string, () => unknown> = {}\r\n private _selectors: Record<string, () => unknown> = {}\r\n\r\n // Les cleanups à appeler à la destruction\r\n private _cleanups: Array<() => void> = []\r\n\r\n // Les hooks lifecycle\r\n private _hooks: StatoHooks<any>\r\n private _publicStore: any = null\r\n private _effects: Array<{\r\n deps: (state: StateSlice<S>) => unknown | unknown[]\r\n run: Function\r\n prevDeps?: unknown[]\r\n hasRun: boolean\r\n cleanup?: () => void\r\n running: boolean\r\n rerunRequested: boolean\r\n }> = []\r\n\r\n private _createMemoizedSelector(fn: Function): () => unknown {\r\n let initialized = false\r\n let cachedResult: unknown\r\n let trackedKeys: string[] = []\r\n let trackedValues: unknown[] = []\r\n\r\n return () => {\r\n if (initialized && trackedKeys.length) {\r\n const unchanged = trackedKeys.every((key, index) =>\r\n Object.is((this._state as any)[key], trackedValues[index])\r\n )\r\n if (unchanged) return cachedResult\r\n }\r\n\r\n const reads = new Set<string>()\r\n const trackingState = new Proxy(this._state as any, {\r\n get: (target, prop, receiver) => {\r\n if (typeof prop === 'string' && prop in target) {\r\n reads.add(prop)\r\n }\r\n return Reflect.get(target, prop, receiver)\r\n }\r\n })\r\n\r\n const result = fn(trackingState)\r\n\r\n trackedKeys = Array.from(reads)\r\n trackedValues = trackedKeys.map((key) => (this._state as any)[key])\r\n cachedResult = result\r\n initialized = true\r\n\r\n return result\r\n }\r\n }\r\n\r\n constructor(config: StatoStoreConfig<S>) {\r\n // 1. Extraire le state initial — tout sauf actions/computed/hooks\r\n const { actions, computed, selectors, effects, hooks, ...initialState } = config\r\n this._state = initialState as StateSlice<S>\r\n this._hooks = hooks ?? {}\r\n\r\n // 2. Enregistrer les actions\r\n if (actions) {\r\n for (const [name, fn] of Object.entries(actions)) {\r\n this._actions[name] = fn\r\n }\r\n }\r\n\r\n // 3. Enregistrer les computed\r\n if (computed) {\r\n for (const [name, fn] of Object.entries(computed)) {\r\n if (typeof fn === 'function') {\r\n this._computed[name] = () => (fn as Function)(this._state)\r\n }\r\n }\r\n }\r\n\r\n // 4. Enregistrer les selectors memoïzés\r\n if (selectors) {\r\n for (const [name, fn] of Object.entries(selectors)) {\r\n if (typeof fn === 'function') {\r\n this._selectors[name] = this._createMemoizedSelector(fn as Function)\r\n }\r\n }\r\n }\r\n\r\n if (effects) {\r\n for (const entry of effects) {\r\n const [deps, run] = entry as EffectEntry<StateSlice<S>>\r\n if (typeof deps === 'function' && typeof run === 'function') {\r\n this._effects.push({\r\n deps,\r\n run,\r\n hasRun: false,\r\n running: false,\r\n rerunRequested: false\r\n })\r\n }\r\n }\r\n }\r\n }\r\n\r\n // ── Lire le state ──────────────────────────────────\r\n getState(): Readonly<StateSlice<S>> {\r\n return { ...this._state }\r\n }\r\n\r\n // ── Modifier le state — usage interne uniquement ───\r\n private _setState(partial: Partial<StateSlice<S>>) {\r\n // Copie immutable — on ne modifie jamais l'objet original\r\n this._state = { ...this._state, ...partial }\r\n this._runEffects()\r\n this._notify()\r\n }\r\n\r\n private _normalizeDeps(value: unknown | unknown[]): unknown[] {\r\n return Array.isArray(value) ? value : [value]\r\n }\r\n\r\n private _depsChanged(prev: unknown[] | undefined, next: unknown[]): boolean {\r\n if (!prev) return true\r\n if (prev.length !== next.length) return true\r\n for (let i = 0; i < next.length; i++) {\r\n if (!Object.is(prev[i], next[i])) return true\r\n }\r\n return false\r\n }\r\n\r\n private _runEffects(force = false) {\r\n for (const effect of this._effects) {\r\n const depsValue = effect.deps(this._state)\r\n const depsArray = this._normalizeDeps(depsValue)\r\n const shouldRun = force || this._depsChanged(effect.prevDeps, depsArray)\r\n if (!shouldRun) continue\r\n\r\n const execute = async () => {\r\n if (effect.running) {\r\n effect.rerunRequested = true\r\n return\r\n }\r\n\r\n effect.running = true\r\n effect.rerunRequested = false\r\n const prevDepsValue = effect.prevDeps\r\n effect.prevDeps = depsArray\r\n\r\n try {\r\n effect.cleanup?.()\r\n const maybeCleanup = await effect.run(depsValue, {\r\n state: { ...this._state },\r\n store: this._publicStore,\r\n prevDepsValue\r\n })\r\n effect.cleanup = typeof maybeCleanup === 'function' ? maybeCleanup : undefined\r\n effect.hasRun = true\r\n } catch (error) {\r\n this._hooks.onError?.(error as Error, 'effect')\r\n } finally {\r\n effect.running = false\r\n if (effect.rerunRequested) {\r\n this._runEffects()\r\n }\r\n }\r\n }\r\n\r\n void execute()\r\n }\r\n }\r\n\r\n // ── Notifier tous les abonnés ──────────────────────\r\n private _notify() {\r\n for (const subscriber of this._subscribers) {\r\n subscriber({ ...this._state })\r\n }\r\n }\r\n\r\n // ── S'abonner aux changements ──────────────────────\r\n subscribe(fn: (state: StateSlice<S>) => void): () => void {\r\n this._subscribers.add(fn)\r\n // Retourne une fonction de désabonnement\r\n return () => this._subscribers.delete(fn)\r\n }\r\n\r\n // ── Exécuter une action ────────────────────────────\r\nasync dispatch(actionName: string, ...args: unknown[]) {\r\n const action = this._actions[actionName]\r\n if (!action) {\r\n throw new Error(`[Stato] Action \"${actionName}\" introuvable`)\r\n }\r\n\r\n // Hook onAction — avant l'exécution\r\n this._hooks.onAction?.(actionName, args)\r\n\r\n const start = Date.now()\r\n const prevState = { ...this._state }\r\n\r\n const stateProxy = new Proxy({ ...this._state } as any, {\r\n set: (target, key, value) => {\r\n target[key] = value\r\n this._setState({ [key]: value } as any)\r\n return true\r\n }\r\n })\r\n\r\n try {\r\n await action(stateProxy, ...args)\r\n\r\n // Hook onActionDone — après l'exécution\r\n this._hooks.onActionDone?.(actionName, Date.now() - start)\r\n\r\n // Hook onStateChange — si le state a changé\r\n this._hooks.onStateChange?.(prevState as any, { ...this._state } as any)\r\n\r\n } catch (error) {\r\n // Hook onError — si une erreur est lancée\r\n this._hooks.onError?.(error as Error, actionName)\r\n throw error // on remonte l'erreur quand même\r\n }\r\n}\r\n\r\n // ── Lire une valeur computed ───────────────────────\r\n getComputed(name: string): unknown {\r\n const fn = this._computed[name]\r\n if (!fn) throw new Error(`[Stato] Computed \"${name}\" introuvable`)\r\n return fn()\r\n }\r\n\r\n getSelector(name: string): unknown {\r\n const fn = this._selectors[name]\r\n if (!fn) throw new Error(`[Stato] Selector \"${name}\" introuvable`)\r\n return fn()\r\n }\r\n\r\n // ── Enregistrer un cleanup (pour fromStream) ───────\r\n registerCleanup(fn: () => void) {\r\n this._cleanups.push(fn)\r\n }\r\n\r\n hydrate(partial: Partial<StateSlice<S>>) {\r\n this._setState(partial)\r\n }\r\n\r\n setPublicStore(publicStore: any) {\r\n this._publicStore = publicStore\r\n this._runEffects(true)\r\n }\r\n\r\n // ── Lifecycle — appelé par l'adaptateur Angular ────\r\n init(publicStore: any) {\r\n this._publicStore = publicStore\r\n this._hooks.onInit?.(publicStore)\r\n this._runEffects(true)\r\n }\r\n\r\n destroy(publicStore: any) {\r\n this._hooks.onDestroy?.(publicStore)\r\n for (const effect of this._effects) {\r\n effect.cleanup?.()\r\n effect.cleanup = undefined\r\n }\r\n // Nettoyer tous les streams ouverts\r\n for (const cleanup of this._cleanups) {\r\n cleanup()\r\n }\r\n this._cleanups = []\r\n this._subscribers.clear()\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// FONCTION PUBLIQUE — createStore()\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function createStore<S extends object>(config: S & StatoStoreConfig<S>) {\r\n\r\n // Créer l'instance interne\r\n const store = new StatoStore<S>(config as StatoStoreConfig<S>)\r\n\r\n // Construire l'objet public\r\n // Les propriétés du state sont accessibles directement\r\n // Les actions sont exposées sans le paramètre state\r\n const publicStore: any = {\r\n // Accès au store interne — pour les adaptateurs Angular/React/Vue\r\n __store__: store,\r\n\r\n // S'abonner aux changements\r\n subscribe: store.subscribe.bind(store),\r\n\r\n // Lire le state complet\r\n getState: store.getState.bind(store),\r\n\r\n // Enregistrer un cleanup\r\n registerCleanup: store.registerCleanup.bind(store),\r\n }\r\n\r\n // Exposer chaque propriété du state\r\n const initialState = store.getState()\r\n for (const key of Object.keys(initialState as object)) {\r\n Object.defineProperty(publicStore, key, {\r\n get: () => store.getState()[key as keyof typeof initialState],\r\n enumerable: true,\r\n configurable: true\r\n })\r\n }\r\n\r\n // Exposer chaque action\r\n const { actions, computed, selectors } = config as StatoStoreConfig<S>\r\n\r\n if (actions) {\r\n for (const name of Object.keys(actions)) {\r\n publicStore[name] = (...args: unknown[]) => store.dispatch(name, ...args)\r\n }\r\n }\r\n\r\n // Exposer chaque computed\r\n if (computed) {\r\n for (const name of Object.keys(computed)) {\r\n Object.defineProperty(publicStore, name, {\r\n get: () => store.getComputed(name),\r\n enumerable: true,\r\n configurable: true\r\n })\r\n }\r\n }\r\n\r\n if (selectors) {\r\n for (const name of Object.keys(selectors)) {\r\n Object.defineProperty(publicStore, name, {\r\n get: () => store.getSelector(name),\r\n enumerable: true,\r\n configurable: true\r\n })\r\n }\r\n }\r\n\r\n store.setPublicStore(publicStore)\r\n\r\n return publicStore\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// store.on() — réactions inter-stores\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function on<S extends object>(\r\n sourceAction: Function,\r\n handler: (state: S) => void | Promise<void>\r\n) {\r\n // Sera implémenté dans v0.2\r\n // après que le core soit stable\r\n console.warn('[Stato] store.on() disponible en v0.2')\r\n}","// ─────────────────────────────────────────────────────\r\n// TYPES PUBLICS DE @ngstato/core\r\n// ─────────────────────────────────────────────────────\r\n\r\n// Le state de base — tout sauf actions/computed/selectors/hooks\r\nexport type StateSlice<T> = Omit<T, 'actions' | 'computed' | 'selectors' | 'hooks'>\r\n\r\n// Une action — sync ou async\r\nexport type Action<S> = (state: S, ...args: any[]) => void | Promise<void> | (() => void)\r\n\r\n// Map d'actions\r\nexport type ActionsMap<S> = Record<string, Action<S>>\r\n\r\n// Computed — dérivé du state local\r\nexport type ComputedFn<S> = (state: S) => unknown\r\nexport type SelectorFn<S> = (state: S) => unknown\r\nexport type EffectDepsFn<S> = (state: S) => unknown | unknown[]\r\nexport type EffectCleanup = void | (() => void)\r\nexport type EffectRunner<S> = (\r\n depsValue: unknown | unknown[],\r\n ctx: { state: Readonly<S>; store: any; prevDepsValue?: unknown | unknown[] }\r\n) => EffectCleanup | Promise<EffectCleanup>\r\nexport type EffectEntry<S> = [EffectDepsFn<S>, EffectRunner<S>]\r\n\r\n// Hooks lifecycle\r\nexport interface StatoHooks<S> {\r\n // Lifecycle du store\r\n onInit?: (store: S) => void | Promise<void>\r\n onDestroy?: (store: S) => void | Promise<void>\r\n\r\n // Lifecycle des actions\r\n onAction?: (name: string, args: unknown[]) => void\r\n onActionDone?: (name: string, duration: number) => void\r\n onError?: (error: Error, actionName: string) => void\r\n\r\n // Lifecycle du state\r\n onStateChange?: (prev: S, next: S) => void\r\n}\r\n\r\n// Configuration du store\r\nexport interface StatoStoreConfig<S extends object> {\r\n actions?: ActionsMap<StateSlice<S>>\r\n computed?: Record<string, ComputedFn<StateSlice<S>> | unknown[]>\r\n selectors?: Record<string, SelectorFn<StateSlice<S>> | unknown[]>\r\n effects?: EffectEntry<StateSlice<S>>[]\r\n hooks?: StatoHooks<any>\r\n [key: string]: unknown\r\n}\r\n\r\n// Instance publique du store\r\nexport type StatoStoreInstance<S extends object> = {\r\n // readonly — on ne peut lire, jamais écrire directement\r\n readonly [K in keyof StateSlice<S>]: StateSlice<S>[K]\r\n} & {\r\n // Les actions sont exposées sans le paramètre state\r\n [K in keyof S as S[K] extends Function ? K : never]:\r\n S[K] extends (state: any, ...args: infer A) => infer R\r\n ? (...args: A) => R\r\n : never\r\n}\r\n\r\n// Configuration du client HTTP\r\nexport interface StatoConfig {\r\n baseUrl?: string\r\n timeout?: number\r\n headers?: Record<string, string>\r\n auth?: () => string | null | undefined\r\n}\r\n\r\n// Erreur HTTP\r\nexport class StatoHttpError extends Error {\r\n constructor(\r\n public status: number,\r\n public body: string\r\n ) {\r\n super(`HTTP ${status}: ${body}`)\r\n this.name = 'StatoHttpError'\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — StatoHttp\r\n// Client HTTP natif — fetch + baseUrl + auth + timeout\r\n// Zero dépendance — pas de HttpClient Angular\r\n// ─────────────────────────────────────────────────────\r\n\r\nimport type { StatoConfig } from './types'\r\nimport { StatoHttpError } from './types'\r\n\r\n// ─────────────────────────────────────────────────────\r\n// OPTIONS PAR REQUÊTE\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface RequestOptions {\r\n params?: Record<string, string | number | boolean>\r\n headers?: Record<string, string>\r\n signal?: AbortSignal // pour abortable()\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// CLASSE PRINCIPALE\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport class StatoHttp {\r\n\r\n private _config: StatoConfig\r\n\r\n constructor(config: StatoConfig = {}) {\r\n this._config = config\r\n }\r\n\r\n // ── GET ───────────────────────────────────────────\r\n get<T = unknown>(url: string, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('GET', url, undefined, options)\r\n }\r\n\r\n // ── POST ──────────────────────────────────────────\r\n post<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('POST', url, body, options)\r\n }\r\n\r\n // ── PUT ───────────────────────────────────────────\r\n put<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('PUT', url, body, options)\r\n }\r\n\r\n // ── PATCH ─────────────────────────────────────────\r\n patch<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('PATCH', url, body, options)\r\n }\r\n\r\n // ── DELETE ────────────────────────────────────────\r\n delete<T = unknown>(url: string, options?: RequestOptions): Promise<T> {\r\n return this._request<T>('DELETE', url, undefined, options)\r\n }\r\n\r\n // ── MOTEUR INTERNE ────────────────────────────────\r\n private async _request<T>(\r\n method: string,\r\n url: string,\r\n body?: unknown,\r\n options?: RequestOptions\r\n ): Promise<T> {\r\n\r\n // 1. Construire l'URL complète avec baseUrl + params\r\n const fullUrl = this._buildUrl(url, options?.params)\r\n\r\n // 2. Récupérer le token auth si configuré\r\n const token = this._config.auth?.()\r\n\r\n // 3. Construire les headers\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n ...this._config.headers,\r\n ...options?.headers,\r\n ...(token ? { Authorization: `Bearer ${token}` } : {})\r\n }\r\n\r\n // 4. Configurer le timeout si défini\r\n let signal = options?.signal\r\n let timeoutId: ReturnType<typeof setTimeout> | undefined\r\n\r\n if (this._config.timeout && !signal) {\r\n const controller = new AbortController()\r\n signal = controller.signal\r\n timeoutId = setTimeout(\r\n () => controller.abort(),\r\n this._config.timeout\r\n )\r\n }\r\n\r\n // 5. Exécuter la requête\r\n try {\r\n const response = await fetch(fullUrl, {\r\n method,\r\n headers,\r\n signal,\r\n ...(body !== undefined\r\n ? { body: JSON.stringify(body) }\r\n : {}\r\n )\r\n })\r\n\r\n // 6. Gérer les erreurs HTTP automatiquement\r\n if (!response.ok) {\r\n const errorBody = await response.text()\r\n throw new StatoHttpError(response.status, errorBody)\r\n }\r\n\r\n // 7. Réponse vide — ex: DELETE 204\r\n const contentType = response.headers.get('content-type')\r\n if (\r\n response.status === 204 ||\r\n !contentType?.includes('application/json')\r\n ) {\r\n return undefined as T\r\n }\r\n\r\n // 8. Parser le JSON\r\n return response.json() as Promise<T>\r\n\r\n } finally {\r\n // Toujours nettoyer le timeout\r\n if (timeoutId) clearTimeout(timeoutId)\r\n }\r\n }\r\n\r\n // ── CONSTRUIRE L'URL AVEC PARAMS ──────────────────\r\n private _buildUrl(\r\n path: string,\r\n params?: Record<string, string | number | boolean>\r\n ): string {\r\n\r\n // Si l'URL est absolue — on ne préfixe pas baseUrl\r\n const url = path.startsWith('http')\r\n ? path\r\n : `${this._config.baseUrl ?? ''}${path}`\r\n\r\n // Ajouter les query params si présents\r\n if (!params || Object.keys(params).length === 0) return url\r\n\r\n const qs = new URLSearchParams(\r\n Object.entries(params).map(([k, v]) => [k, String(v)])\r\n ).toString()\r\n\r\n return `${url}?${qs}`\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// FACTORY FUNCTION — createHttp()\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function createHttp(config: StatoConfig = {}): StatoHttp {\r\n return new StatoHttp(config)\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// INSTANCE GLOBALE — http\r\n// Utilisée dans les actions des stores\r\n// Configurée via provideStato()\r\n// ─────────────────────────────────────────────────────\r\n\r\nlet _globalHttp: StatoHttp = new StatoHttp()\r\n\r\nexport function configureHttp(config: StatoConfig): void {\r\n _globalHttp = new StatoHttp(config)\r\n}\r\n\r\n// L'objet http — utilisé dans les actions\r\n// await http.get('/api/users')\r\nexport const http = {\r\n get: <T>(url: string, options?: RequestOptions) =>\r\n _globalHttp.get<T>(url, options),\r\n\r\n post: <T>(url: string, body?: unknown, options?: RequestOptions) =>\r\n _globalHttp.post<T>(url, body, options),\r\n\r\n put: <T>(url: string, body?: unknown, options?: RequestOptions) =>\r\n _globalHttp.put<T>(url, body, options),\r\n\r\n patch: <T>(url: string, body?: unknown, options?: RequestOptions) =>\r\n _globalHttp.patch<T>(url, body, options),\r\n\r\n delete: <T>(url: string, options?: RequestOptions) =>\r\n _globalHttp.delete<T>(url, options),\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — abortable()\r\n// Annule automatiquement la requête précédente\r\n// Remplace switchMap de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface AbortableOptions {\r\n signal: AbortSignal\r\n}\r\n\r\nexport function abortable<S, A extends unknown[]>(\r\n fn: (state: S, ...args: [...A, AbortableOptions]) => Promise<void>\r\n) {\r\n let controller: AbortController | null = null\r\n\r\n return async (state: S, ...args: A): Promise<void> => {\r\n // Annuler la requête précédente si elle tourne encore\r\n if (controller) {\r\n controller.abort()\r\n }\r\n\r\n // Créer un nouveau controller pour cette requête\r\n controller = new AbortController()\r\n const signal = controller.signal\r\n\r\n try {\r\n await fn(state, ...args, { signal } as any)\r\n } catch (error: any) {\r\n // Ignorer silencieusement les erreurs d'annulation\r\n if (error?.name === 'AbortError') return\r\n throw error\r\n } finally {\r\n controller = null\r\n }\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — debounced()\r\n// Attend que l'utilisateur arrête de taper\r\n// Remplace debounceTime de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function debounced<S, A extends unknown[]>(\r\n fn: (state: S, ...args: A) => void | Promise<void>,\r\n ms: number = 300\r\n) {\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n\r\n return (state: S, ...args: A): Promise<void> => {\r\n // Annuler le timer précédent\r\n if (timer) clearTimeout(timer)\r\n\r\n // Retourner une Promise qui se résout après le délai\r\n return new Promise((resolve, reject) => {\r\n timer = setTimeout(async () => {\r\n try {\r\n await fn(state, ...args)\r\n resolve()\r\n } catch (error) {\r\n reject(error)\r\n } finally {\r\n timer = null\r\n }\r\n }, ms)\r\n })\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — throttled()\r\n// Limite la fréquence d'exécution d'une action\r\n// Remplace throttleTime de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function throttled<S, A extends unknown[]>(\r\n fn: (state: S, ...args: A) => void | Promise<void>,\r\n ms: number = 300\r\n) {\r\n let lastCall = 0\r\n let timer: ReturnType<typeof setTimeout> | null = null\r\n\r\n return async (state: S, ...args: A): Promise<void> => {\r\n const now = Date.now()\r\n const remaining = ms - (now - lastCall)\r\n\r\n if (remaining <= 0) {\r\n // Assez de temps passé — on exécute immédiatement\r\n lastCall = now\r\n if (timer) {\r\n clearTimeout(timer)\r\n timer = null\r\n }\r\n await fn(state, ...args)\r\n } else {\r\n // Trop tôt — on planifie pour la fin du délai\r\n if (timer) clearTimeout(timer)\r\n return new Promise((resolve, reject) => {\r\n timer = setTimeout(async () => {\r\n lastCall = Date.now()\r\n timer = null\r\n try {\r\n await fn(state, ...args)\r\n resolve()\r\n } catch (error) {\r\n reject(error)\r\n }\r\n }, remaining)\r\n })\r\n }\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — retryable()\r\n// Réessaie automatiquement en cas d'échec\r\n// Remplace retryWhen de RxJS — sans RxJS\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface RetryOptions {\r\n attempts: number // nombre de tentatives\r\n backoff: 'fixed' | 'exponential' // stratégie de délai\r\n delay?: number // délai de base en ms (défaut 1000)\r\n onRetry?: (attempt: number, error: Error) => void // callback optionnel\r\n}\r\n\r\nexport function retryable<S, A extends unknown[]>(\r\n fn: (state: S, ...args: A) => Promise<void>,\r\n options: RetryOptions = {\r\n attempts: 3,\r\n backoff: 'exponential',\r\n delay: 1000\r\n }\r\n) {\r\n return async (state: S, ...args: A): Promise<void> => {\r\n const { attempts, backoff, delay = 1000, onRetry } = options\r\n\r\n for (let i = 0; i < attempts; i++) {\r\n try {\r\n await fn(state, ...args)\r\n return // succès — on sort immédiatement\r\n\r\n } catch (error) {\r\n const isLastAttempt = i === attempts - 1\r\n\r\n // Dernière tentative — on remonte l'erreur\r\n if (isLastAttempt) throw error\r\n\r\n // Calculer le délai avant la prochaine tentative\r\n const waitMs = backoff === 'exponential'\r\n ? delay * Math.pow(2, i) // 1s, 2s, 4s, 8s...\r\n : delay // fixe : toujours 1s\r\n\r\n // Callback optionnel — pour logger ou afficher un message\r\n onRetry?.(i + 1, error as Error)\r\n\r\n // Attendre avant de réessayer\r\n await new Promise(resolve => setTimeout(resolve, waitMs))\r\n }\r\n }\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — fromStream()\r\n// Pont entre un flux Observable/callback et le state\r\n// Pour : Firebase, Supabase, WebSocket, SSE\r\n// RxJS optionnel — pas obligatoire\r\n// ─────────────────────────────────────────────────────\r\n\r\n// Interface minimale d'un Observable\r\n// Compatible RxJS sans l'importer\r\nexport interface StatoObservable<T> {\r\n subscribe(observer: {\r\n next?: (value: T) => void\r\n error?: (error: unknown) => void\r\n complete?: () => void\r\n }): { unsubscribe(): void }\r\n}\r\n\r\nexport interface StreamOptions {\r\n // Appelé quand le stream se termine normalement\r\n onComplete?: () => void\r\n // Appelé quand le stream rencontre une erreur\r\n onError?: (error: unknown) => void\r\n}\r\n\r\nexport function fromStream<S, T>(\r\n // setupFn — retourne l'Observable ou le flux\r\n setupFn: (state: S) => StatoObservable<T>,\r\n // updateFn — appelé à chaque valeur émise\r\n updateFn: (state: S, value: T) => void,\r\n options?: StreamOptions\r\n) {\r\n return (state: S): (() => void) => {\r\n // Démarrer le flux\r\n const stream$ = setupFn(state)\r\n const subscription = stream$.subscribe({\r\n\r\n next: (value: T) => {\r\n // Mettre à jour le state à chaque émission\r\n updateFn(state, value)\r\n },\r\n\r\n error: (error: unknown) => {\r\n options?.onError?.(error)\r\n },\r\n\r\n complete: () => {\r\n options?.onComplete?.()\r\n }\r\n })\r\n\r\n // Retourner la fonction de cleanup\r\n // appelée automatiquement à la destruction du store\r\n return () => subscription.unsubscribe()\r\n }\r\n}","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — optimistic()\r\n// Mise à jour optimiste avec rollback automatique\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function optimistic<S, A extends unknown[]>(\r\n // Action immédiate — modifie le state sans attendre\r\n immediate: (state: S, ...args: A) => void,\r\n // Confirmation API — si elle échoue → rollback\r\n confirm: (state: S, ...args: A) => Promise<void>\r\n) {\r\n return async (state: S, ...args: A): Promise<void> => {\r\n // 1. Snapshot du state AVANT la modification\r\n const snapshot = { ...(state as object) } as S\r\n\r\n // 2. Appliquer la modification immédiatement\r\n immediate(state, ...args)\r\n\r\n try {\r\n // 3. Confirmer avec l'API\r\n await confirm(state, ...args)\r\n // Succès — le state optimiste est correct, rien à faire\r\n\r\n } catch (error) {\r\n // 4. Échec — restaurer le state d'avant\r\n Object.assign(state as object, snapshot)\r\n throw error\r\n }\r\n }\r\n}","import type { StateSlice, StatoStoreConfig, StatoHooks } from '../types'\n\nexport interface PersistStorage {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n removeItem(key: string): void\n}\n\nexport interface PersistEnvelope<T> {\n v: number\n data: Partial<T>\n}\n\nexport interface PersistOptions<S extends object> {\n key: string\n version?: number\n storage?: PersistStorage\n pick?: (keyof S)[]\n migrate?: (data: unknown, fromVersion: number) => Partial<S>\n onError?: (error: Error) => void\n}\n\nfunction resolveStorage(custom?: PersistStorage): PersistStorage | null {\n if (custom) return custom\n if (typeof window === 'undefined') return null\n try {\n return window.localStorage\n } catch {\n return null\n }\n}\n\nfunction pickState<S extends object>(state: Partial<S>, keys?: (keyof S)[]) {\n if (!keys?.length) return state\n const picked: Partial<S> = {}\n for (const key of keys) {\n picked[key] = state[key]\n }\n return picked\n}\n\nexport function withPersist<S extends object>(\n config: S & StatoStoreConfig<S>,\n options: PersistOptions<StateSlice<S>>\n): S & StatoStoreConfig<S> {\n const {\n key,\n version = 1,\n storage: customStorage,\n pick,\n migrate,\n onError\n } = options\n\n const storage = resolveStorage(customStorage)\n const userHooks = config.hooks ?? {}\n\n const mergedHooks: StatoHooks<any> = {\n ...userHooks,\n onInit(store: any) {\n try {\n if (!storage) return userHooks.onInit?.(store)\n const raw = storage.getItem(key)\n if (!raw) return userHooks.onInit?.(store)\n\n const parsed = JSON.parse(raw) as PersistEnvelope<StateSlice<S>>\n const data =\n parsed.v === version\n ? parsed.data\n : migrate\n ? migrate(parsed.data, parsed.v)\n : parsed.data\n\n if (data && typeof data === 'object') {\n store.__store__?.hydrate?.(data)\n }\n } catch (error) {\n onError?.(error as Error)\n }\n return userHooks.onInit?.(store)\n },\n\n onStateChange(prev: any, next: any) {\n try {\n if (storage) {\n const payload: PersistEnvelope<StateSlice<S>> = {\n v: version,\n data: pickState(next, pick as (keyof StateSlice<S>)[] | undefined)\n }\n storage.setItem(key, JSON.stringify(payload))\n }\n } catch (error) {\n onError?.(error as Error)\n }\n userHooks.onStateChange?.(prev, next)\n },\n\n onDestroy(store: any) {\n return userHooks.onDestroy?.(store)\n },\n onAction(name: string, args: unknown[]) {\n return userHooks.onAction?.(name, args)\n },\n onActionDone(name: string, duration: number) {\n return userHooks.onActionDone?.(name, duration)\n },\n onError(error: Error, actionName: string) {\n return userHooks.onError?.(error, actionName)\n }\n }\n\n return {\n ...config,\n hooks: mergedHooks\n }\n}\n\n","// ─────────────────────────────────────────────────────\r\n// @ngstato/core — DevTools\r\n// Logique pure — pas de dépendance Angular\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport interface ActionLog {\r\n id: number\r\n name: string\r\n args: unknown[]\r\n duration: number\r\n status: 'success' | 'error'\r\n error?: string\r\n prevState: unknown\r\n nextState: unknown\r\n at: string\r\n}\r\n\r\nexport interface DevToolsState {\r\n logs: ActionLog[]\r\n isOpen: boolean\r\n maxLogs: number\r\n}\r\n\r\nexport interface DevToolsInstance {\r\n state: DevToolsState\r\n logAction: (log: Omit<ActionLog, 'id' | 'at'>) => void\r\n clear: () => void\r\n open: () => void\r\n close: () => void\r\n toggle: () => void\r\n subscribe: (cb: (state: DevToolsState) => void) => () => void\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// FACTORY\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function createDevTools(maxLogs = 50): DevToolsInstance {\r\n let counter = 0\r\n\r\n const state: DevToolsState = {\r\n logs: [],\r\n isOpen: false,\r\n maxLogs\r\n }\r\n\r\n const listeners = new Set<(state: DevToolsState) => void>()\r\n\r\n function notify() {\r\n listeners.forEach(cb => cb({ ...state, logs: [...state.logs] }))\r\n }\r\n\r\n return {\r\n state,\r\n\r\n logAction(log) {\r\n const entry: ActionLog = {\r\n ...log,\r\n id: ++counter,\r\n at: new Date().toISOString()\r\n }\r\n\r\n state.logs = [entry, ...state.logs].slice(0, maxLogs)\r\n notify()\r\n },\r\n\r\n clear() {\r\n state.logs = []\r\n notify()\r\n },\r\n\r\n open() {\r\n state.isOpen = true\r\n notify()\r\n },\r\n\r\n close() {\r\n state.isOpen = false\r\n notify()\r\n },\r\n\r\n toggle() {\r\n state.isOpen = !state.isOpen\r\n notify()\r\n },\r\n\r\n subscribe(cb) {\r\n listeners.add(cb)\r\n return () => listeners.delete(cb)\r\n }\r\n }\r\n}\r\n\r\n// ─────────────────────────────────────────────────────\r\n// INSTANCE GLOBALE — singleton partagé entre tous les stores\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport const devTools = createDevTools()\r\n\r\n// ─────────────────────────────────────────────────────\r\n// PLUGIN — connecte un store aux DevTools\r\n// ─────────────────────────────────────────────────────\r\n\r\nexport function connectDevTools(store: any, storeName: string) {\r\n if (!devTools) return\r\n\r\n let prevState: any = {}\r\n\r\n // Accès aux hooks via __store__\r\n const internalStore = store.__store__\r\n\r\n if (!internalStore) return\r\n\r\n // Sauvegarder les hooks existants\r\n const existingHooks = { ...internalStore['_hooks'] }\r\n\r\n // Remplacer les hooks\r\n internalStore['_hooks'] = {\r\n ...existingHooks,\r\n\r\n onAction(name: string, args: unknown[]) {\r\n prevState = store.getState()\r\n existingHooks.onAction?.(name, args)\r\n },\r\n\r\n onActionDone(name: string, duration: number) {\r\n const nextState = store.getState()\r\n devTools.logAction({\r\n name: `[${storeName}] ${name}`,\r\n args: [],\r\n duration,\r\n status: 'success',\r\n prevState: { ...prevState },\r\n nextState: { ...nextState }\r\n })\r\n existingHooks.onActionDone?.(name, duration)\r\n },\r\n\r\n onError(error: Error, actionName: string) {\r\n devTools.logAction({\r\n name: `[${storeName}] ${actionName}`,\r\n args: [],\r\n duration: 0,\r\n status: 'error',\r\n error: error.message,\r\n prevState: { ...prevState },\r\n nextState: { ...prevState }\r\n })\r\n existingHooks.onError?.(error, actionName)\r\n },\r\n\r\n onStateChange: existingHooks.onStateChange\r\n }\r\n}"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ngstato/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Stato — Zero-dependency state management engine",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -22,5 +22,24 @@
|
|
|
22
22
|
"tsup": "^8.0.0",
|
|
23
23
|
"vitest": "^1.6.0",
|
|
24
24
|
"typescript": "^5.4.0"
|
|
25
|
-
}
|
|
26
|
-
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/becher/ngStato.git",
|
|
30
|
+
"directory": "packages/core"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/becher/ngStato#readme",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/becher/ngStato/issues"
|
|
35
|
+
},
|
|
36
|
+
"author": "becher",
|
|
37
|
+
"keywords": [
|
|
38
|
+
"state-management",
|
|
39
|
+
"store",
|
|
40
|
+
"signals",
|
|
41
|
+
"framework-agnostic",
|
|
42
|
+
"rxjs-alternative",
|
|
43
|
+
"ngstato"
|
|
44
|
+
]
|
|
45
|
+
}
|