@plyaz/types 1.22.9 → 1.23.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.
@@ -180,3 +180,188 @@ export interface CoreBaseBackendServiceConfig extends CoreBaseDomainServiceConfi
180
180
  defaultTtl?: number;
181
181
  };
182
182
  }
183
+ /**
184
+ * Base interface for service type bundles.
185
+ * Define your concrete types by implementing this interface.
186
+ *
187
+ * This reduces the number of generic parameters from 13 to 5:
188
+ * - TConfig (service config)
189
+ * - TTypes (this bundle)
190
+ * - TRepository
191
+ * - TMapper
192
+ * - TValidator
193
+ *
194
+ * @example
195
+ * ```typescript
196
+ * // Define your service types bundle (no extends needed!)
197
+ * interface UserServiceTypes {
198
+ * Entity: User;
199
+ * ResponseDTO: UserResponseDTO;
200
+ * CreateDTO: CreateUserDTO;
201
+ * UpdateDTO: UpdateUserDTO;
202
+ * PatchDTO: PatchUserDTO;
203
+ * QueryDTO: QueryUserDTO;
204
+ * DeleteOptions: { soft: boolean };
205
+ * DatabaseRow: UserDatabaseRow;
206
+ * StoreState: UserStoreItem;
207
+ * }
208
+ *
209
+ * // Use in service (5 generics instead of 13!)
210
+ * class UserService extends BaseBackendDomainServiceV2<
211
+ * UserServiceConfig,
212
+ * UserServiceTypes,
213
+ * UserRepository,
214
+ * UserMapper,
215
+ * UserValidator
216
+ * > {}
217
+ * ```
218
+ */
219
+ export interface BackendServiceTypesShape {
220
+ /** Domain entity type */
221
+ Entity: unknown;
222
+ /** API response DTO type */
223
+ ResponseDTO: unknown;
224
+ /** Create input DTO type (POST body) - must be Record<string, unknown> */
225
+ CreateDTO: Record<string, unknown>;
226
+ /** Update input DTO type (PUT body) - must be Record<string, unknown> */
227
+ UpdateDTO: Record<string, unknown>;
228
+ /** Patch input DTO type (PATCH body) */
229
+ PatchDTO: Partial<Record<string, unknown>>;
230
+ /** Query params DTO type */
231
+ QueryDTO: Record<string, unknown>;
232
+ /** Delete options type */
233
+ DeleteOptions: unknown;
234
+ /** Database row type - must be Record<string, unknown> */
235
+ DatabaseRow: Record<string, unknown>;
236
+ /** Store state type (serializable) */
237
+ StoreState: unknown;
238
+ }
239
+ /**
240
+ * Frontend service types shape (without database-specific types)
241
+ */
242
+ export interface FrontendServiceTypesShape {
243
+ /** Domain entity type */
244
+ Entity: unknown;
245
+ /** API response DTO type */
246
+ ResponseDTO: unknown;
247
+ /** Create input DTO type */
248
+ CreateDTO: unknown;
249
+ /** Update input DTO type */
250
+ UpdateDTO: unknown;
251
+ /** Patch input DTO type */
252
+ PatchDTO: unknown;
253
+ /** Query params DTO type */
254
+ QueryDTO: unknown;
255
+ /** Store state type */
256
+ StoreState: unknown;
257
+ }
258
+ /**
259
+ * Helper to create a backend service types bundle with defaults.
260
+ * Use this when you want type inference with sensible defaults.
261
+ *
262
+ * @example
263
+ * ```typescript
264
+ * type UserTypes = DefineBackendServiceTypes<{
265
+ * Entity: User;
266
+ * ResponseDTO: UserResponseDTO;
267
+ * CreateDTO: CreateUserDTO;
268
+ * // UpdateDTO defaults to CreateDTO
269
+ * // PatchDTO defaults to Partial<CreateDTO>
270
+ * QueryDTO: QueryUserDTO;
271
+ * DatabaseRow: UserDatabaseRow;
272
+ * }>;
273
+ * ```
274
+ */
275
+ export type DefineBackendServiceTypes<T extends Partial<BackendServiceTypesShape> & {
276
+ Entity: unknown;
277
+ CreateDTO: Record<string, unknown>;
278
+ }> = {
279
+ Entity: T['Entity'];
280
+ ResponseDTO: T extends {
281
+ ResponseDTO: infer R;
282
+ } ? R : T['Entity'];
283
+ CreateDTO: T['CreateDTO'];
284
+ UpdateDTO: T extends {
285
+ UpdateDTO: infer U;
286
+ } ? U : T['CreateDTO'];
287
+ PatchDTO: T extends {
288
+ PatchDTO: infer P;
289
+ } ? P : Partial<T['CreateDTO']>;
290
+ QueryDTO: T extends {
291
+ QueryDTO: infer Q;
292
+ } ? Q : Record<string, unknown>;
293
+ DeleteOptions: T extends {
294
+ DeleteOptions: infer D;
295
+ } ? D : {
296
+ soft: boolean;
297
+ };
298
+ DatabaseRow: T extends {
299
+ DatabaseRow: infer DB;
300
+ } ? DB : T['CreateDTO'] & {
301
+ id: string;
302
+ };
303
+ StoreState: T extends {
304
+ StoreState: infer S;
305
+ } ? S : T['Entity'];
306
+ };
307
+ /**
308
+ * Helper to create a frontend service types bundle with defaults.
309
+ */
310
+ export type DefineFrontendServiceTypes<T extends Partial<FrontendServiceTypesShape> & {
311
+ Entity: unknown;
312
+ }> = {
313
+ Entity: T['Entity'];
314
+ ResponseDTO: T extends {
315
+ ResponseDTO: infer R;
316
+ } ? R : T['Entity'];
317
+ CreateDTO: T extends {
318
+ CreateDTO: infer C;
319
+ } ? C : Record<string, unknown>;
320
+ UpdateDTO: T extends {
321
+ UpdateDTO: infer U;
322
+ } ? U : T extends {
323
+ CreateDTO: infer C;
324
+ } ? C : Record<string, unknown>;
325
+ PatchDTO: T extends {
326
+ PatchDTO: infer P;
327
+ } ? P : Partial<T extends {
328
+ CreateDTO: infer C;
329
+ } ? C : Record<string, unknown>>;
330
+ QueryDTO: T extends {
331
+ QueryDTO: infer Q;
332
+ } ? Q : Record<string, unknown>;
333
+ StoreState: T extends {
334
+ StoreState: infer S;
335
+ } ? S : T['Entity'];
336
+ };
337
+ /**
338
+ * Type-safe extraction helpers for service type bundles.
339
+ * These work with any object that has the expected shape.
340
+ */
341
+ export type ExtractEntity<T extends {
342
+ Entity: unknown;
343
+ }> = T['Entity'];
344
+ export type ExtractResponseDTO<T extends {
345
+ ResponseDTO: unknown;
346
+ }> = T['ResponseDTO'];
347
+ export type ExtractCreateDTO<T extends {
348
+ CreateDTO: unknown;
349
+ }> = T['CreateDTO'];
350
+ export type ExtractUpdateDTO<T extends {
351
+ UpdateDTO: unknown;
352
+ }> = T['UpdateDTO'];
353
+ export type ExtractPatchDTO<T extends {
354
+ PatchDTO: unknown;
355
+ }> = T['PatchDTO'];
356
+ export type ExtractQueryDTO<T extends {
357
+ QueryDTO: unknown;
358
+ }> = T['QueryDTO'];
359
+ export type ExtractDeleteOptions<T extends {
360
+ DeleteOptions: unknown;
361
+ }> = T['DeleteOptions'];
362
+ export type ExtractDatabaseRow<T extends {
363
+ DatabaseRow: unknown;
364
+ }> = T['DatabaseRow'];
365
+ export type ExtractStoreState<T extends {
366
+ StoreState: unknown;
367
+ }> = T['StoreState'];
@@ -2,5 +2,5 @@
2
2
  * Core Frontend Types
3
3
  * Type definitions for @plyaz/core frontend services
4
4
  */
5
- export type { CoreBaseFrontendStore, CoreBaseFrontendServiceConfig, CoreBaseFrontendServiceInterface, CoreStoreHandlers, CoreFetcherFunction, CoreServiceFetchers, CorePlyazApiConfig, FrontendFeatureFlagProvider, CorePlyazFeatureFlagConfig, CorePlyazStoreConfig, CorePlyazConfig, CoreFeatureFlagServiceLike, CoreFeatureFlagFetcherOptions, CoreFeatureFlagStoreInitConfig, CoreBaseFrontendServiceConstructorConfig, CoreInitializationErrorProps, CoreInitializationLoadingProps, CorePlyazServices, CorePlyazContextValue, CorePlyazProviderProps, } from './types';
5
+ export type { CoreBaseFrontendStore, CoreBaseFrontendServiceConfig, CoreBaseFrontendServiceInterface, CoreStoreHandlers, CoreOptimisticUpdateConfig, OptimisticConflictResolution, CoreFetcherFunction, CoreServiceFetchers, CorePlyazApiConfig, FrontendFeatureFlagProvider, CorePlyazFeatureFlagConfig, CorePlyazStoreConfig, CorePlyazConfig, CoreFeatureFlagServiceLike, CoreFeatureFlagFetcherOptions, CoreFeatureFlagStoreInitConfig, CoreBaseFrontendServiceConstructorConfig, CoreInitializationErrorProps, CoreInitializationLoadingProps, CorePlyazServices, CorePlyazContextValue, CorePlyazProviderProps, } from './types';
6
6
  export type { CoreFrontendFeatureFlagEventType, CoreFeatureFlagStore, CoreFeatureFlagServiceConfig, CoreFeatureFlagServiceInitConfig, CoreFeatureFlagServiceInterface, } from './featureFlags';
@@ -638,6 +638,68 @@ export interface CoreStoreHandlers<TData = Record<string, unknown>, TStore exten
638
638
  */
639
639
  removeData?: (store: TStore, id: string) => void;
640
640
  }
641
+ /**
642
+ * Conflict resolution strategy for optimistic updates
643
+ */
644
+ export type OptimisticConflictResolution = 'server-wins' | 'client-wins' | 'merge' | 'manual';
645
+ /**
646
+ * Optimistic update configuration
647
+ *
648
+ * When enabled, store updates happen immediately before API call completes.
649
+ * If the API call fails, changes are rolled back automatically.
650
+ *
651
+ * @example
652
+ * ```typescript
653
+ * optimisticUpdates: {
654
+ * enabled: true,
655
+ * rollbackOnError: true,
656
+ * conflictResolution: 'server-wins',
657
+ * }
658
+ * ```
659
+ */
660
+ export interface CoreOptimisticUpdateConfig {
661
+ /**
662
+ * Enable optimistic updates for CRUD operations.
663
+ * When true, store is updated before API response.
664
+ * @default false
665
+ */
666
+ enabled?: boolean;
667
+ /**
668
+ * Automatically rollback on API error.
669
+ * When true, reverts store to previous state if API fails.
670
+ * @default true
671
+ */
672
+ rollbackOnError?: boolean;
673
+ /**
674
+ * How to resolve conflicts when server response differs from optimistic state.
675
+ * - 'server-wins': Always use server response (default, safest)
676
+ * - 'client-wins': Keep client changes, ignore server differences
677
+ * - 'merge': Deep merge server and client data
678
+ * - 'manual': Call onConflict handler for resolution
679
+ * @default 'server-wins'
680
+ */
681
+ conflictResolution?: OptimisticConflictResolution;
682
+ /**
683
+ * Delay before applying optimistic update (ms).
684
+ * Useful for debouncing rapid updates.
685
+ * @default 0
686
+ */
687
+ debounceMs?: number;
688
+ /**
689
+ * Operations to enable optimistic updates for.
690
+ * @default ['create', 'update', 'delete']
691
+ */
692
+ operations?: ('create' | 'update' | 'delete')[];
693
+ /**
694
+ * Called when conflict detected (only when conflictResolution is 'manual').
695
+ * Return the resolved data to use.
696
+ */
697
+ onConflict?: <T>(optimistic: T, server: T) => T;
698
+ /**
699
+ * Called when rollback occurs due to error.
700
+ */
701
+ onRollback?: (operation: string, error: Error, previousState: unknown) => void;
702
+ }
641
703
  /**
642
704
  * Configuration for frontend domain services
643
705
  */
@@ -684,6 +746,24 @@ export interface CoreBaseFrontendServiceConfig<TData = Record<string, unknown>,
684
746
  * ```
685
747
  */
686
748
  storeHandlers?: CoreStoreHandlers<TData, TStore>;
749
+ /**
750
+ * Optimistic update configuration.
751
+ *
752
+ * When enabled, store updates happen immediately before API completes.
753
+ * If API fails, changes are automatically rolled back.
754
+ *
755
+ * @see {@link CoreOptimisticUpdateConfig} for options
756
+ *
757
+ * @example
758
+ * ```typescript
759
+ * optimisticUpdates: {
760
+ * enabled: true,
761
+ * rollbackOnError: true,
762
+ * conflictResolution: 'server-wins',
763
+ * }
764
+ * ```
765
+ */
766
+ optimisticUpdates?: CoreOptimisticUpdateConfig;
687
767
  }
688
768
  /**
689
769
  * Base interface for frontend domain services with store integration.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plyaz/types",
3
- "version": "1.22.9",
3
+ "version": "1.23.0",
4
4
  "author": "Redeemer Pace",
5
5
  "license": "ISC",
6
6
  "description": "Provides shared TypeScript types and schema utilities for validation and parsing in the @playz ecosystem.",