@ngstato/core 0.1.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 ADDED
@@ -0,0 +1,49 @@
1
+ # @ngstato/core
2
+
3
+ State management framework-agnostic — Signals-first, sans RxJS obligatoire.
4
+
5
+ ## Installation
6
+ ```bash
7
+ npm install @ngstato/core
8
+ ```
9
+
10
+ ## Usage
11
+ ```ts
12
+ import { createStore, http } from '@ngstato/core'
13
+
14
+ const store = createStore({
15
+ users: [] as User[],
16
+ isLoading: false,
17
+
18
+ actions: {
19
+ async loadUsers(state) {
20
+ state.isLoading = true
21
+ state.users = await http.get('/users')
22
+ state.isLoading = false
23
+ }
24
+ },
25
+
26
+ computed: {
27
+ total: (state) => state.users.length
28
+ }
29
+ })
30
+
31
+ await store.loadUsers()
32
+ console.log(store.users) // User[]
33
+ console.log(store.total) // number
34
+ ```
35
+
36
+ ## Helpers
37
+
38
+ | Helper | Description |
39
+ |--------|-------------|
40
+ | `abortable()` | Annule la requête précédente si l'action est rappelée |
41
+ | `debounced()` | Debounce sans RxJS |
42
+ | `throttled()` | Throttle sans RxJS |
43
+ | `retryable()` | Retry avec backoff fixe ou exponentiel |
44
+ | `fromStream()` | Realtime — WebSocket, Firebase, Supabase |
45
+ | `optimistic()` | Optimistic update + rollback automatique |
46
+
47
+ ## Documentation
48
+
49
+ Voir [github.com/becher/ngstato](https://github.com/becher/ngstato)
@@ -0,0 +1,127 @@
1
+ type StateSlice<T> = Omit<T, 'actions' | 'computed' | 'hooks'>;
2
+ type Action<S> = (state: S, ...args: any[]) => void | Promise<void> | (() => void);
3
+ type ActionsMap<S> = Record<string, Action<S>>;
4
+ type ComputedFn<S> = (state: S) => unknown;
5
+ interface StatoHooks<S> {
6
+ onInit?: (store: S) => void | Promise<void>;
7
+ onDestroy?: (store: S) => void | Promise<void>;
8
+ onAction?: (name: string, args: unknown[]) => void;
9
+ onActionDone?: (name: string, duration: number) => void;
10
+ onError?: (error: Error, actionName: string) => void;
11
+ onStateChange?: (prev: S, next: S) => void;
12
+ }
13
+ interface StatoStoreConfig<S extends object> {
14
+ actions?: ActionsMap<StateSlice<S>>;
15
+ computed?: Record<string, ComputedFn<StateSlice<S>> | unknown[]>;
16
+ hooks?: StatoHooks<any>;
17
+ [key: string]: unknown;
18
+ }
19
+ type StatoStoreInstance<S extends object> = {
20
+ readonly [K in keyof StateSlice<S>]: StateSlice<S>[K];
21
+ } & {
22
+ [K in keyof S as S[K] extends Function ? K : never]: S[K] extends (state: any, ...args: infer A) => infer R ? (...args: A) => R : never;
23
+ };
24
+ interface StatoConfig {
25
+ baseUrl?: string;
26
+ timeout?: number;
27
+ headers?: Record<string, string>;
28
+ auth?: () => string | null | undefined;
29
+ }
30
+ declare class StatoHttpError extends Error {
31
+ status: number;
32
+ body: string;
33
+ constructor(status: number, body: string);
34
+ }
35
+
36
+ declare function createStore<S extends object>(config: S & StatoStoreConfig<S>): any;
37
+
38
+ interface RequestOptions {
39
+ params?: Record<string, string | number | boolean>;
40
+ headers?: Record<string, string>;
41
+ signal?: AbortSignal;
42
+ }
43
+ declare class StatoHttp {
44
+ private _config;
45
+ constructor(config?: StatoConfig);
46
+ get<T = unknown>(url: string, options?: RequestOptions): Promise<T>;
47
+ post<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T>;
48
+ put<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T>;
49
+ patch<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T>;
50
+ delete<T = unknown>(url: string, options?: RequestOptions): Promise<T>;
51
+ private _request;
52
+ private _buildUrl;
53
+ }
54
+ declare function createHttp(config?: StatoConfig): StatoHttp;
55
+ declare function configureHttp(config: StatoConfig): void;
56
+ declare const http: {
57
+ get: <T>(url: string, options?: RequestOptions) => Promise<T>;
58
+ post: <T>(url: string, body?: unknown, options?: RequestOptions) => Promise<T>;
59
+ put: <T>(url: string, body?: unknown, options?: RequestOptions) => Promise<T>;
60
+ patch: <T>(url: string, body?: unknown, options?: RequestOptions) => Promise<T>;
61
+ delete: <T>(url: string, options?: RequestOptions) => Promise<T>;
62
+ };
63
+
64
+ interface AbortableOptions {
65
+ signal: AbortSignal;
66
+ }
67
+ declare function abortable<S, A extends unknown[]>(fn: (state: S, ...args: [...A, AbortableOptions]) => Promise<void>): (state: S, ...args: A) => Promise<void>;
68
+
69
+ declare function debounced<S, A extends unknown[]>(fn: (state: S, ...args: A) => void | Promise<void>, ms?: number): (state: S, ...args: A) => Promise<void>;
70
+
71
+ declare function throttled<S, A extends unknown[]>(fn: (state: S, ...args: A) => void | Promise<void>, ms?: number): (state: S, ...args: A) => Promise<void>;
72
+
73
+ interface RetryOptions {
74
+ attempts: number;
75
+ backoff: 'fixed' | 'exponential';
76
+ delay?: number;
77
+ onRetry?: (attempt: number, error: Error) => void;
78
+ }
79
+ declare function retryable<S, A extends unknown[]>(fn: (state: S, ...args: A) => Promise<void>, options?: RetryOptions): (state: S, ...args: A) => Promise<void>;
80
+
81
+ interface StatoObservable<T> {
82
+ subscribe(observer: {
83
+ next?: (value: T) => void;
84
+ error?: (error: unknown) => void;
85
+ complete?: () => void;
86
+ }): {
87
+ unsubscribe(): void;
88
+ };
89
+ }
90
+ interface StreamOptions {
91
+ onComplete?: () => void;
92
+ onError?: (error: unknown) => void;
93
+ }
94
+ declare function fromStream<S, T>(setupFn: (state: S) => StatoObservable<T>, updateFn: (state: S, value: T) => void, options?: StreamOptions): (state: S) => (() => void);
95
+
96
+ 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
+
98
+ interface ActionLog {
99
+ id: number;
100
+ name: string;
101
+ args: unknown[];
102
+ duration: number;
103
+ status: 'success' | 'error';
104
+ error?: string;
105
+ prevState: unknown;
106
+ nextState: unknown;
107
+ at: string;
108
+ }
109
+ interface DevToolsState {
110
+ logs: ActionLog[];
111
+ isOpen: boolean;
112
+ maxLogs: number;
113
+ }
114
+ interface DevToolsInstance {
115
+ state: DevToolsState;
116
+ logAction: (log: Omit<ActionLog, 'id' | 'at'>) => void;
117
+ clear: () => void;
118
+ open: () => void;
119
+ close: () => void;
120
+ toggle: () => void;
121
+ subscribe: (cb: (state: DevToolsState) => void) => () => void;
122
+ }
123
+ declare function createDevTools(maxLogs?: number): DevToolsInstance;
124
+ declare const devTools: DevToolsInstance;
125
+ declare function connectDevTools(store: any, storeName: string): void;
126
+
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 };
@@ -0,0 +1,127 @@
1
+ type StateSlice<T> = Omit<T, 'actions' | 'computed' | 'hooks'>;
2
+ type Action<S> = (state: S, ...args: any[]) => void | Promise<void> | (() => void);
3
+ type ActionsMap<S> = Record<string, Action<S>>;
4
+ type ComputedFn<S> = (state: S) => unknown;
5
+ interface StatoHooks<S> {
6
+ onInit?: (store: S) => void | Promise<void>;
7
+ onDestroy?: (store: S) => void | Promise<void>;
8
+ onAction?: (name: string, args: unknown[]) => void;
9
+ onActionDone?: (name: string, duration: number) => void;
10
+ onError?: (error: Error, actionName: string) => void;
11
+ onStateChange?: (prev: S, next: S) => void;
12
+ }
13
+ interface StatoStoreConfig<S extends object> {
14
+ actions?: ActionsMap<StateSlice<S>>;
15
+ computed?: Record<string, ComputedFn<StateSlice<S>> | unknown[]>;
16
+ hooks?: StatoHooks<any>;
17
+ [key: string]: unknown;
18
+ }
19
+ type StatoStoreInstance<S extends object> = {
20
+ readonly [K in keyof StateSlice<S>]: StateSlice<S>[K];
21
+ } & {
22
+ [K in keyof S as S[K] extends Function ? K : never]: S[K] extends (state: any, ...args: infer A) => infer R ? (...args: A) => R : never;
23
+ };
24
+ interface StatoConfig {
25
+ baseUrl?: string;
26
+ timeout?: number;
27
+ headers?: Record<string, string>;
28
+ auth?: () => string | null | undefined;
29
+ }
30
+ declare class StatoHttpError extends Error {
31
+ status: number;
32
+ body: string;
33
+ constructor(status: number, body: string);
34
+ }
35
+
36
+ declare function createStore<S extends object>(config: S & StatoStoreConfig<S>): any;
37
+
38
+ interface RequestOptions {
39
+ params?: Record<string, string | number | boolean>;
40
+ headers?: Record<string, string>;
41
+ signal?: AbortSignal;
42
+ }
43
+ declare class StatoHttp {
44
+ private _config;
45
+ constructor(config?: StatoConfig);
46
+ get<T = unknown>(url: string, options?: RequestOptions): Promise<T>;
47
+ post<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T>;
48
+ put<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T>;
49
+ patch<T = unknown>(url: string, body?: unknown, options?: RequestOptions): Promise<T>;
50
+ delete<T = unknown>(url: string, options?: RequestOptions): Promise<T>;
51
+ private _request;
52
+ private _buildUrl;
53
+ }
54
+ declare function createHttp(config?: StatoConfig): StatoHttp;
55
+ declare function configureHttp(config: StatoConfig): void;
56
+ declare const http: {
57
+ get: <T>(url: string, options?: RequestOptions) => Promise<T>;
58
+ post: <T>(url: string, body?: unknown, options?: RequestOptions) => Promise<T>;
59
+ put: <T>(url: string, body?: unknown, options?: RequestOptions) => Promise<T>;
60
+ patch: <T>(url: string, body?: unknown, options?: RequestOptions) => Promise<T>;
61
+ delete: <T>(url: string, options?: RequestOptions) => Promise<T>;
62
+ };
63
+
64
+ interface AbortableOptions {
65
+ signal: AbortSignal;
66
+ }
67
+ declare function abortable<S, A extends unknown[]>(fn: (state: S, ...args: [...A, AbortableOptions]) => Promise<void>): (state: S, ...args: A) => Promise<void>;
68
+
69
+ declare function debounced<S, A extends unknown[]>(fn: (state: S, ...args: A) => void | Promise<void>, ms?: number): (state: S, ...args: A) => Promise<void>;
70
+
71
+ declare function throttled<S, A extends unknown[]>(fn: (state: S, ...args: A) => void | Promise<void>, ms?: number): (state: S, ...args: A) => Promise<void>;
72
+
73
+ interface RetryOptions {
74
+ attempts: number;
75
+ backoff: 'fixed' | 'exponential';
76
+ delay?: number;
77
+ onRetry?: (attempt: number, error: Error) => void;
78
+ }
79
+ declare function retryable<S, A extends unknown[]>(fn: (state: S, ...args: A) => Promise<void>, options?: RetryOptions): (state: S, ...args: A) => Promise<void>;
80
+
81
+ interface StatoObservable<T> {
82
+ subscribe(observer: {
83
+ next?: (value: T) => void;
84
+ error?: (error: unknown) => void;
85
+ complete?: () => void;
86
+ }): {
87
+ unsubscribe(): void;
88
+ };
89
+ }
90
+ interface StreamOptions {
91
+ onComplete?: () => void;
92
+ onError?: (error: unknown) => void;
93
+ }
94
+ declare function fromStream<S, T>(setupFn: (state: S) => StatoObservable<T>, updateFn: (state: S, value: T) => void, options?: StreamOptions): (state: S) => (() => void);
95
+
96
+ 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
+
98
+ interface ActionLog {
99
+ id: number;
100
+ name: string;
101
+ args: unknown[];
102
+ duration: number;
103
+ status: 'success' | 'error';
104
+ error?: string;
105
+ prevState: unknown;
106
+ nextState: unknown;
107
+ at: string;
108
+ }
109
+ interface DevToolsState {
110
+ logs: ActionLog[];
111
+ isOpen: boolean;
112
+ maxLogs: number;
113
+ }
114
+ interface DevToolsInstance {
115
+ state: DevToolsState;
116
+ logAction: (log: Omit<ActionLog, 'id' | 'at'>) => void;
117
+ clear: () => void;
118
+ open: () => void;
119
+ close: () => void;
120
+ toggle: () => void;
121
+ subscribe: (cb: (state: DevToolsState) => void) => () => void;
122
+ }
123
+ declare function createDevTools(maxLogs?: number): DevToolsInstance;
124
+ declare const devTools: DevToolsInstance;
125
+ declare function connectDevTools(store: any, storeName: string): void;
126
+
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 };