@plyaz/types 1.22.5 → 1.22.7
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.
|
@@ -107,13 +107,19 @@ export type CoreValidatorClass<T extends CoreBaseValidatorInstance = CoreBaseVal
|
|
|
107
107
|
* Injected services/dependencies for domain services.
|
|
108
108
|
* These are created/managed by ServiceRegistry and injected into services.
|
|
109
109
|
*/
|
|
110
|
-
export interface CoreInjectedServices {
|
|
110
|
+
export interface CoreInjectedServices<TStores = unknown> {
|
|
111
111
|
/** Cache manager instance */
|
|
112
112
|
cache?: unknown;
|
|
113
113
|
/** Database service instance */
|
|
114
114
|
db?: unknown;
|
|
115
115
|
/** API client instance */
|
|
116
116
|
api?: unknown;
|
|
117
|
+
/**
|
|
118
|
+
* Store instances (from root store) keyed by store key.
|
|
119
|
+
* Type-safe: each key maps to its specific slice type.
|
|
120
|
+
* @example { example: ExampleStoreSlice, errors: ErrorStoreSlice }
|
|
121
|
+
*/
|
|
122
|
+
stores?: TStores extends Record<string, unknown> ? Partial<TStores> : Record<string, TStores>;
|
|
117
123
|
}
|
|
118
124
|
/**
|
|
119
125
|
* Base service configuration passed to constructor
|
|
@@ -53,15 +53,12 @@ export interface CoreFeatureFlagServiceInitConfig extends CoreBaseFrontendServic
|
|
|
53
53
|
}
|
|
54
54
|
/**
|
|
55
55
|
* Base interface for frontend services with store integration
|
|
56
|
+
*
|
|
57
|
+
* Note: In the single root store architecture, stores are auto-injected
|
|
58
|
+
* by ServiceRegistry. Services no longer manually connect/disconnect stores.
|
|
56
59
|
*/
|
|
57
60
|
export interface CoreBaseFrontendServiceInterface<TStore extends CoreBaseFrontendStore = CoreBaseFrontendStore> extends CoreBaseDomainServiceInterface {
|
|
58
|
-
/**
|
|
59
|
-
connectStore(store: TStore): void;
|
|
60
|
-
/** Disconnect a store from receiving updates */
|
|
61
|
-
disconnectStore(store: TStore): void;
|
|
62
|
-
/** Disconnect all connected stores */
|
|
63
|
-
disconnectAllStores(): void;
|
|
64
|
-
/** Number of connected stores */
|
|
61
|
+
/** Number of connected stores (primary + read stores) */
|
|
65
62
|
readonly connectedStoreCount: number;
|
|
66
63
|
/** Whether any stores are connected */
|
|
67
64
|
readonly hasConnectedStores: boolean;
|
|
@@ -7,6 +7,7 @@ import type { ReactNode } from 'react';
|
|
|
7
7
|
import type { CoreBaseDomainServiceInterface } from '../domain';
|
|
8
8
|
import type { CoreAppEnvironment, CoreAppContext } from '../modules';
|
|
9
9
|
import type { FeatureFlagValue, FeatureFlagContext } from '../../features';
|
|
10
|
+
import type { RootStoreSlice } from '../../store';
|
|
10
11
|
import type { CoreBaseDomainServiceConfig } from '../domain';
|
|
11
12
|
import type { CoreBaseServiceConfig, CoreBaseMapperInstance, CoreBaseValidatorInstance } from '../domain';
|
|
12
13
|
import type { CoreDomainServiceInstance, CoreServiceEntry } from '../init';
|
|
@@ -40,36 +41,28 @@ import type { CoreDomainServiceInstance, CoreServiceEntry } from '../init';
|
|
|
40
41
|
* selectedId: string | null;
|
|
41
42
|
* }
|
|
42
43
|
*
|
|
44
|
+
* // Extend CoreBaseFrontendStore - all CRUD methods included in base
|
|
43
45
|
* interface MyStore extends CoreBaseFrontendStore<MyStoreData> {
|
|
44
46
|
* items: MyEntity[];
|
|
45
47
|
* selectedId: string | null;
|
|
46
48
|
* isLoading: boolean;
|
|
47
|
-
*
|
|
48
|
-
* // Required by CoreBaseFrontendStore
|
|
49
|
-
* setData: (data: MyStoreData) => void;
|
|
50
|
-
* updateData: (data: Partial<MyStoreData>) => void;
|
|
51
|
-
* setLoading: (isLoading: boolean) => void;
|
|
52
|
-
*
|
|
53
|
-
* // Domain-specific methods
|
|
54
|
-
* addItem: (item: MyEntity) => void;
|
|
55
|
-
* updateItem: (id: string, item: MyEntity) => void;
|
|
56
|
-
* removeItem: (id: string) => void;
|
|
57
49
|
* }
|
|
58
50
|
*
|
|
59
|
-
* export const useMyStore = create<MyStore>((set) => ({
|
|
51
|
+
* export const useMyStore = create<MyStore>((set, get) => ({
|
|
60
52
|
* items: [],
|
|
61
53
|
* selectedId: null,
|
|
62
54
|
* isLoading: false,
|
|
63
55
|
*
|
|
56
|
+
* // CoreBaseFrontendStore methods
|
|
57
|
+
* getData: () => ({ items: get().items, selectedId: get().selectedId }),
|
|
64
58
|
* setData: (data) => set({ items: data.items, selectedId: data.selectedId }),
|
|
65
59
|
* updateData: (data) => set((state) => ({ ...state, ...data })),
|
|
66
60
|
* setLoading: (isLoading) => set({ isLoading }),
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* items: state.items.map((i) => (i.id === id ? item : i)),
|
|
61
|
+
* addData: (item) => set((state) => ({ items: [...state.items, item] })),
|
|
62
|
+
* updateDataById: (id, item) => set((state) => ({
|
|
63
|
+
* items: state.items.map((i) => i.id === id ? { ...i, ...item } : i),
|
|
71
64
|
* })),
|
|
72
|
-
*
|
|
65
|
+
* removeData: (id) => set((state) => ({
|
|
73
66
|
* items: state.items.filter((i) => i.id !== id),
|
|
74
67
|
* })),
|
|
75
68
|
* }));
|
|
@@ -78,8 +71,9 @@ import type { CoreDomainServiceInstance, CoreServiceEntry } from '../init';
|
|
|
78
71
|
* ## Service Integration
|
|
79
72
|
* Services automatically call these methods after successful operations:
|
|
80
73
|
* - After `fetchAll()` → calls `setData()` with full dataset
|
|
81
|
-
* - After `create()` →
|
|
82
|
-
* - After `update()` →
|
|
74
|
+
* - After `create()` → calls `addData()` to append new item
|
|
75
|
+
* - After `update()` → calls `updateDataById()` to update specific item
|
|
76
|
+
* - After `delete()` → calls `removeData()` to remove item
|
|
83
77
|
* - Before any operation → calls `setLoading(true)`
|
|
84
78
|
* - After operation completes → calls `setLoading(false)`
|
|
85
79
|
*
|
|
@@ -89,6 +83,20 @@ import type { CoreDomainServiceInstance, CoreServiceEntry } from '../init';
|
|
|
89
83
|
* @see {@link BaseFrontendDomainService} for service implementation
|
|
90
84
|
*/
|
|
91
85
|
export interface CoreBaseFrontendStore<TData = Record<string, unknown>> {
|
|
86
|
+
/**
|
|
87
|
+
* Get current store data.
|
|
88
|
+
*
|
|
89
|
+
* Used by services to read current state for operations like delete
|
|
90
|
+
* (filter out item) or optimistic updates.
|
|
91
|
+
*
|
|
92
|
+
* @returns Current data object
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* getData: () => ({ items: get().items, selectedId: get().selectedId })
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
getData?(): TData;
|
|
92
100
|
/**
|
|
93
101
|
* Set/replace all data in the store (full replacement).
|
|
94
102
|
*
|
|
@@ -132,6 +140,55 @@ export interface CoreBaseFrontendStore<TData = Record<string, unknown>> {
|
|
|
132
140
|
* ```
|
|
133
141
|
*/
|
|
134
142
|
setLoading?(isLoading: boolean): void;
|
|
143
|
+
/**
|
|
144
|
+
* Add data to store (append to array).
|
|
145
|
+
*
|
|
146
|
+
* Called by services after successful create operations.
|
|
147
|
+
* Store implementation handles appending to the items array.
|
|
148
|
+
*
|
|
149
|
+
* @param item - Item to add
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```typescript
|
|
153
|
+
* addData: (item) => set((state) => ({
|
|
154
|
+
* items: [...state.items, item]
|
|
155
|
+
* }))
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
addData?(item: unknown): void;
|
|
159
|
+
/**
|
|
160
|
+
* Update data in store by ID.
|
|
161
|
+
*
|
|
162
|
+
* Called by services after successful update operations.
|
|
163
|
+
* Store implementation handles finding and updating the specific item.
|
|
164
|
+
*
|
|
165
|
+
* @param id - Item ID to update
|
|
166
|
+
* @param item - Updated item data
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```typescript
|
|
170
|
+
* updateDataById: (id, item) => set((state) => ({
|
|
171
|
+
* items: state.items.map((i) => i.id === id ? { ...i, ...item } : i)
|
|
172
|
+
* }))
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
updateDataById?(id: string, item: unknown): void;
|
|
176
|
+
/**
|
|
177
|
+
* Remove data from store by ID.
|
|
178
|
+
*
|
|
179
|
+
* Called by services after successful delete operations.
|
|
180
|
+
* Store implementation handles filtering out the item.
|
|
181
|
+
*
|
|
182
|
+
* @param id - Item ID to remove
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```typescript
|
|
186
|
+
* removeData: (id) => set((state) => ({
|
|
187
|
+
* items: state.items.filter((item) => item.id !== id)
|
|
188
|
+
* }))
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
removeData?(id: string): void;
|
|
135
192
|
}
|
|
136
193
|
/**
|
|
137
194
|
* Fetcher function type for API operations
|
|
@@ -525,6 +582,61 @@ export interface CoreStoreHandlers<TData = Record<string, unknown>, TStore exten
|
|
|
525
582
|
* ```
|
|
526
583
|
*/
|
|
527
584
|
setLoading?: (store: TStore, isLoading: boolean) => void;
|
|
585
|
+
/**
|
|
586
|
+
* Custom handler for adding data to store.
|
|
587
|
+
*
|
|
588
|
+
* Replaces the default `store.addData(item)` call.
|
|
589
|
+
* Called during create operations.
|
|
590
|
+
*
|
|
591
|
+
* @param store - Store instance
|
|
592
|
+
* @param item - Item to add
|
|
593
|
+
*
|
|
594
|
+
* @example
|
|
595
|
+
* ```typescript
|
|
596
|
+
* addData: (store, item) => {
|
|
597
|
+
* store.appendItem(item);
|
|
598
|
+
* store.setLastCreated(item.id);
|
|
599
|
+
* }
|
|
600
|
+
* ```
|
|
601
|
+
*/
|
|
602
|
+
addData?: (store: TStore, item: unknown) => void;
|
|
603
|
+
/**
|
|
604
|
+
* Custom handler for updating data by ID.
|
|
605
|
+
*
|
|
606
|
+
* Replaces the default `store.updateDataById(id, item)` call.
|
|
607
|
+
* Called during update operations.
|
|
608
|
+
*
|
|
609
|
+
* @param store - Store instance
|
|
610
|
+
* @param id - Item ID to update
|
|
611
|
+
* @param item - Updated item data
|
|
612
|
+
*
|
|
613
|
+
* @example
|
|
614
|
+
* ```typescript
|
|
615
|
+
* updateDataById: (store, id, item) => {
|
|
616
|
+
* store.updateItemById(id, item);
|
|
617
|
+
* store.setLastUpdated(id);
|
|
618
|
+
* }
|
|
619
|
+
* ```
|
|
620
|
+
*/
|
|
621
|
+
updateDataById?: (store: TStore, id: string, item: unknown) => void;
|
|
622
|
+
/**
|
|
623
|
+
* Custom handler for removing data by ID.
|
|
624
|
+
*
|
|
625
|
+
* Replaces the default `store.removeData(id)` call.
|
|
626
|
+
* Called during delete operations.
|
|
627
|
+
*
|
|
628
|
+
* @param store - Store instance
|
|
629
|
+
* @param id - Item ID to remove
|
|
630
|
+
*
|
|
631
|
+
* @example
|
|
632
|
+
* ```typescript
|
|
633
|
+
* removeData: (store, id) => {
|
|
634
|
+
* store.removeItemById(id);
|
|
635
|
+
* store.clearSelection();
|
|
636
|
+
* }
|
|
637
|
+
* ```
|
|
638
|
+
*/
|
|
639
|
+
removeData?: (store: TStore, id: string) => void;
|
|
528
640
|
}
|
|
529
641
|
/**
|
|
530
642
|
* Configuration for frontend domain services
|
|
@@ -533,19 +645,20 @@ export interface CoreBaseFrontendServiceConfig<TData = Record<string, unknown>,
|
|
|
533
645
|
/**
|
|
534
646
|
* Primary store key - the main store this service can mutate.
|
|
535
647
|
* Service can call setData(), updateData(), setLoading() on this store.
|
|
536
|
-
*
|
|
648
|
+
* Type-safe: only valid store keys from RootStoreSlice allowed.
|
|
537
649
|
*
|
|
538
|
-
* @example '
|
|
650
|
+
* @example 'example'
|
|
539
651
|
*/
|
|
540
|
-
store?:
|
|
652
|
+
store?: keyof RootStoreSlice;
|
|
541
653
|
/**
|
|
542
654
|
* Read-only store keys - stores this service can read from but not mutate.
|
|
543
655
|
* Service can access state but should not call mutation methods.
|
|
544
656
|
* Used for cross-domain data access (e.g., campaign service reading user data).
|
|
657
|
+
* Type-safe: only valid store keys from RootStoreSlice allowed.
|
|
545
658
|
*
|
|
546
|
-
* @example ['
|
|
659
|
+
* @example ['errors', 'featureFlags']
|
|
547
660
|
*/
|
|
548
|
-
readStores?:
|
|
661
|
+
readStores?: (keyof RootStoreSlice)[];
|
|
549
662
|
/** API base path for endpoints (e.g., '/api/examples') */
|
|
550
663
|
apiBasePath?: string;
|
|
551
664
|
/** Fetcher functions for API operations (replaces direct apiClient usage) */
|
|
@@ -8,6 +8,7 @@ import type { ApiClientOptions } from '../../api';
|
|
|
8
8
|
import type { FeatureFlagValue, FeatureFlagPollingConfig, CacheStrategyType } from '../../features';
|
|
9
9
|
import type { PackageErrorLike, MessageCatalog } from '../../errors';
|
|
10
10
|
import type { GlobalErrorHandlerConfig, ErrorHandlerLogger } from '../../errors/middleware';
|
|
11
|
+
import type { RootStoreSlice } from '../../store';
|
|
11
12
|
import type { CoreAppEnvironment, CoreAppContext, CoreRuntimeEnvironment, CoreServiceRuntime } from '../modules';
|
|
12
13
|
import type { CoreDbServiceConfig } from '../services';
|
|
13
14
|
import type { CoreInjectedServices } from '../domain';
|
|
@@ -36,23 +37,25 @@ export interface CoreServiceInitConfig {
|
|
|
36
37
|
/**
|
|
37
38
|
* Primary store key - the main store this service can mutate.
|
|
38
39
|
* The service can call setData(), updateData(), setLoading() on this store.
|
|
40
|
+
* Type-safe: only valid store keys allowed.
|
|
39
41
|
*
|
|
40
42
|
* @example
|
|
41
43
|
* ```typescript
|
|
42
44
|
* { service: CampaignService, config: { store: 'campaigns' } }
|
|
43
45
|
* ```
|
|
44
46
|
*/
|
|
45
|
-
store?:
|
|
47
|
+
store?: keyof RootStoreSlice;
|
|
46
48
|
/**
|
|
47
49
|
* Read-only store keys - stores this service can read from but not mutate.
|
|
48
50
|
* Used for cross-domain data access (e.g., campaign service reading user data).
|
|
51
|
+
* Type-safe: only valid store keys allowed.
|
|
49
52
|
*
|
|
50
53
|
* @example
|
|
51
54
|
* ```typescript
|
|
52
|
-
* { service: CampaignService, config: { store: 'campaigns', readStores: ['users', '
|
|
55
|
+
* { service: CampaignService, config: { store: 'campaigns', readStores: ['users', 'errors'] } }
|
|
53
56
|
* ```
|
|
54
57
|
*/
|
|
55
|
-
readStores?:
|
|
58
|
+
readStores?: (keyof RootStoreSlice)[];
|
|
56
59
|
/**
|
|
57
60
|
* When to initialize the service:
|
|
58
61
|
* - 'immediate': Initialize during Core.initialize() (default)
|
|
@@ -386,13 +389,17 @@ export interface CoreServiceRegistryConfig {
|
|
|
386
389
|
cache?: CoreCacheConfig;
|
|
387
390
|
/**
|
|
388
391
|
* Store registry interface for injecting stores into services.
|
|
389
|
-
* Provides type-safe store access via
|
|
392
|
+
* Provides type-safe store access via store keys.
|
|
390
393
|
*
|
|
391
|
-
* @see
|
|
394
|
+
* @see RootStoreSlice in @plyaz/types/store for available stores
|
|
392
395
|
*/
|
|
393
396
|
stores?: {
|
|
394
|
-
/**
|
|
395
|
-
|
|
397
|
+
/**
|
|
398
|
+
* Get a store slice by key with full type safety.
|
|
399
|
+
* @param key - Store key (e.g., 'example', 'errors', 'featureFlags')
|
|
400
|
+
* @returns Typed store slice or undefined
|
|
401
|
+
*/
|
|
402
|
+
getStore<K extends keyof RootStoreSlice>(key: K): RootStoreSlice[K] | undefined;
|
|
396
403
|
};
|
|
397
404
|
/** Services to register and initialize */
|
|
398
405
|
services: CoreServiceEntry[];
|
package/dist/examples/types.d.ts
CHANGED
|
@@ -123,17 +123,9 @@ export interface ExampleFrontendStoreState {
|
|
|
123
123
|
}
|
|
124
124
|
/**
|
|
125
125
|
* Example frontend store actions.
|
|
126
|
-
* Extends CoreBaseFrontendStore
|
|
126
|
+
* Extends CoreBaseFrontendStore which provides all CRUD methods.
|
|
127
127
|
*/
|
|
128
128
|
export interface ExampleFrontendStoreActions extends CoreBaseFrontendStore<ExampleFrontendStoreData> {
|
|
129
|
-
/** Set items array */
|
|
130
|
-
setItems: (items: ExampleEntity[]) => void;
|
|
131
|
-
/** Add a single item */
|
|
132
|
-
addItem: (item: ExampleEntity) => void;
|
|
133
|
-
/** Update a single item */
|
|
134
|
-
updateItem: (id: string, updates: Partial<ExampleEntity>) => void;
|
|
135
|
-
/** Remove a single item */
|
|
136
|
-
removeItem: (id: string) => void;
|
|
137
129
|
/** Select an item by ID */
|
|
138
130
|
selectItem: (id: string | null) => void;
|
|
139
131
|
}
|
package/dist/store/types.d.ts
CHANGED
|
@@ -56,35 +56,34 @@ export interface FeatureFlagStoreConfig {
|
|
|
56
56
|
}
|
|
57
57
|
/**
|
|
58
58
|
* Combined root store state and actions.
|
|
59
|
-
*
|
|
59
|
+
* Uses NAMESPACED structure for clear separation of slices.
|
|
60
60
|
*
|
|
61
61
|
* **Architecture:**
|
|
62
|
-
* - Global slices:
|
|
62
|
+
* - Global slices: errors, featureFlags (always included)
|
|
63
63
|
* - Domain slices: example, campaigns, users, etc. (add as needed)
|
|
64
|
+
* - Each slice is namespaced under its key (e.g., store.example.items)
|
|
64
65
|
*
|
|
65
|
-
* **Benefits of single-store:**
|
|
66
|
+
* **Benefits of namespaced single-store:**
|
|
66
67
|
* - ✅ One Zustand instance - can access without hooks
|
|
67
68
|
* - ✅ Cross-slice subscriptions work automatically
|
|
68
69
|
* - ✅ Single source of truth via store.getState()
|
|
69
|
-
* - ✅
|
|
70
|
-
|
|
71
|
-
export type RootStoreSlice = ErrorStoreSlice & FeatureFlagStoreSlice & ExampleFrontendStoreSlice;
|
|
72
|
-
/**
|
|
73
|
-
* Type map of all available stores in the system.
|
|
74
|
-
* Maps store keys to their corresponding store types.
|
|
70
|
+
* - ✅ Clear ownership - no property name conflicts
|
|
71
|
+
* - ✅ getStore(key) returns specific slice (not entire root)
|
|
75
72
|
*
|
|
76
|
-
* Add new stores here for type-safe store access:
|
|
77
73
|
* @example
|
|
78
74
|
* ```typescript
|
|
79
|
-
* const
|
|
75
|
+
* const rootStore = useRootStore();
|
|
76
|
+
* rootStore.example.items; // Example slice
|
|
77
|
+
* rootStore.errors.errors; // Error slice
|
|
78
|
+
* rootStore.featureFlags.flags; // Feature flag slice
|
|
80
79
|
* ```
|
|
81
80
|
*/
|
|
82
|
-
export interface
|
|
83
|
-
/** Error
|
|
84
|
-
|
|
85
|
-
/** Feature flags
|
|
81
|
+
export interface RootStoreSlice {
|
|
82
|
+
/** Error tracking slice (global) */
|
|
83
|
+
errors: ErrorStoreSlice;
|
|
84
|
+
/** Feature flags slice (global) */
|
|
86
85
|
featureFlags: FeatureFlagStoreSlice;
|
|
87
|
-
/** Example
|
|
86
|
+
/** Example domain slice */
|
|
88
87
|
example: ExampleFrontendStoreSlice;
|
|
89
88
|
}
|
|
90
89
|
/**
|
|
@@ -93,11 +92,17 @@ export interface StoreTypeMap {
|
|
|
93
92
|
*/
|
|
94
93
|
export interface StoreRegistry {
|
|
95
94
|
/**
|
|
96
|
-
* Get a store by key with full type safety.
|
|
95
|
+
* Get a store slice by key with full type safety.
|
|
97
96
|
* @param key - Store key from STORE_KEYS
|
|
98
|
-
* @returns Typed store
|
|
97
|
+
* @returns Typed store slice or undefined
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const exampleSlice = getStore('example'); // Returns ExampleFrontendStoreSlice
|
|
102
|
+
* const errorSlice = getStore('errors'); // Returns ErrorStoreSlice
|
|
103
|
+
* ```
|
|
99
104
|
*/
|
|
100
|
-
getStore<K extends keyof
|
|
105
|
+
getStore<K extends keyof RootStoreSlice>(key: K): RootStoreSlice[K] | undefined;
|
|
101
106
|
}
|
|
102
107
|
/**
|
|
103
108
|
* Configuration for creating the root store.
|
package/package.json
CHANGED