@plyaz/types 1.22.0 → 1.22.2
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/dist/api/index.cjs.map +1 -1
- package/dist/api/index.js.map +1 -1
- package/dist/core/domain/crud.d.ts +27 -0
- package/dist/core/domain/index.d.ts +2 -1
- package/dist/core/domain/types.d.ts +34 -0
- package/dist/core/events/payloads.d.ts +1 -0
- package/dist/core/frontend/featureFlags.d.ts +3 -3
- package/dist/core/frontend/index.d.ts +1 -1
- package/dist/core/frontend/types.d.ts +544 -8
- package/dist/core/index.d.ts +1 -0
- package/dist/core/init/index.d.ts +1 -1
- package/dist/core/init/types.d.ts +133 -3
- package/dist/core/services/index.d.ts +1 -0
- package/dist/core/services/keys.d.ts +40 -0
- package/dist/errors/codes.d.ts +11 -0
- package/dist/errors/index.cjs +13 -1
- package/dist/errors/index.cjs.map +1 -1
- package/dist/errors/index.js +13 -1
- package/dist/errors/index.js.map +1 -1
- package/dist/errors/middleware.d.ts +23 -4
- package/dist/examples/types.d.ts +9 -5
- package/dist/features/cache/index.cjs +6 -0
- package/dist/features/cache/index.cjs.map +1 -1
- package/dist/features/cache/index.d.ts +1 -0
- package/dist/features/cache/index.js +5 -0
- package/dist/features/cache/index.js.map +1 -1
- package/dist/features/cache/types.d.ts +9 -1
- package/dist/features/index.cjs +6 -0
- package/dist/features/index.cjs.map +1 -1
- package/dist/features/index.d.ts +1 -0
- package/dist/features/index.js +5 -0
- package/dist/features/index.js.map +1 -1
- package/dist/index.cjs +30 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +28 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -13,18 +13,519 @@ import type { CoreBaseServiceConfig, CoreBaseMapperInstance, CoreBaseValidatorIn
|
|
|
13
13
|
import type { CoreDomainServiceInstance, CoreServiceEntry } from '../init';
|
|
14
14
|
/**
|
|
15
15
|
* Base store interface for frontend services.
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
*
|
|
17
|
+
* ## Overview
|
|
18
|
+
* This interface defines the contract between domain services and Zustand stores.
|
|
19
|
+
* Services call these methods to synchronize state after API operations.
|
|
20
|
+
*
|
|
21
|
+
* ## Required Methods
|
|
22
|
+
* At minimum, stores must implement either `setData` or domain-specific setters
|
|
23
|
+
* (e.g., `setFlags` for feature flags, `setItems` for collections).
|
|
24
|
+
*
|
|
25
|
+
* ## Optional Methods
|
|
26
|
+
* - `updateData` - For partial/merge updates (recommended for performance)
|
|
27
|
+
* - `setLoading` - For loading state management (automatically called by services)
|
|
28
|
+
*
|
|
29
|
+
* ## Error Handling
|
|
30
|
+
* **Important**: Error state is handled globally via the error store.
|
|
31
|
+
* Individual domain stores should NOT have `setError` or `error` state.
|
|
32
|
+
* Errors are automatically sent to the global error store by base services.
|
|
33
|
+
*
|
|
34
|
+
* ## Zustand Implementation Example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import { create } from 'zustand';
|
|
37
|
+
* import type { CoreBaseFrontendStore } from '@plyaz/types/core';
|
|
38
|
+
*
|
|
39
|
+
* interface MyStoreData {
|
|
40
|
+
* items: MyEntity[];
|
|
41
|
+
* selectedId: string | null;
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* interface MyStore extends CoreBaseFrontendStore<MyStoreData> {
|
|
45
|
+
* items: MyEntity[];
|
|
46
|
+
* selectedId: string | null;
|
|
47
|
+
* isLoading: boolean;
|
|
48
|
+
*
|
|
49
|
+
* // Required by CoreBaseFrontendStore
|
|
50
|
+
* setData: (data: MyStoreData) => void;
|
|
51
|
+
* updateData: (data: Partial<MyStoreData>) => void;
|
|
52
|
+
* setLoading: (isLoading: boolean) => void;
|
|
53
|
+
*
|
|
54
|
+
* // Domain-specific methods
|
|
55
|
+
* addItem: (item: MyEntity) => void;
|
|
56
|
+
* updateItem: (id: string, item: MyEntity) => void;
|
|
57
|
+
* removeItem: (id: string) => void;
|
|
58
|
+
* }
|
|
59
|
+
*
|
|
60
|
+
* export const useMyStore = create<MyStore>((set) => ({
|
|
61
|
+
* items: [],
|
|
62
|
+
* selectedId: null,
|
|
63
|
+
* isLoading: false,
|
|
64
|
+
*
|
|
65
|
+
* setData: (data) => set({ items: data.items, selectedId: data.selectedId }),
|
|
66
|
+
* updateData: (data) => set((state) => ({ ...state, ...data })),
|
|
67
|
+
* setLoading: (isLoading) => set({ isLoading }),
|
|
68
|
+
*
|
|
69
|
+
* addItem: (item) => set((state) => ({ items: [...state.items, item] })),
|
|
70
|
+
* updateItem: (id, item) => set((state) => ({
|
|
71
|
+
* items: state.items.map((i) => (i.id === id ? item : i)),
|
|
72
|
+
* })),
|
|
73
|
+
* removeItem: (id) => set((state) => ({
|
|
74
|
+
* items: state.items.filter((i) => i.id !== id),
|
|
75
|
+
* })),
|
|
76
|
+
* }));
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* ## Service Integration
|
|
80
|
+
* Services automatically call these methods after successful operations:
|
|
81
|
+
* - After `fetchAll()` → calls `setData()` with full dataset
|
|
82
|
+
* - After `create()` → service calls custom `addItem()` in `afterCreate` hook
|
|
83
|
+
* - After `update()` → service calls custom `updateItem()` in `afterUpdate` hook
|
|
84
|
+
* - Before any operation → calls `setLoading(true)`
|
|
85
|
+
* - After operation completes → calls `setLoading(false)`
|
|
86
|
+
*
|
|
87
|
+
* @typeParam TData - Store data structure (e.g., `{ items: Entity[]; selectedId: string | null }`)
|
|
88
|
+
*
|
|
89
|
+
* @see {@link CoreBaseFrontendServiceConfig} for service configuration
|
|
90
|
+
* @see {@link BaseFrontendDomainService} for service implementation
|
|
18
91
|
*/
|
|
19
92
|
export interface CoreBaseFrontendStore<TData = Record<string, unknown>> {
|
|
20
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* Set/replace all data in the store (full replacement).
|
|
95
|
+
*
|
|
96
|
+
* Called by services after operations that return complete datasets,
|
|
97
|
+
* such as `fetchAll()` or when resetting store state.
|
|
98
|
+
*
|
|
99
|
+
* @param data - Complete data object matching TData structure
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```typescript
|
|
103
|
+
* setData: (data) => set({ items: data.items, selectedId: data.selectedId })
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
21
106
|
setData?(data: TData): void;
|
|
22
|
-
/**
|
|
107
|
+
/**
|
|
108
|
+
* Update/merge data in the store (partial update).
|
|
109
|
+
*
|
|
110
|
+
* Called by services for incremental updates. More efficient than `setData`
|
|
111
|
+
* when only updating specific fields.
|
|
112
|
+
*
|
|
113
|
+
* @param data - Partial data object with fields to update
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* updateData: (data) => set((state) => ({ ...state, ...data }))
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
23
120
|
updateData?(data: Partial<TData>): void;
|
|
24
|
-
/**
|
|
121
|
+
/**
|
|
122
|
+
* Set loading state for async operations.
|
|
123
|
+
*
|
|
124
|
+
* Automatically called by services:
|
|
125
|
+
* - `setLoading(true)` before API call
|
|
126
|
+
* - `setLoading(false)` after completion (success or error)
|
|
127
|
+
*
|
|
128
|
+
* @param isLoading - Whether an operation is in progress
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```typescript
|
|
132
|
+
* setLoading: (isLoading) => set({ isLoading })
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
25
135
|
setLoading?(isLoading: boolean): void;
|
|
26
|
-
|
|
27
|
-
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Fetcher function type for API operations
|
|
139
|
+
* Matches FetchResponse structure from fetchff
|
|
140
|
+
* Uses ServiceOptions from @plyaz/api for config merging
|
|
141
|
+
*/
|
|
142
|
+
export type CoreFetcherFunction<TData = unknown, TResult = unknown, TOptions = unknown> = (data?: TData, options?: TOptions) => Promise<{
|
|
143
|
+
isSuccess: boolean;
|
|
144
|
+
data?: TResult;
|
|
145
|
+
error?: Error | null;
|
|
146
|
+
}>;
|
|
147
|
+
/**
|
|
148
|
+
* Fetchers configuration for frontend services.
|
|
149
|
+
*
|
|
150
|
+
* ## Overview
|
|
151
|
+
* Defines fetcher functions that services use to make API calls.
|
|
152
|
+
* Fetchers wrap the API client and handle request/response transformation.
|
|
153
|
+
*
|
|
154
|
+
* ## Why Fetchers?
|
|
155
|
+
* Services should NEVER call `apiClient.get()`, `apiClient.post()`, etc. directly.
|
|
156
|
+
* Instead, they configure fetchers that:
|
|
157
|
+
* 1. Encapsulate API endpoints
|
|
158
|
+
* 2. Handle request/response formatting
|
|
159
|
+
* 3. Allow for easy mocking in tests
|
|
160
|
+
* 4. Provide type-safe API calls
|
|
161
|
+
*
|
|
162
|
+
* ## Configuration Pattern
|
|
163
|
+
* ```typescript
|
|
164
|
+
* class MyService extends BaseFrontendDomainService<...> {
|
|
165
|
+
* constructor(config: MyServiceConfig) {
|
|
166
|
+
* super({
|
|
167
|
+
* serviceConfig: {
|
|
168
|
+
* fetchers: {
|
|
169
|
+
* fetchAll: async (_, options) =>
|
|
170
|
+
* this.apiClient.get<MyDTO[]>('/api/my-entities'),
|
|
171
|
+
* create: async (data, options) =>
|
|
172
|
+
* this.apiClient.post<MyDTO>('/api/my-entities', data),
|
|
173
|
+
* // ... other fetchers
|
|
174
|
+
* },
|
|
175
|
+
* },
|
|
176
|
+
* // ... other config
|
|
177
|
+
* });
|
|
178
|
+
* }
|
|
179
|
+
* }
|
|
180
|
+
* ```
|
|
181
|
+
*
|
|
182
|
+
* ## Fetcher Function Signature
|
|
183
|
+
* All fetchers return a Promise with this structure:
|
|
184
|
+
* ```typescript
|
|
185
|
+
* Promise<{
|
|
186
|
+
* isSuccess: boolean;
|
|
187
|
+
* data?: TResult;
|
|
188
|
+
* error?: Error | null;
|
|
189
|
+
* }>
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* ## HTTP Methods Supported
|
|
193
|
+
* - **GET** - `fetchAll`, `fetchById` (read operations)
|
|
194
|
+
* - **POST** - `create` (create new entity)
|
|
195
|
+
* - **PUT** - `put` (full entity replacement)
|
|
196
|
+
* - **PATCH** - `update` (partial entity update)
|
|
197
|
+
* - **DELETE** - `delete` (remove entity)
|
|
198
|
+
* - **OPTIONS** - `options` (get allowed methods/CORS headers)
|
|
199
|
+
* - **HEAD** - `head` (get headers only, no body)
|
|
200
|
+
*
|
|
201
|
+
* ## When to Use Each Method
|
|
202
|
+
* - Use `fetchAll` for listing/querying entities
|
|
203
|
+
* - Use `fetchById` for retrieving single entities
|
|
204
|
+
* - Use `create` for POST requests (new entities)
|
|
205
|
+
* - Use `update` for PATCH requests (most common for updates)
|
|
206
|
+
* - Use `put` for full replacements (less common)
|
|
207
|
+
* - Use `delete` for removing entities
|
|
208
|
+
*
|
|
209
|
+
* @typeParam TEntity - Domain entity type (internal representation)
|
|
210
|
+
* @typeParam TResponseDTO - API response DTO type (server format)
|
|
211
|
+
* @typeParam TCreateDTO - Create request DTO type (for POST)
|
|
212
|
+
* @typeParam TPatchDTO - Patch request DTO type (for PATCH)
|
|
213
|
+
* @typeParam TOptions - Options type for fetcher calls (custom config)
|
|
214
|
+
* @typeParam TDeleteResult - Delete response type (default: unknown - can be confirmation, deleted entity, or void)
|
|
215
|
+
*
|
|
216
|
+
* @see {@link CoreFetcherFunction} for the function signature
|
|
217
|
+
* @see {@link BaseFrontendDomainService} for usage in services
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```typescript
|
|
221
|
+
* // Example with all fetchers configured
|
|
222
|
+
* const fetchers: CoreServiceFetchers<
|
|
223
|
+
* Topic,
|
|
224
|
+
* TopicDTO,
|
|
225
|
+
* CreateTopicDTO,
|
|
226
|
+
* PatchTopicDTO,
|
|
227
|
+
* QueryTopicDTO
|
|
228
|
+
* > = {
|
|
229
|
+
* fetchAll: async (query, opts) =>
|
|
230
|
+
* apiClient.get<TopicDTO[]>('/api/topics', { params: query }),
|
|
231
|
+
*
|
|
232
|
+
* fetchById: async (id, opts) =>
|
|
233
|
+
* apiClient.get<TopicDTO>(`/api/topics/${id}`),
|
|
234
|
+
*
|
|
235
|
+
* create: async (data, opts) =>
|
|
236
|
+
* apiClient.post<TopicDTO>('/api/topics', data),
|
|
237
|
+
*
|
|
238
|
+
* update: async ({ id, data }, opts) =>
|
|
239
|
+
* apiClient.patch<TopicDTO>(`/api/topics/${id}`, data),
|
|
240
|
+
*
|
|
241
|
+
* delete: async (id, opts) => {
|
|
242
|
+
* const response = await apiClient.delete(`/api/topics/${id}`);
|
|
243
|
+
* return { ...response, data: { success: true } };
|
|
244
|
+
* },
|
|
245
|
+
* };
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
export interface CoreServiceFetchers<TEntity = unknown, TResponseDTO = unknown, TCreateDTO = unknown, TPatchDTO = unknown, TQueryDTO = unknown, TOptions = unknown, TDeleteResult = unknown> {
|
|
249
|
+
/**
|
|
250
|
+
* Fetch all entities from API (GET).
|
|
251
|
+
*
|
|
252
|
+
* Used by `service.fetchAll(query?)` to retrieve a list/collection.
|
|
253
|
+
*
|
|
254
|
+
* @param query - Optional query/filter parameters (e.g., { status: 'active' })
|
|
255
|
+
* @param options - Optional service options (request config, etc.)
|
|
256
|
+
* @returns Promise with array of DTOs
|
|
257
|
+
*
|
|
258
|
+
* @example
|
|
259
|
+
* ```typescript
|
|
260
|
+
* fetchAll: async (query, opts) =>
|
|
261
|
+
* apiClient.get<TopicDTO[]>('/api/topics', { params: query })
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
fetchAll?: CoreFetcherFunction<Partial<TQueryDTO> | undefined, TResponseDTO[], TOptions>;
|
|
265
|
+
/**
|
|
266
|
+
* Fetch single entity by ID (GET).
|
|
267
|
+
*
|
|
268
|
+
* Used by `service.fetchById(id)` to retrieve one entity.
|
|
269
|
+
*
|
|
270
|
+
* @param data - Entity ID (string)
|
|
271
|
+
* @param options - Optional query params
|
|
272
|
+
* @returns Promise with single DTO
|
|
273
|
+
*
|
|
274
|
+
* @example
|
|
275
|
+
* ```typescript
|
|
276
|
+
* fetchById: async (id, opts) =>
|
|
277
|
+
* apiClient.get<TopicDTO>(`/api/topics/${id}`)
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
fetchById?: CoreFetcherFunction<string, TResponseDTO, TOptions>;
|
|
281
|
+
/**
|
|
282
|
+
* Create new entity (POST).
|
|
283
|
+
*
|
|
284
|
+
* Used by `service.create(data)` to create a new entity.
|
|
285
|
+
*
|
|
286
|
+
* @param data - Create DTO (entity data)
|
|
287
|
+
* @param options - Optional request config
|
|
288
|
+
* @returns Promise with created entity DTO
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* ```typescript
|
|
292
|
+
* create: async (data, opts) =>
|
|
293
|
+
* apiClient.post<TopicDTO>('/api/topics', data)
|
|
294
|
+
* ```
|
|
295
|
+
*/
|
|
296
|
+
create?: CoreFetcherFunction<TCreateDTO, TResponseDTO, TOptions>;
|
|
297
|
+
/**
|
|
298
|
+
* Update entity - full replacement (PUT).
|
|
299
|
+
*
|
|
300
|
+
* Used by `service.put(id, data)` for full entity replacement.
|
|
301
|
+
* Less common than PATCH - only use when API requires full object.
|
|
302
|
+
*
|
|
303
|
+
* @param data - Object with `id` and `data` (full entity)
|
|
304
|
+
* @param options - Optional request config
|
|
305
|
+
* @returns Promise with updated entity DTO
|
|
306
|
+
*
|
|
307
|
+
* @example
|
|
308
|
+
* ```typescript
|
|
309
|
+
* put: async ({ id, data }, opts) =>
|
|
310
|
+
* apiClient.put<TopicDTO>(`/api/topics/${id}`, data)
|
|
311
|
+
* ```
|
|
312
|
+
*/
|
|
313
|
+
put?: CoreFetcherFunction<{
|
|
314
|
+
id: string;
|
|
315
|
+
data: TCreateDTO;
|
|
316
|
+
}, TResponseDTO, TOptions>;
|
|
317
|
+
/**
|
|
318
|
+
* Update entity - partial (PATCH).
|
|
319
|
+
*
|
|
320
|
+
* Used by `service.update(id, data)` for partial updates.
|
|
321
|
+
* Most common update method - only sends changed fields.
|
|
322
|
+
*
|
|
323
|
+
* @param data - Object with `id` and `data` (partial entity)
|
|
324
|
+
* @param options - Optional request config
|
|
325
|
+
* @returns Promise with updated entity DTO
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```typescript
|
|
329
|
+
* update: async ({ id, data }, opts) =>
|
|
330
|
+
* apiClient.patch<TopicDTO>(`/api/topics/${id}`, data)
|
|
331
|
+
* ```
|
|
332
|
+
*/
|
|
333
|
+
update?: CoreFetcherFunction<{
|
|
334
|
+
id: string;
|
|
335
|
+
data: TPatchDTO;
|
|
336
|
+
}, TResponseDTO, TOptions>;
|
|
337
|
+
/**
|
|
338
|
+
* Delete entity (DELETE).
|
|
339
|
+
*
|
|
340
|
+
* Used by `service.delete(id)` to remove an entity.
|
|
341
|
+
* Can return success confirmation, deleted entity, or void.
|
|
342
|
+
*
|
|
343
|
+
* @param data - Entity ID (string)
|
|
344
|
+
* @param options - Optional request config (e.g., soft delete flag)
|
|
345
|
+
* @returns Promise with delete result (confirmation, deleted entity, or void)
|
|
346
|
+
*
|
|
347
|
+
* @example
|
|
348
|
+
* ```typescript
|
|
349
|
+
* // Example 1: Return confirmation object
|
|
350
|
+
* delete: async (id, opts) => {
|
|
351
|
+
* const response = await apiClient.delete(`/api/topics/${id}`);
|
|
352
|
+
* return { ...response, data: { success: true, message: 'Deleted' } };
|
|
353
|
+
* }
|
|
354
|
+
*
|
|
355
|
+
* // Example 2: Return deleted entity
|
|
356
|
+
* delete: async (id, opts) =>
|
|
357
|
+
* apiClient.delete<TopicDTO>(`/api/topics/${id}`) // Server returns deleted entity
|
|
358
|
+
*
|
|
359
|
+
* // Example 3: Return void (204 No Content)
|
|
360
|
+
* delete: async (id, opts) => {
|
|
361
|
+
* const response = await apiClient.delete(`/api/topics/${id}`);
|
|
362
|
+
* return { ...response, data: undefined };
|
|
363
|
+
* }
|
|
364
|
+
* ```
|
|
365
|
+
*/
|
|
366
|
+
delete?: CoreFetcherFunction<string, TDeleteResult, TOptions>;
|
|
367
|
+
/**
|
|
368
|
+
* Options request (OPTIONS).
|
|
369
|
+
*
|
|
370
|
+
* Used to discover allowed HTTP methods and CORS headers.
|
|
371
|
+
* Rarely implemented in domain services.
|
|
372
|
+
*
|
|
373
|
+
* @param data - Optional URL or resource identifier
|
|
374
|
+
* @param options - Optional request config
|
|
375
|
+
* @returns Promise with allowed methods/headers metadata
|
|
376
|
+
*/
|
|
377
|
+
options?: CoreFetcherFunction<string | undefined, unknown, TOptions>;
|
|
378
|
+
/**
|
|
379
|
+
* Head request (HEAD).
|
|
380
|
+
*
|
|
381
|
+
* Used to get headers without response body (e.g., check if resource exists).
|
|
382
|
+
* Rarely implemented in domain services.
|
|
383
|
+
*
|
|
384
|
+
* @param data - Optional URL or resource identifier
|
|
385
|
+
* @param options - Optional request config
|
|
386
|
+
* @returns Promise with void (only headers, no body)
|
|
387
|
+
*/
|
|
388
|
+
head?: CoreFetcherFunction<string | undefined, void, TOptions>;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Store handlers configuration for customizing store synchronization.
|
|
392
|
+
*
|
|
393
|
+
* ## Overview
|
|
394
|
+
* Allows services to customize how data is synced to Zustand stores.
|
|
395
|
+
* By default, services call `setData()`, `updateData()`, and `setLoading()`.
|
|
396
|
+
* Store handlers let you override this behavior with custom logic.
|
|
397
|
+
*
|
|
398
|
+
* ## Use Cases
|
|
399
|
+
* - **Custom store methods**: Use store-specific methods instead of generic ones
|
|
400
|
+
* - **Disable sync**: Turn off store updates completely for manual control
|
|
401
|
+
* - **Complex transformations**: Transform data before syncing to store
|
|
402
|
+
* - **Deep nested updates**: Update nested paths in store state
|
|
403
|
+
*
|
|
404
|
+
* ## Configuration Pattern
|
|
405
|
+
* ```typescript
|
|
406
|
+
* class MyService extends BaseFrontendDomainService<...> {
|
|
407
|
+
* constructor(config: MyServiceConfig) {
|
|
408
|
+
* super({
|
|
409
|
+
* serviceConfig: {
|
|
410
|
+
* // Custom handlers
|
|
411
|
+
* storeHandlers: {
|
|
412
|
+
* setData: (store, data) => store.setMyCustomItems(data.items),
|
|
413
|
+
* updateData: (store, data) => store.mergeMyItems(data.items),
|
|
414
|
+
* setLoading: (store, isLoading) => store.setIsMyLoading(isLoading),
|
|
415
|
+
* },
|
|
416
|
+
* // Or disable completely
|
|
417
|
+
* // storeHandlers: { disabled: true },
|
|
418
|
+
* },
|
|
419
|
+
* });
|
|
420
|
+
* }
|
|
421
|
+
* }
|
|
422
|
+
* ```
|
|
423
|
+
*
|
|
424
|
+
* ## Default Behavior (if not configured)
|
|
425
|
+
* When `storeHandlers` is not provided, services use:
|
|
426
|
+
* - `store.setData(data)` - for full replacement
|
|
427
|
+
* - `store.updateData(data)` - for partial updates (if available)
|
|
428
|
+
* - `store.setLoading(isLoading)` - for loading state
|
|
429
|
+
*
|
|
430
|
+
* ## Disabling Store Sync
|
|
431
|
+
* Set `disabled: true` to prevent all store updates.
|
|
432
|
+
* Useful for services that manage state manually or use different patterns.
|
|
433
|
+
*
|
|
434
|
+
* @typeParam TStore - Store interface type
|
|
435
|
+
* @typeParam TData - Data type for store sync
|
|
436
|
+
*
|
|
437
|
+
* @see {@link CoreBaseFrontendStore} for store interface
|
|
438
|
+
* @see {@link CoreBaseFrontendServiceConfig} for service configuration
|
|
439
|
+
*
|
|
440
|
+
* @example
|
|
441
|
+
* ```typescript
|
|
442
|
+
* // Example 1: Custom store methods
|
|
443
|
+
* const handlers: CoreStoreHandlers<CampaignStoreData, CampaignStore> = {
|
|
444
|
+
* setData: (store, data) => store.setCampaigns(data.campaigns),
|
|
445
|
+
* updateData: (store, data) => store.mergeCampaigns(data.campaigns),
|
|
446
|
+
* setLoading: (store, isLoading) => store.setIsCampaignsLoading(isLoading),
|
|
447
|
+
* };
|
|
448
|
+
*
|
|
449
|
+
* // Example 2: Disable store sync
|
|
450
|
+
* const handlers: CoreStoreHandlers<MyData, MyStore> = {
|
|
451
|
+
* disabled: true,
|
|
452
|
+
* };
|
|
453
|
+
*
|
|
454
|
+
* // Example 3: Complex transformation
|
|
455
|
+
* const handlers: CoreStoreHandlers<TopicStoreData, TopicStore> = {
|
|
456
|
+
* setData: (store, data) => {
|
|
457
|
+
* // Transform data before syncing
|
|
458
|
+
* const sorted = [...data.topics].sort((a, b) => a.order - b.order);
|
|
459
|
+
* store.setTopics(sorted);
|
|
460
|
+
* store.setLastSync(new Date());
|
|
461
|
+
* },
|
|
462
|
+
* };
|
|
463
|
+
* ```
|
|
464
|
+
*/
|
|
465
|
+
export interface CoreStoreHandlers<TData = Record<string, unknown>, TStore extends CoreBaseFrontendStore<TData> = CoreBaseFrontendStore<TData>> {
|
|
466
|
+
/**
|
|
467
|
+
* Disable all store synchronization.
|
|
468
|
+
*
|
|
469
|
+
* When true, the service will not call any store methods.
|
|
470
|
+
* Useful for manual state management or non-reactive patterns.
|
|
471
|
+
*
|
|
472
|
+
* @default false
|
|
473
|
+
*/
|
|
474
|
+
disabled?: boolean;
|
|
475
|
+
/**
|
|
476
|
+
* Custom handler for setting full data.
|
|
477
|
+
*
|
|
478
|
+
* Replaces the default `store.setData(data)` call.
|
|
479
|
+
* Called during `fetchAll()` and other operations that replace full state.
|
|
480
|
+
*
|
|
481
|
+
* @param store - Store instance
|
|
482
|
+
* @param data - Full data to set
|
|
483
|
+
*
|
|
484
|
+
* @example
|
|
485
|
+
* ```typescript
|
|
486
|
+
* setData: (store, data) => {
|
|
487
|
+
* store.setItems(data.items);
|
|
488
|
+
* store.setLastFetch(Date.now());
|
|
489
|
+
* }
|
|
490
|
+
* ```
|
|
491
|
+
*/
|
|
492
|
+
setData?: (store: TStore, data: TData) => void;
|
|
493
|
+
/**
|
|
494
|
+
* Custom handler for partial data updates.
|
|
495
|
+
*
|
|
496
|
+
* Replaces the default `store.updateData(data)` call.
|
|
497
|
+
* Called during operations that merge/update partial state.
|
|
498
|
+
*
|
|
499
|
+
* @param store - Store instance
|
|
500
|
+
* @param data - Partial data to merge
|
|
501
|
+
*
|
|
502
|
+
* @example
|
|
503
|
+
* ```typescript
|
|
504
|
+
* updateData: (store, data) => {
|
|
505
|
+
* if (data.items) store.mergeItems(data.items);
|
|
506
|
+
* if (data.selectedId) store.setSelectedId(data.selectedId);
|
|
507
|
+
* }
|
|
508
|
+
* ```
|
|
509
|
+
*/
|
|
510
|
+
updateData?: (store: TStore, data: Partial<TData>) => void;
|
|
511
|
+
/**
|
|
512
|
+
* Custom handler for loading state.
|
|
513
|
+
*
|
|
514
|
+
* Replaces the default `store.setLoading(isLoading)` call.
|
|
515
|
+
* Called before and after all CRUD operations.
|
|
516
|
+
*
|
|
517
|
+
* @param store - Store instance
|
|
518
|
+
* @param isLoading - Loading state
|
|
519
|
+
*
|
|
520
|
+
* @example
|
|
521
|
+
* ```typescript
|
|
522
|
+
* setLoading: (store, isLoading) => {
|
|
523
|
+
* store.setIsItemsLoading(isLoading);
|
|
524
|
+
* if (isLoading) store.clearError();
|
|
525
|
+
* }
|
|
526
|
+
* ```
|
|
527
|
+
*/
|
|
528
|
+
setLoading?: (store: TStore, isLoading: boolean) => void;
|
|
28
529
|
}
|
|
29
530
|
/**
|
|
30
531
|
* Configuration for frontend domain services
|
|
@@ -40,6 +541,31 @@ export interface CoreBaseFrontendServiceConfig<TData = Record<string, unknown>,
|
|
|
40
541
|
* If not specified, no stores are connected (warning logged).
|
|
41
542
|
*/
|
|
42
543
|
storeKeys?: StoreKey[];
|
|
544
|
+
/** API base path for endpoints (e.g., '/api/examples') */
|
|
545
|
+
apiBasePath?: string;
|
|
546
|
+
/** Fetcher functions for API operations (replaces direct apiClient usage) */
|
|
547
|
+
fetchers?: CoreServiceFetchers<unknown, unknown, unknown, unknown, unknown, unknown, unknown>;
|
|
548
|
+
/**
|
|
549
|
+
* Store handlers for customizing store synchronization.
|
|
550
|
+
*
|
|
551
|
+
* Allows services to override default store sync behavior with custom logic.
|
|
552
|
+
* Useful for custom store methods, complex transformations, or disabling sync.
|
|
553
|
+
*
|
|
554
|
+
* @see {@link CoreStoreHandlers} for configuration options
|
|
555
|
+
*
|
|
556
|
+
* @example
|
|
557
|
+
* ```typescript
|
|
558
|
+
* // Custom handlers
|
|
559
|
+
* storeHandlers: {
|
|
560
|
+
* setData: (store, data) => store.setCustomItems(data.items),
|
|
561
|
+
* updateData: (store, data) => store.mergeCustomItems(data.items),
|
|
562
|
+
* }
|
|
563
|
+
*
|
|
564
|
+
* // Disable sync
|
|
565
|
+
* storeHandlers: { disabled: true }
|
|
566
|
+
* ```
|
|
567
|
+
*/
|
|
568
|
+
storeHandlers?: CoreStoreHandlers<TData, TStore>;
|
|
43
569
|
}
|
|
44
570
|
/**
|
|
45
571
|
* Base interface for frontend domain services with store integration.
|
|
@@ -193,7 +719,17 @@ export interface CoreFeatureFlagStoreInitConfig {
|
|
|
193
719
|
* Base service config for frontend services (constructor config)
|
|
194
720
|
*/
|
|
195
721
|
export interface CoreBaseFrontendServiceConstructorConfig<TConfig extends CoreBaseFrontendServiceConfig<TData, TStore>, TStore extends CoreBaseFrontendStore<TData>, TData = Record<string, unknown>, TMapper extends CoreBaseMapperInstance = CoreBaseMapperInstance, TValidator extends CoreBaseValidatorInstance = CoreBaseValidatorInstance> extends CoreBaseServiceConfig<TConfig, TMapper, TValidator> {
|
|
196
|
-
/**
|
|
722
|
+
/**
|
|
723
|
+
* Data key used for store sync - indicates which property in the store contains the primary data.
|
|
724
|
+
*
|
|
725
|
+
* Examples:
|
|
726
|
+
* - For feature flags: 'flags' (store has flags property)
|
|
727
|
+
* - For items/entities: 'items' (store has items property)
|
|
728
|
+
* - For nested data: 'nested.items' (store has nested.items)
|
|
729
|
+
*
|
|
730
|
+
* This is used as metadata and for potential helper methods.
|
|
731
|
+
* For custom sync behavior, use `storeHandlers` in serviceConfig instead.
|
|
732
|
+
*/
|
|
197
733
|
storeDataKey?: string;
|
|
198
734
|
}
|
|
199
735
|
/**
|
package/dist/core/index.d.ts
CHANGED
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* Core Init Types
|
|
3
3
|
* Service registry and initialization type definitions
|
|
4
4
|
*/
|
|
5
|
-
export type { CoreDomainServiceInstance, CoreServiceInitConfig, CoreServiceCreateOptions, CoreInitializableDomainService, CoreServiceEntry, CoreServiceRegistryConfig, CoreExtractServiceConfig, CoreExtractServiceInstance, CoreFeatureFlagInitConfig, CoreErrorHandlerInitConfig, CoreInitOptionsBase, CoreServicesResultBase, } from './types';
|
|
5
|
+
export type { CoreDomainServiceInstance, CoreServiceInitConfig, CoreServiceCreateOptions, CoreInitializableDomainService, CoreServiceEntry, CoreServiceRegistryConfig, CoreExtractServiceConfig, CoreExtractServiceInstance, CoreFeatureFlagInitConfig, CoreErrorHandlerInitConfig, CoreCacheConfig, CoreInitOptionsBase, CoreServicesResultBase, } from './types';
|