reslib 1.0.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.
Files changed (200) hide show
  1. package/README.md +298 -0
  2. package/build/auth/index.d.ts +2034 -0
  3. package/build/auth/index.js +5 -0
  4. package/build/auth/types.d.ts +465 -0
  5. package/build/auth/types.js +1 -0
  6. package/build/countries/countries.d.ts +1454 -0
  7. package/build/countries/countries.js +1 -0
  8. package/build/countries/index.d.ts +159 -0
  9. package/build/countries/index.js +5 -0
  10. package/build/countries/types.d.ts +65 -0
  11. package/build/countries/types.js +1 -0
  12. package/build/currency/currencies.d.ts +8 -0
  13. package/build/currency/currencies.js +1 -0
  14. package/build/currency/index.d.ts +51 -0
  15. package/build/currency/index.js +5 -0
  16. package/build/currency/session.d.ts +23 -0
  17. package/build/currency/session.js +5 -0
  18. package/build/currency/types.d.ts +1039 -0
  19. package/build/currency/types.js +1 -0
  20. package/build/currency/utils.d.ts +25 -0
  21. package/build/currency/utils.js +1 -0
  22. package/build/i18n/index.d.ts +640 -0
  23. package/build/i18n/index.js +5 -0
  24. package/build/inputFormatter/index.d.ts +396 -0
  25. package/build/inputFormatter/index.js +5 -0
  26. package/build/inputFormatter/types.d.ts +544 -0
  27. package/build/inputFormatter/types.js +1 -0
  28. package/build/logger/index.d.ts +235 -0
  29. package/build/logger/index.js +5 -0
  30. package/build/observable/index.d.ts +329 -0
  31. package/build/observable/index.js +1 -0
  32. package/build/platform/index.d.ts +32 -0
  33. package/build/platform/index.js +1 -0
  34. package/build/resources/ResourcePaginationHelper.d.ts +537 -0
  35. package/build/resources/ResourcePaginationHelper.js +2 -0
  36. package/build/resources/decorators/create.decorator.d.ts +20 -0
  37. package/build/resources/decorators/create.decorator.js +1 -0
  38. package/build/resources/decorators/index.d.ts +41 -0
  39. package/build/resources/decorators/index.js +1 -0
  40. package/build/resources/fields/index.d.ts +33 -0
  41. package/build/resources/fields/index.js +1 -0
  42. package/build/resources/filters.d.ts +62 -0
  43. package/build/resources/filters.js +1 -0
  44. package/build/resources/index.d.ts +854 -0
  45. package/build/resources/index.js +6 -0
  46. package/build/resources/types/filters.d.ts +508 -0
  47. package/build/resources/types/filters.js +1 -0
  48. package/build/resources/types/index.d.ts +4138 -0
  49. package/build/resources/types/index.js +1 -0
  50. package/build/session/index.d.ts +1474 -0
  51. package/build/session/index.js +1 -0
  52. package/build/translations/auth.en.d.ts +3 -0
  53. package/build/translations/auth.en.js +1 -0
  54. package/build/translations/countries.en.d.ts +6 -0
  55. package/build/translations/countries.en.js +1 -0
  56. package/build/translations/currencies.en.d.ts +5 -0
  57. package/build/translations/currencies.en.js +1 -0
  58. package/build/translations/date.en.d.ts +19 -0
  59. package/build/translations/date.en.js +1 -0
  60. package/build/translations/index.d.ts +1583 -0
  61. package/build/translations/index.js +5 -0
  62. package/build/translations/resources.en.d.ts +6 -0
  63. package/build/translations/resources.en.js +1 -0
  64. package/build/translations/validator.en.d.ts +104 -0
  65. package/build/translations/validator.en.js +5 -0
  66. package/build/types/date.d.ts +44 -0
  67. package/build/types/date.js +1 -0
  68. package/build/types/dictionary.d.ts +29 -0
  69. package/build/types/dictionary.js +1 -0
  70. package/build/types/i18n.d.ts +121 -0
  71. package/build/types/i18n.js +1 -0
  72. package/build/types/index.d.ts +145 -0
  73. package/build/types/index.js +1 -0
  74. package/build/utils/areEquals.d.ts +19 -0
  75. package/build/utils/areEquals.js +1 -0
  76. package/build/utils/date/dateHelper.d.ts +371 -0
  77. package/build/utils/date/dateHelper.js +5 -0
  78. package/build/utils/date/index.d.ts +212 -0
  79. package/build/utils/date/index.js +5 -0
  80. package/build/utils/date/isDateObj.d.ts +14 -0
  81. package/build/utils/date/isDateObj.js +1 -0
  82. package/build/utils/debounce.d.ts +52 -0
  83. package/build/utils/debounce.js +1 -0
  84. package/build/utils/defaultArray.d.ts +18 -0
  85. package/build/utils/defaultArray.js +1 -0
  86. package/build/utils/defaultBool.d.ts +14 -0
  87. package/build/utils/defaultBool.js +1 -0
  88. package/build/utils/defaultStr.d.ts +17 -0
  89. package/build/utils/defaultStr.js +1 -0
  90. package/build/utils/defaultVal.d.ts +18 -0
  91. package/build/utils/defaultVal.js +1 -0
  92. package/build/utils/dom/index.d.ts +65 -0
  93. package/build/utils/dom/index.js +1 -0
  94. package/build/utils/dom/isDOMElement.d.ts +11 -0
  95. package/build/utils/dom/isDOMElement.js +1 -0
  96. package/build/utils/file/index.d.ts +26 -0
  97. package/build/utils/file/index.js +1 -0
  98. package/build/utils/global.d.ts +53 -0
  99. package/build/utils/global.js +1 -0
  100. package/build/utils/image.d.ts +56 -0
  101. package/build/utils/image.js +1 -0
  102. package/build/utils/index.d.ts +39 -0
  103. package/build/utils/index.js +6 -0
  104. package/build/utils/interpolate.d.ts +105 -0
  105. package/build/utils/interpolate.js +1 -0
  106. package/build/utils/isEmail.d.ts +57 -0
  107. package/build/utils/isEmail.js +1 -0
  108. package/build/utils/isEmpty.d.ts +18 -0
  109. package/build/utils/isEmpty.js +1 -0
  110. package/build/utils/isNonNullString.d.ts +17 -0
  111. package/build/utils/isNonNullString.js +1 -0
  112. package/build/utils/isNullable.d.ts +7 -0
  113. package/build/utils/isNullable.js +1 -0
  114. package/build/utils/isNumber.d.ts +36 -0
  115. package/build/utils/isNumber.js +1 -0
  116. package/build/utils/isPrimitive.d.ts +16 -0
  117. package/build/utils/isPrimitive.js +1 -0
  118. package/build/utils/isPromise.d.ts +14 -0
  119. package/build/utils/isPromise.js +1 -0
  120. package/build/utils/isRegex.d.ts +15 -0
  121. package/build/utils/isRegex.js +1 -0
  122. package/build/utils/isTime.d.ts +18 -0
  123. package/build/utils/isTime.js +1 -0
  124. package/build/utils/json.d.ts +224 -0
  125. package/build/utils/json.js +1 -0
  126. package/build/utils/numbers.d.ts +148 -0
  127. package/build/utils/numbers.js +5 -0
  128. package/build/utils/object.d.ts +567 -0
  129. package/build/utils/object.js +1 -0
  130. package/build/utils/sort.d.ts +67 -0
  131. package/build/utils/sort.js +1 -0
  132. package/build/utils/string.d.ts +165 -0
  133. package/build/utils/string.js +1 -0
  134. package/build/utils/stringify.d.ts +23 -0
  135. package/build/utils/stringify.js +1 -0
  136. package/build/utils/uniqid.d.ts +18 -0
  137. package/build/utils/uniqid.js +1 -0
  138. package/build/utils/uri/index.d.ts +333 -0
  139. package/build/utils/uri/index.js +2 -0
  140. package/build/validator/index.d.ts +4 -0
  141. package/build/validator/index.js +6 -0
  142. package/build/validator/rules/array.d.ts +848 -0
  143. package/build/validator/rules/array.js +5 -0
  144. package/build/validator/rules/boolean.d.ts +87 -0
  145. package/build/validator/rules/boolean.js +5 -0
  146. package/build/validator/rules/date.d.ts +551 -0
  147. package/build/validator/rules/date.js +5 -0
  148. package/build/validator/rules/default.d.ts +367 -0
  149. package/build/validator/rules/default.js +5 -0
  150. package/build/validator/rules/enum.d.ts +155 -0
  151. package/build/validator/rules/enum.js +5 -0
  152. package/build/validator/rules/file.d.ts +356 -0
  153. package/build/validator/rules/file.js +5 -0
  154. package/build/validator/rules/format.d.ts +2825 -0
  155. package/build/validator/rules/format.js +6 -0
  156. package/build/validator/rules/index.d.ts +16 -0
  157. package/build/validator/rules/index.js +6 -0
  158. package/build/validator/rules/multiRules.d.ts +475 -0
  159. package/build/validator/rules/multiRules.js +5 -0
  160. package/build/validator/rules/numeric.d.ts +1135 -0
  161. package/build/validator/rules/numeric.js +5 -0
  162. package/build/validator/rules/string.d.ts +504 -0
  163. package/build/validator/rules/string.js +5 -0
  164. package/build/validator/rules/target.d.ts +137 -0
  165. package/build/validator/rules/target.js +5 -0
  166. package/build/validator/rules/utils.d.ts +1 -0
  167. package/build/validator/rules/utils.js +1 -0
  168. package/build/validator/rulesMarkers.d.ts +11 -0
  169. package/build/validator/rulesMarkers.js +1 -0
  170. package/build/validator/types.d.ts +2906 -0
  171. package/build/validator/types.js +1 -0
  172. package/build/validator/validator.d.ts +3692 -0
  173. package/build/validator/validator.js +5 -0
  174. package/lib/cjs/auth.js +1 -0
  175. package/lib/cjs/countries.js +1 -0
  176. package/lib/cjs/currency.js +1 -0
  177. package/lib/cjs/i18n.js +1 -0
  178. package/lib/cjs/inputFormatter.js +1 -0
  179. package/lib/cjs/logger.js +1 -0
  180. package/lib/cjs/observable.js +1 -0
  181. package/lib/cjs/platform.js +1 -0
  182. package/lib/cjs/resources.js +1 -0
  183. package/lib/cjs/session.js +1 -0
  184. package/lib/cjs/types.js +1 -0
  185. package/lib/cjs/utils.js +1 -0
  186. package/lib/cjs/validator.js +1 -0
  187. package/lib/esm/auth.mjs +1 -0
  188. package/lib/esm/countries.mjs +1 -0
  189. package/lib/esm/currency.mjs +1 -0
  190. package/lib/esm/i18n.mjs +1 -0
  191. package/lib/esm/inputFormatter.mjs +1 -0
  192. package/lib/esm/logger.mjs +1 -0
  193. package/lib/esm/observable.mjs +1 -0
  194. package/lib/esm/platform.mjs +1 -0
  195. package/lib/esm/resources.mjs +1 -0
  196. package/lib/esm/session.mjs +1 -0
  197. package/lib/esm/types.mjs +1 -0
  198. package/lib/esm/utils.mjs +1 -0
  199. package/lib/esm/validator.mjs +1 -0
  200. package/package.json +244 -0
@@ -0,0 +1,4138 @@
1
+ import { AuthPerm } from '../../auth/types';
2
+ import { InputFormatterOptions } from '../../inputFormatter/types';
3
+ import { Dictionary, UppercaseFirst } from '../../types/dictionary';
4
+ import { MongoQuery, ResourceQueryOrderBy } from './filters';
5
+ export * from './filters';
6
+ export interface FieldBase<TFieldType extends FieldType = FieldType, TValueType = any> extends Partial<ResourceActionTupleObject<ResourceName>>, Omit<InputFormatterOptions<TFieldType, TValueType>, 'value' | 'type'> {
7
+ /**
8
+ * The type of the field.
9
+ *
10
+ * @description
11
+ * This property specifies the type of the field, such as "text", "number", or "date".
12
+ *
13
+ * @default "text"
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const textField: FieldBase = {
18
+ * type: 'text'
19
+ * };
20
+ * ```
21
+ */
22
+ type: TFieldType;
23
+ /**
24
+ * The name of the field.
25
+ *
26
+ * @description
27
+ * This property specifies the unique name or identifier for the field.
28
+ *
29
+ * @example
30
+ * ```typescript
31
+ * const textField: FieldBase = {
32
+ * name: 'textField'
33
+ * };
34
+ * ```
35
+ */
36
+ name?: string;
37
+ /**
38
+ * The name of the field in the database table.
39
+ *
40
+ * @description
41
+ * This property specifies the name of the field as it appears in the database table.
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * const textField: FieldBase = {
46
+ * databaseName: 'text_field'
47
+ * };
48
+ * ```
49
+ */
50
+ databaseName?: string;
51
+ /**
52
+ * The name of the field's table or collection in the database.
53
+ *
54
+ * @description
55
+ * This property specifies the name of the table or collection that contains the field in the database.
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const textField: FieldBase = {
60
+ * databaseTableName: 'text_fields'
61
+ * };
62
+ * ```
63
+ */
64
+ databaseTableName?: string;
65
+ /***
66
+ * weatherr the field is a primary key or not
67
+ */
68
+ primaryKey?: boolean;
69
+ /**
70
+ * weatherr the field is rendable or not
71
+ * It is used to determine if the field should be rendered or not.
72
+ */
73
+ rendable?: boolean;
74
+ /***
75
+ * weatherr the field is readonly or not
76
+ */
77
+ readOnly?: boolean;
78
+ /**
79
+ * weatherr the field is disabled or not
80
+ */
81
+ disabled?: boolean;
82
+ /***
83
+ * weatherr the field is unique for the resource or not
84
+ */
85
+ unique?: boolean;
86
+ /**
87
+ * weatherr the field is required or not
88
+ */
89
+ required?: boolean;
90
+ /***
91
+ * the min length of the field
92
+ */
93
+ minLength?: number;
94
+ /**
95
+ * the max length of the field
96
+ */
97
+ maxLength?: number;
98
+ /**
99
+ * the length of the field
100
+ */
101
+ length?: number;
102
+ /***
103
+ * whether the field is visible or not
104
+ */
105
+ visible?: boolean;
106
+ /***
107
+ * The permission associated with the field. This permission is used to determine if the field will be rendered or not.
108
+ */
109
+ perm?: AuthPerm;
110
+ /**
111
+ * The default value of the field.
112
+ */
113
+ defaultValue?: TValueType;
114
+ }
115
+ /**
116
+ * ## FieldMap Interface
117
+ *
118
+ * A global interface for defining field mappings in the resource system.
119
+ * This interface serves as a central registry for all available field types
120
+ * and their configurations, enabling type-safe field definitions across the application.
121
+ *
122
+ * ### Purpose
123
+ * The `FieldMap` interface is designed for **module augmentation**, allowing developers
124
+ * to extend it with custom field definitions. Each key represents a field type (e.g., "text", "number"),
125
+ * and each value must extend the `FieldBase` interface, ensuring consistent structure
126
+ * and type safety for all field configurations.
127
+ *
128
+ * ### How It Works
129
+ * - **Empty by Design**: The interface is intentionally empty in the core library.
130
+ * - **Module Augmentation**: Developers extend it via `declare module` statements.
131
+ * - **Type Safety**: The `Field<T>` type uses `FieldMap[T]` to enforce that field
132
+ * configurations match their declared types.
133
+ * - **Extensibility**: New field types can be added without modifying the core library.
134
+ *
135
+ * ### Template Parameters
136
+ * This interface doesn't use generic parameters itself, but the values must conform to `FieldBase<TFieldType, ValueType>`.
137
+ *
138
+ * ### Examples
139
+ *
140
+ * #### Basic Module Augmentation
141
+ * ```typescript
142
+ * // In your application's types file (e.g., types.ts or global.d.ts)
143
+ * import "reslib/resources";
144
+ *
145
+ * declare module "reslib/resources/resources" {
146
+ * interface FieldMap {
147
+ * // Define a text field type
148
+ * text: FieldBase<"text", string>;
149
+ *
150
+ * // Define a number field type
151
+ * number: FieldBase<"number", number>;
152
+ *
153
+ * // Define an email field type
154
+ * email: FieldBase<"email", string>;
155
+ * }
156
+ * }
157
+ * ```
158
+ *
159
+ * #### Advanced FieldMeta Configuration
160
+ * ```typescript
161
+ * declare module "reslib/resources/resources" {
162
+ * interface FieldMap {
163
+ * // Text field with validation
164
+ * text: FieldBase<"text", string> & {
165
+ * minLength?: number;
166
+ * maxLength?: number;
167
+ * pattern?: RegExp;
168
+ * };
169
+ *
170
+ * // Number field with range constraints
171
+ * number: FieldBase<"number", number> & {
172
+ * min?: number;
173
+ * max?: number;
174
+ * step?: number;
175
+ * };
176
+ *
177
+ * // Select field with predefined options
178
+ * select: FieldBase<"select", string> & {
179
+ * options: Array<{ label: string; value: string }>;
180
+ * multiple?: boolean;
181
+ * };
182
+ *
183
+ * // Date field with format options
184
+ * date: FieldBase<"date", Date> & {
185
+ * format?: string;
186
+ * minDate?: Date;
187
+ * maxDate?: Date;
188
+ * };
189
+ * }
190
+ * }
191
+ * ```
192
+ *
193
+ * #### Using Defined Fields
194
+ * ```typescript
195
+ * // After augmentation, you can create type-safe fields
196
+ * const userFields: Fields = {
197
+ * username: {
198
+ * type: "text", // ✓ TypeScript knows this is valid
199
+ * name: "username",
200
+ * required: true,
201
+ * minLength: 3, // ✓ Additional properties available
202
+ * maxLength: 50,
203
+ * forCreate: { required: true },
204
+ * forUpdate: { required: false }
205
+ * },
206
+ * age: {
207
+ * type: "number", // ✓ TypeScript knows this is valid
208
+ * name: "age",
209
+ * min: 0, // ✓ Range constraints available
210
+ * max: 150,
211
+ * forFilter: { allowRange: true }
212
+ * },
213
+ * email: {
214
+ * type: "email", // ✓ TypeScript knows this is valid
215
+ * name: "email",
216
+ * required: true,
217
+ * forCreate: { required: true }
218
+ * }
219
+ * };
220
+ *
221
+ * // TypeScript will catch invalid field types:
222
+ * // const invalidField: Field = { type: "invalid" }; // ✗ Error: "invalid" not in FieldMap
223
+ * ```
224
+ *
225
+ * #### Conditional FieldMeta Extensions
226
+ * ```typescript
227
+ * declare module "reslib/resources/resources" {
228
+ * interface FieldMap {
229
+ * // Conditional field that changes behavior based on context
230
+ * conditional: FieldBase<"conditional", any> & {
231
+ * condition: (context: any) => boolean;
232
+ * trueField: keyof FieldMap;
233
+ * falseField: keyof FieldMap;
234
+ * };
235
+ * }
236
+ * }
237
+ * ```
238
+ *
239
+ * ### Best Practices
240
+ * - **Consistent Naming**: Use lowercase strings for field type keys (e.g., "text", "number").
241
+ * - **Extensive Properties**: Add as many type-specific properties as needed for your use case.
242
+ * - **Documentation**: Document custom field types clearly for team members.
243
+ * - **Versioning**: Consider the impact on existing field definitions when adding new properties.
244
+ * - **Validation**: Use TypeScript's type system to enforce field constraints at compile time.
245
+ *
246
+ * ### Integration with Other Types
247
+ * - **Field<T>**: Uses `FieldMap[T]` to create type-safe field configurations.
248
+ * - **FieldType**: Derives from `keyof FieldMap` to constrain valid field types.
249
+ * - **FieldBase**: Provides the base structure that all field definitions must extend.
250
+ *
251
+ * ### Migration Notes
252
+ * If you're upgrading from a version where field types were defined differently,
253
+ * update your module augmentations to use this new structure for better type safety.
254
+ *
255
+ * @interface FieldMap
256
+ * @public
257
+ *
258
+ * @see {@link FieldBase} - The base interface that field definitions must extend
259
+ * @see {@link Field} - How field configurations are created from this map
260
+ * @see {@link FieldType} - The union type of all defined field types
261
+ * @example
262
+ * ```typescript
263
+ * // Complete example of extending FieldMap
264
+ * declare module "reslib/resources/resources" {
265
+ * interface FieldMap {
266
+ * text: FieldBase<"text", string> & {
267
+ * minLength?: number;
268
+ * maxLength?: number;
269
+ * placeholder?: string;
270
+ * };
271
+ *
272
+ * number: FieldBase<"number", number> & {
273
+ * min?: number;
274
+ * max?: number;
275
+ * step?: number;
276
+ * };
277
+ *
278
+ * boolean: FieldBase<"boolean", boolean>;
279
+ *
280
+ * date: FieldBase<"date", Date> & {
281
+ * format?: string;
282
+ * };
283
+ *
284
+ * select: FieldBase<"select", string> & {
285
+ * options: Array<{ label: string; value: any }>;
286
+ * multiple?: boolean;
287
+ * };
288
+ * }
289
+ * }
290
+ * ```
291
+ */
292
+ export interface FieldMap {
293
+ }
294
+ /**
295
+ * ## FieldActionsMap Interface
296
+ *
297
+ * A global interface defining the action contexts available for field configurations.
298
+ * This interface serves as a central registry for all possible field action types
299
+ * that can have different validation rules, requirements, or behaviors.
300
+ *
301
+ * ### Purpose
302
+ * The `FieldActionsMap` interface defines the different contexts in which fields
303
+ * can be used within the resource system. Each key represents an action context
304
+ * (e.g., "create", "update", "filter"), and the corresponding string value is used
305
+ * for type-level operations and transformations.
306
+ *
307
+ * ### How It Works
308
+ * - **Action Contexts**: Defines the different operations where field behavior might differ
309
+ * - **Type Generation**: Used by `Field<T>` to generate action-specific field overrides
310
+ * like `forCreate`, `forUpdate`, `forCreateOrUpdate`, and `forFilter`
311
+ * - **Module Augmentation**: Can be extended via `declare module` for custom action contexts
312
+ * - **String Values**: The string values are primarily used for TypeScript type manipulation
313
+ *
314
+ * ### Default Action Contexts
315
+ *
316
+ * - **create**: FieldMeta configuration when creating new resource instances
317
+ * - **update**: FieldMeta configuration when updating existing resource instances
318
+ * - **createOrUpdate**: FieldMeta configuration for operations that can create or update
319
+ * - **filter**: FieldMeta configuration for filtering/searching resource instances
320
+ *
321
+ * ### Template Parameters
322
+ * This interface doesn't use generic parameters itself, but serves as a foundation
323
+ * for generating action-specific field configurations.
324
+ *
325
+ * ### Examples
326
+ *
327
+ * #### Basic Usage in FieldMeta Definitions
328
+ * ```typescript
329
+ * // Fields can have different configurations for different actions
330
+ * const userFields: Fields = {
331
+ * password: {
332
+ * type: "text",
333
+ * required: true,
334
+ * minLength: 8,
335
+ * // Different requirements for create vs update
336
+ * forCreate: { required: true }, // Password required when creating
337
+ * forUpdate: { required: false } // Password optional when updating
338
+ * },
339
+ * email: {
340
+ * type: "email",
341
+ * required: true,
342
+ * unique: true,
343
+ * // Email validation differs by context
344
+ * forCreate: { required: true, unique: true },
345
+ * forUpdate: { required: true, unique: true },
346
+ * forFilter: { required: false } // Email optional for filtering
347
+ * }
348
+ * };
349
+ * ```
350
+ *
351
+ * #### Module Augmentation for Custom Actions
352
+ * ```typescript
353
+ * // In your application's types file
354
+ * import "reslib/resources/resources";
355
+ *
356
+ * declare module "reslib/resources/resources" {
357
+ * interface FieldActionsMap {
358
+ * // Add custom action contexts
359
+ * import: string; // For bulk import operations
360
+ * export: string; // For data export configurations
361
+ * validate: string; // For validation-only contexts
362
+ * preview: string; // For preview/display contexts
363
+ * }
364
+ * }
365
+ *
366
+ * // Now you can use these in field definitions
367
+ * const productFields: Fields = {
368
+ * sku: {
369
+ * type: "text",
370
+ * required: true,
371
+ * forCreate: { required: true },
372
+ * forUpdate: { required: true },
373
+ * forImport: { required: true, pattern: "^[A-Z0-9]+$" }, // Custom validation for imports
374
+ * forExport: { required: false } // SKU optional in exports
375
+ * }
376
+ * };
377
+ * ```
378
+ *
379
+ * #### Advanced FieldMeta Behavior Overrides
380
+ * ```typescript
381
+ * declare module "reslib/resources/resources" {
382
+ * interface FieldActionsMap {
383
+ * bulkUpdate: string;
384
+ * softDelete: string;
385
+ * archive: string;
386
+ * }
387
+ * }
388
+ *
389
+ * const documentFields: Fields = {
390
+ * status: {
391
+ * type: "select",
392
+ * options: ["draft", "published", "archived"],
393
+ * required: true,
394
+ * forCreate: { required: true, defaultValue: "draft" },
395
+ * forUpdate: { required: true },
396
+ * forBulkUpdate: { required: false }, // Optional in bulk operations
397
+ * forSoftDelete: { readOnly: true }, // Can't change status when soft deleting
398
+ * forArchive: { required: true, allowedValues: ["archived"] } // Only allow archive status
399
+ * },
400
+ * deletedAt: {
401
+ * type: "date",
402
+ * readOnly: true,
403
+ * forSoftDelete: { required: true }, // Must set deletion timestamp
404
+ * forArchive: { required: false } // Optional for archiving
405
+ * }
406
+ * };
407
+ * ```
408
+ *
409
+ * #### Conditional FieldMeta Requirements
410
+ * ```typescript
411
+ * const orderFields: Fields = {
412
+ * paymentMethod: {
413
+ * type: "select",
414
+ * options: ["credit_card", "paypal", "bank_transfer"],
415
+ * forCreate: { required: true },
416
+ * forUpdate: { required: false }, // Can't change payment method after creation
417
+ * forFilter: { required: false }
418
+ * },
419
+ * creditCardNumber: {
420
+ * type: "text",
421
+ * pattern: "^\\d{16}$",
422
+ * forCreate: {
423
+ * required: true,
424
+ * // Only required if payment method is credit card
425
+ * conditionalRequired: (data) => data.paymentMethod === "credit_card"
426
+ * },
427
+ * forUpdate: { readOnly: true }, // Never updatable for security
428
+ * forFilter: { required: false }
429
+ * }
430
+ * };
431
+ * ```
432
+ *
433
+ * ### Best Practices
434
+ * - **Consistent Naming**: Use lowercase action names (e.g., "create", "update")
435
+ * - **Semantic Actions**: Choose action names that clearly describe their purpose
436
+ * - **Minimal Overrides**: Only override field properties when behavior genuinely differs
437
+ * - **Security Considerations**: Use action contexts to enforce security rules
438
+ * (e.g., making fields read-only in certain contexts)
439
+ * - **Documentation**: Document custom action contexts for team members
440
+ *
441
+ * ### Integration with Other Types
442
+ * - **Field<T>**: Uses `FieldActionsMap` to generate action-specific properties
443
+ * - **FieldMap**: Provides the base field configurations that can be overridden
444
+ * - **UppercaseFirst**: Used to transform action names (e.g., "create" → "Create" → "forCreate")
445
+ *
446
+ * ### Migration Notes
447
+ * When adding new action contexts, ensure that existing field definitions are
448
+ * compatible. Consider providing default behaviors for new actions to maintain
449
+ * backward compatibility.
450
+ *
451
+ * @interface FieldActionsMap
452
+ * @public
453
+ *
454
+ * @see {@link Field} - How action contexts are used in field definitions
455
+ * @see {@link FieldMap} - The base field configurations that can be overridden
456
+ * @see {@link UppercaseFirst} - Utility for transforming action names
457
+ * @example
458
+ * ```typescript
459
+ * // Complete example of extending FieldActionsMap
460
+ * declare module "reslib/resources/resources" {
461
+ * interface FieldActionsMap {
462
+ * // Standard CRUD operations
463
+ * create: string;
464
+ * update: string;
465
+ * createOrUpdate: string;
466
+ * filter: string;
467
+ *
468
+ * // Custom business logic actions
469
+ * approve: string; // For approval workflows
470
+ * reject: string; // For rejection workflows
471
+ * publish: string; // For content publishing
472
+ * archive: string; // For archiving operations
473
+ *
474
+ * // Data operations
475
+ * import: string; // For bulk import
476
+ * export: string; // For data export
477
+ * migrate: string; // For data migration
478
+ *
479
+ * // Administrative actions
480
+ * adminUpdate: string; // For admin-only updates
481
+ * systemUpdate: string; // For system-generated updates
482
+ * }
483
+ * }
484
+ *
485
+ * // Usage in field definitions
486
+ * const contentFields: Fields = {
487
+ * publishedAt: {
488
+ * type: "date",
489
+ * readOnly: true,
490
+ * forCreate: { required: false },
491
+ * forPublish: { required: true }, // Must set when publishing
492
+ * forUpdate: { required: false },
493
+ * forAdminUpdate: { required: false } // Admins can modify
494
+ * },
495
+ * approvalStatus: {
496
+ * type: "select",
497
+ * options: ["pending", "approved", "rejected"],
498
+ * defaultValue: "pending",
499
+ * forCreate: { required: false },
500
+ * forApprove: { required: true, allowedValues: ["approved"] },
501
+ * forReject: { required: true, allowedValues: ["rejected"] },
502
+ * forUpdate: { readOnly: true } // Status changes through specific actions
503
+ * }
504
+ * };
505
+ * ```
506
+ */
507
+ export interface FieldActionsMap {
508
+ create: string;
509
+ update: string;
510
+ createOrUpdate: string;
511
+ filter: string;
512
+ }
513
+ /**
514
+ * ## Field Type
515
+ *
516
+ * The core type representing a field configuration in the resource system.
517
+ * This conditional type combines base field properties with action-specific overrides,
518
+ * enabling flexible and type-safe field definitions across different operations.
519
+ *
520
+ * ### Purpose
521
+ * The `Field` type serves as the primary interface for defining fields in resource schemas.
522
+ * It provides a structured way to specify field behavior, validation rules, and operation-specific
523
+ * customizations, ensuring type safety and consistency throughout the application.
524
+ *
525
+ * ### How It Works
526
+ * This type uses TypeScript's conditional types and mapped types to dynamically construct
527
+ * field configurations based on the field type and available actions:
528
+ *
529
+ * 1. **Base Configuration**: Inherits all properties from the specific field type in `FieldMap[T]`
530
+ * 2. **Action Overrides**: Adds optional properties for each action in `FieldActionsMap`
531
+ * 3. **Type Safety**: Ensures only valid field types and action contexts are used
532
+ * 4. **Extensibility**: Supports module augmentation for custom field types and actions
533
+ *
534
+ * ### Template Parameters
535
+ * - **T**: The field type (extends `FieldType`, which is `keyof FieldMap`). Defaults to `FieldType`.
536
+ *
537
+ * ### Type Construction
538
+ * ```typescript
539
+ * Field<T> = FieldMap[T] extends FieldBase
540
+ * ? FieldMap[T] & {
541
+ * [key in keyof FieldActionsMap as `for${UppercaseFirst<key>}`]?: Partial<FieldMap[keyof FieldMap]>
542
+ * }
543
+ * : never
544
+ * ```
545
+ *
546
+ * This creates a type that includes:
547
+ * - All base properties from `FieldMap[T]` (e.g., `type`, `name`, `required`, field-specific properties)
548
+ * - Optional action-specific overrides like `forCreate`, `forUpdate`, `forFilter`, etc.
549
+ *
550
+ * ### Examples
551
+ *
552
+ * #### Basic Field Definition
553
+ * ```typescript
554
+ * // Define a text field with basic properties
555
+ * const usernameField: Field<"text"> = {
556
+ * type: "text",
557
+ * name: "username",
558
+ * required: true,
559
+ * minLength: 3,
560
+ * maxLength: 50,
561
+ * placeholder: "Enter username"
562
+ * };
563
+ * ```
564
+ *
565
+ * #### Field with Action-Specific Overrides
566
+ * ```typescript
567
+ * // Field that behaves differently for different actions
568
+ * const passwordField: Field<"text"> = {
569
+ * type: "text",
570
+ * name: "password",
571
+ * // Base configuration
572
+ * minLength: 8,
573
+ * pattern: "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$",
574
+ *
575
+ * // Action-specific overrides
576
+ * forCreate: {
577
+ * required: true, // Password required when creating
578
+ * minLength: 8 // Minimum length for creation
579
+ * },
580
+ * forUpdate: {
581
+ * required: false, // Password optional when updating
582
+ * minLength: 0 // No minimum when updating (keep existing)
583
+ * },
584
+ * forFilter: {
585
+ * required: false, // Not used in filtering
586
+ * minLength: 0
587
+ * }
588
+ * };
589
+ * ```
590
+ *
591
+ * #### Complex Field with Multiple Overrides
592
+ * ```typescript
593
+ * const statusField: Field<"select"> = {
594
+ * type: "select",
595
+ * name: "status",
596
+ * required: true,
597
+ * options: ["draft", "published", "archived"],
598
+ * defaultValue: "draft",
599
+ *
600
+ * // Different validation rules per action
601
+ * forCreate: {
602
+ * required: false, // Optional during creation
603
+ * defaultValue: "draft" // Default to draft
604
+ * },
605
+ * forUpdate: {
606
+ * required: true, // Required during updates
607
+ * allowedValues: ["published", "archived"] // Can't go back to draft
608
+ * },
609
+ * forFilter: {
610
+ * required: false, // Optional in filters
611
+ * multiple: true // Allow multiple values in filters
612
+ * }
613
+ * };
614
+ * ```
615
+ *
616
+ * #### Field Collection Usage
617
+ * ```typescript
618
+ * // Using fields in a resource definition
619
+ * const userFields: Fields = {
620
+ * id: {
621
+ * type: "uuid",
622
+ * name: "id",
623
+ * primaryKey: true,
624
+ * readOnly: true
625
+ * },
626
+ * username: {
627
+ * type: "text",
628
+ * name: "username",
629
+ * required: true,
630
+ * minLength: 3,
631
+ * maxLength: 50,
632
+ * forCreate: { required: true },
633
+ * forUpdate: { required: true }
634
+ * },
635
+ * email: {
636
+ * type: "email",
637
+ * name: "email",
638
+ * required: true,
639
+ * unique: true,
640
+ * forCreate: { required: true, unique: true },
641
+ * forUpdate: { required: true, unique: true }
642
+ * },
643
+ * role: {
644
+ * type: "select",
645
+ * name: "role",
646
+ * options: ["admin", "user", "moderator"],
647
+ * defaultValue: "user",
648
+ * forCreate: { required: false },
649
+ * forUpdate: { required: true, allowedValues: ["admin", "user"] }
650
+ * }
651
+ * };
652
+ * ```
653
+ *
654
+ * #### Type-Safe Field Access
655
+ * ```typescript
656
+ * // TypeScript ensures type safety
657
+ * function processField<T extends FieldType>(field: Field<T>) {
658
+ * // field.type is guaranteed to be T
659
+ * // field.name is always available
660
+ * // Action overrides are optional and type-safe
661
+ *
662
+ * if (field.forCreate) {
663
+ * console.log("Create-specific config:", field.forCreate);
664
+ * }
665
+ *
666
+ * if (field.forUpdate) {
667
+ * console.log("Update-specific config:", field.forUpdate);
668
+ * }
669
+ * }
670
+ * ```
671
+ *
672
+ * #### Advanced Usage with Custom Field Types
673
+ * ```typescript
674
+ * // After extending FieldMap with custom types
675
+ * declare module "reslib/resources/resources" {
676
+ * interface FieldMap {
677
+ * richText: FieldBase<"richText", string> & {
678
+ * toolbar: string[];
679
+ * maxLength: number;
680
+ * allowedFormats: string[];
681
+ * };
682
+ * dateRange: FieldBase<"dateRange", { start: Date; end: Date }> & {
683
+ * minDate?: Date;
684
+ * maxDate?: Date;
685
+ * format: string;
686
+ * };
687
+ * }
688
+ * }
689
+ *
690
+ * // Now you can use these custom types
691
+ * const contentField: Field<"richText"> = {
692
+ * type: "richText",
693
+ * name: "content",
694
+ * toolbar: ["bold", "italic", "link"],
695
+ * maxLength: 10000,
696
+ * allowedFormats: ["html", "markdown"],
697
+ * forCreate: { required: true },
698
+ * forUpdate: { required: false }
699
+ * };
700
+ *
701
+ * const dateRangeField: Field<"dateRange"> = {
702
+ * type: "dateRange",
703
+ * name: "eventDates",
704
+ * format: "YYYY-MM-DD",
705
+ * minDate: new Date(),
706
+ * forFilter: { required: false }
707
+ * };
708
+ * ```
709
+ *
710
+ * ### Action-Specific Properties
711
+ * The `Field` type automatically generates properties for each action defined in `FieldActionsMap`:
712
+ *
713
+ * - **`forCreate`**: Configuration when creating new resource instances
714
+ * - **`forUpdate`**: Configuration when updating existing resource instances
715
+ * - **`forCreateOrUpdate`**: Configuration for operations that can create or update
716
+ * - **`forFilter`**: Configuration for filtering/searching resource instances
717
+ *
718
+ * Each action property is optional and can contain any subset of properties from any field type,
719
+ * allowing flexible customization of field behavior per operation.
720
+ *
721
+ * ### Best Practices
722
+ * - **Consistent Base Properties**: Define common properties (like `name`, `type`) at the base level
723
+ * - **Minimal Overrides**: Only specify action-specific properties when behavior genuinely differs
724
+ * - **Type Safety**: Leverage TypeScript's inference for field types and action properties
725
+ * - **Documentation**: Document custom field types and their action-specific behaviors
726
+ * - **Validation**: Use action overrides to enforce security rules and business logic
727
+ *
728
+ * ### Integration with Other Types
729
+ * - **`FieldMap`**: Provides the base field type definitions
730
+ * - **`FieldActionsMap`**: Defines available action contexts
731
+ * - **`Fields`**: Collection of fields for resource definitions
732
+ * - **`FieldBase`**: Common base properties for all field types
733
+ * - **`FieldType`**: Union of all valid field type keys
734
+ *
735
+ * ### Migration Notes
736
+ * When upgrading from simpler field definitions, gradually add action-specific overrides
737
+ * to maintain backward compatibility. The base properties remain available and functional
738
+ * even when action overrides are not specified.
739
+ *
740
+ * @type Field
741
+ * @template T - The field type (must be a key of FieldMap)
742
+ * @default FieldType
743
+ * @public
744
+ *
745
+ * @see {@link FieldMap} - The interface defining field type configurations
746
+ * @see {@link FieldActionsMap} - The interface defining action contexts
747
+ * @see {@link FieldBase} - The base properties shared by all field types
748
+ * @see {@link Fields} - How fields are collected into resource schemas
749
+ * @example
750
+ * ```typescript
751
+ * // Complete example of field definitions with action overrides
752
+ * import "reslib/resources/resources";
753
+ *
754
+ * declare module "reslib/resources/resources" {
755
+ * interface FieldMap {
756
+ * text: FieldBase<"text", string> & {
757
+ * minLength?: number;
758
+ * maxLength?: number;
759
+ * pattern?: RegExp;
760
+ * placeholder?: string;
761
+ * };
762
+ * select: FieldBase<"select", string> & {
763
+ * options: string[];
764
+ * multiple?: boolean;
765
+ * defaultValue?: string;
766
+ * };
767
+ * number: FieldBase<"number", number> & {
768
+ * min?: number;
769
+ * max?: number;
770
+ * step?: number;
771
+ * };
772
+ * }
773
+ * }
774
+ *
775
+ * // Define a comprehensive user resource schema
776
+ * const userFields: Fields = {
777
+ * username: {
778
+ * type: "text",
779
+ * name: "username",
780
+ * required: true,
781
+ * minLength: 3,
782
+ * maxLength: 50,
783
+ * pattern: /^[a-zA-Z0-9_]+$/,
784
+ * forCreate: { required: true },
785
+ * forUpdate: { required: true },
786
+ * forFilter: { required: false }
787
+ * } as Field<"text">,
788
+ *
789
+ * email: {
790
+ * type: "email",
791
+ * name: "email",
792
+ * required: true,
793
+ * forCreate: { required: true },
794
+ * forUpdate: { required: true },
795
+ * forFilter: { required: false }
796
+ * } as Field<"text">, // email extends text with validation
797
+ *
798
+ * role: {
799
+ * type: "select",
800
+ * name: "role",
801
+ * options: ["admin", "user", "moderator"],
802
+ * defaultValue: "user",
803
+ * forCreate: { required: false },
804
+ * forUpdate: { required: true },
805
+ * forFilter: { required: false, multiple: true }
806
+ * } as Field<"select">,
807
+ *
808
+ * age: {
809
+ * type: "number",
810
+ * name: "age",
811
+ * min: 0,
812
+ * max: 150,
813
+ * forCreate: { required: false },
814
+ * forUpdate: { required: false },
815
+ * forFilter: { required: false, min: 18, max: 100 }
816
+ * } as Field<"number">
817
+ * };
818
+ *
819
+ * // Type-safe usage
820
+ * function validateField(field: Field, action: keyof FieldActionsMap, value: any): boolean {
821
+ * const actionConfig = field[`for${action.charAt(0).toUpperCase() + action.slice(1)}` as keyof Field];
822
+ *
823
+ * if (actionConfig && 'required' in actionConfig) {
824
+ * if (actionConfig.required && (value === undefined || value === null)) {
825
+ * return false;
826
+ * }
827
+ * }
828
+ *
829
+ * // Additional validation logic...
830
+ * return true;
831
+ * }
832
+ * ```
833
+ */
834
+ export type Field<T extends FieldType = FieldType> = FieldMap[T] extends FieldBase ? FieldMap[T] & {
835
+ [key in keyof FieldActionsMap as `for${UppercaseFirst<key>}`]?: Partial<FieldMap[keyof FieldMap]>;
836
+ } : never;
837
+ /**
838
+ * Type representing a collection of fields where each key is a string and each value is an Field.
839
+ * This type is used to define the structure of fields for a resource or form.
840
+ *
841
+ * This type provides a flexible way to define multiple fields with their configurations,
842
+ * validation rules, and action-specific overrides. It's commonly used when defining
843
+ * the schema for resources, forms, or data validation.
844
+ *
845
+ * @type Fields
846
+ *
847
+ * @example
848
+ * ```typescript
849
+ * // Basic field collection for a user resource
850
+ * const userFields: Fields = {
851
+ * username: {
852
+ * type: "text",
853
+ * name: "username",
854
+ * required: true,
855
+ * minLength: 3,
856
+ * maxLength: 50,
857
+ * forCreate: { required: true },
858
+ * forUpdate: { required: false }
859
+ * },
860
+ * email: {
861
+ * type: "email",
862
+ * name: "email",
863
+ * required: true,
864
+ * unique: true,
865
+ * forCreate: { required: true },
866
+ * forUpdate: { required: true }
867
+ * },
868
+ * age: {
869
+ * type: "number",
870
+ * name: "age",
871
+ * required: false,
872
+ * min: 0,
873
+ * max: 150,
874
+ * forFilter: { allowRange: true }
875
+ * }
876
+ * };
877
+ * ```
878
+ *
879
+ * @example
880
+ * ```typescript
881
+ * // Dynamic field collection based on user permissions
882
+ * function createFieldsForUser(userRole: string): Fields {
883
+ * const baseFields: Fields = {
884
+ * id: { type: "uuid", name: "id", primaryKey: true, readOnly: true },
885
+ * createdAt: { type: "date", name: "createdAt", readOnly: true },
886
+ * updatedAt: { type: "date", name: "updatedAt", readOnly: true }
887
+ * };
888
+ *
889
+ * if (userRole === 'admin') {
890
+ * return {
891
+ * ...baseFields,
892
+ * adminNotes: {
893
+ * type: "textarea",
894
+ * name: "adminNotes",
895
+ * required: false,
896
+ * maxLength: 1000
897
+ * },
898
+ * isActive: {
899
+ * type: "boolean",
900
+ * name: "isActive",
901
+ * required: true,
902
+ * defaultValue: true
903
+ * }
904
+ * };
905
+ * }
906
+ *
907
+ * return baseFields;
908
+ * }
909
+ * ```
910
+ *
911
+ * @example
912
+ * ```typescript
913
+ * // Form validation using field collection
914
+ * function validateFormData(fields: Fields, data: Record<string, any>): ValidationResult {
915
+ * const errors: string[] = [];
916
+ *
917
+ * for (const [fieldName, fieldConfig] of Object.entries(fields)) {
918
+ * const value = data[fieldName];
919
+ *
920
+ * // Check required fields
921
+ * if (fieldConfig.required && (value === undefined || value === null || value === '')) {
922
+ * errors.push(`${fieldConfig.name || fieldName} is required`);
923
+ * }
924
+ *
925
+ * // Check string length constraints
926
+ * if (typeof value === 'string') {
927
+ * if (fieldConfig.minLength && value.length < fieldConfig.minLength) {
928
+ * errors.push(`${fieldName} must be at least ${fieldConfig.minLength} characters`);
929
+ * }
930
+ * if (fieldConfig.maxLength && value.length > fieldConfig.maxLength) {
931
+ * errors.push(`${fieldName} must be at most ${fieldConfig.maxLength} characters`);
932
+ * }
933
+ * }
934
+ * }
935
+ *
936
+ * return { isValid: errors.length === 0, errors };
937
+ * }
938
+ * ```
939
+ */
940
+ export type Fields = Record<string, Field>;
941
+ /**
942
+ * Type representing the union of all possible field types defined in FieldMap.
943
+ * This type is used to constrain field types to only those defined in the field map.
944
+ *
945
+ * This type ensures type safety by only allowing field types that have been
946
+ * explicitly defined in the FieldMap interface. It prevents typos and ensures
947
+ * that all field types are known and properly configured.
948
+ *
949
+ * @type FieldType
950
+ *
951
+ * @example
952
+ * ```typescript
953
+ * // Basic usage - defining a field with a valid type
954
+ * const textField: FieldBase<"text"> = {
955
+ * type: "text", // ✓ Valid - "text" is in FieldMap
956
+ * name: "username",
957
+ * required: true
958
+ * };
959
+ *
960
+ * const emailField: FieldBase<"email"> = {
961
+ * type: "email", // ✓ Valid - "email" is in FieldMap
962
+ * name: "userEmail",
963
+ * required: true
964
+ * };
965
+ * ```
966
+ *
967
+ * @example
968
+ * ```typescript
969
+ * // Type-safe field type checking
970
+ * function createField<T extends FieldType>(
971
+ * type: T,
972
+ * config: Omit<FieldBase<T>, 'type'>
973
+ * ): FieldBase<T> {
974
+ * return { type, ...config };
975
+ * }
976
+ *
977
+ * // Usage with type safety
978
+ * const numberField = createField("number", {
979
+ * name: "age",
980
+ * required: true,
981
+ * min: 0,
982
+ * max: 150
983
+ * });
984
+ *
985
+ * const dateField = createField("date", {
986
+ * name: "birthDate",
987
+ * required: false
988
+ * });
989
+ *
990
+ * // This would cause a TypeScript error:
991
+ * // const invalidField = createField("invalidType", { name: "test" });
992
+ * // Error: "invalidType" is not assignable to FieldType
993
+ * ```
994
+ *
995
+ * @example
996
+ * ```typescript
997
+ * // Dynamic field type validation
998
+ * function isValidFieldType(type: string): type is FieldType {
999
+ * const validTypes: FieldType[] = ["text", "number", "boolean", "date", "email"];
1000
+ * return validTypes.includes(type as FieldType);
1001
+ * }
1002
+ *
1003
+ * // Usage in runtime validation
1004
+ * function validateFieldType(input: string): FieldType {
1005
+ * if (!isValidFieldType(input)) {
1006
+ * throw new Error(`Invalid field type: ${input}. Valid types are: text, number, boolean, date, email`);
1007
+ * }
1008
+ * return input;
1009
+ * }
1010
+ *
1011
+ * // Safe usage
1012
+ * const fieldType = validateFieldType("text"); // ✓ Valid
1013
+ * // const invalidType = validateFieldType("invalid"); // ✗ Throws error
1014
+ * ```
1015
+ */
1016
+ export type FieldType = keyof FieldMap;
1017
+ /**
1018
+ * ## Resources Interface
1019
+ *
1020
+ * A global interface for defining resource configurations in the application.
1021
+ * This interface serves as a central registry for all available resources and their
1022
+ * metadata, enabling type-safe resource management across the entire codebase.
1023
+ *
1024
+ * ### Purpose
1025
+ * The `Resources` interface is designed for **module augmentation**, allowing developers
1026
+ * to extend it with custom resource definitions. Each key represents a resource name
1027
+ * (e.g., "users", "posts", "products"), and each value must conform to the `ResourceBase` interface,
1028
+ * ensuring consistent structure and type safety for all resource configurations.
1029
+ *
1030
+ * ### How It Works
1031
+ * - **Empty by Design**: The interface is intentionally empty in the core library.
1032
+ * - **Module Augmentation**: Developers extend it via `declare module` statements.
1033
+ * - **Type Safety**: The `ResourceConfig<T>`, `ResourceName`, and other types use `Resources[K]`
1034
+ * to enforce that resource configurations match their declared types.
1035
+ * - **Extensibility**: New resources can be added without modifying the core library.
1036
+ *
1037
+ * ### Template Parameters
1038
+ * This interface doesn't use generic parameters itself, but the values must conform to `ResourceBase<Name, DataType, TPrimaryKey, Actions>`.
1039
+ *
1040
+ * ### Examples
1041
+ *
1042
+ * #### Basic Module Augmentation
1043
+ * ```typescript
1044
+ * // In your application's types file (e.g., types.ts or global.d.ts)
1045
+ * import "reslib/resources";
1046
+ *
1047
+ * declare module "reslib/resources" {
1048
+ * interface Resources {
1049
+ * // Define a users resource
1050
+ * users: {
1051
+ * actions: {
1052
+ * read: { label: "Read User" };
1053
+ * create: { label: "Create User" };
1054
+ * update: { label: "Update User" };
1055
+ * delete: { label: "Delete User" };
1056
+ * }
1057
+ * };
1058
+ *
1059
+ * // Define a posts resource
1060
+ * posts: {
1061
+ * actions: {
1062
+ * read: { label: "Read Post" };
1063
+ * create: { label: "Create Post" };
1064
+ * publish: { label: "Publish Post" };
1065
+ * archive: { label: "Archive Post" };
1066
+ * }
1067
+ * };
1068
+ * }
1069
+ * }
1070
+ * ```
1071
+ *
1072
+ * #### Advanced Resource Configuration
1073
+ * ```typescript
1074
+ * declare module "reslib/resources" {
1075
+ * interface Resources {
1076
+ * // User resource with comprehensive actions
1077
+ * users: {
1078
+ * actions: {
1079
+ * read: { label: "Read User", title: "View user details" };
1080
+ * create: { label: "Create User", title: "Add new user" };
1081
+ * update: { label: "Update User", title: "Modify user data" };
1082
+ * delete: { label: "Delete User", title: "Remove user" };
1083
+ * activate: { label: "Activate User", title: "Enable user account" };
1084
+ * deactivate: { label: "Deactivate User", title: "Disable user account" };
1085
+ * resetPassword: { label: "Reset Password", title: "Send password reset" };
1086
+ * }
1087
+ * };
1088
+ *
1089
+ * // Product resource with inventory management
1090
+ * products: {
1091
+ * actions: {
1092
+ * read: { label: "View Product" };
1093
+ * create: { label: "Add Product" };
1094
+ * update: { label: "Edit Product" };
1095
+ * delete: { label: "Remove Product" };
1096
+ * restock: { label: "Restock Product" };
1097
+ * discontinue: { label: "Discontinue Product" };
1098
+ * }
1099
+ * };
1100
+ *
1101
+ * // Order resource with workflow actions
1102
+ * orders: {
1103
+ * actions: {
1104
+ * read: { label: "View Order" };
1105
+ * create: { label: "Create Order" };
1106
+ * update: { label: "Update Order" };
1107
+ * cancel: { label: "Cancel Order" };
1108
+ * ship: { label: "Ship Order" };
1109
+ * deliver: { label: "Mark Delivered" };
1110
+ * refund: { label: "Process Refund" };
1111
+ * }
1112
+ * };
1113
+ * }
1114
+ * }
1115
+ * ```
1116
+ *
1117
+ * #### Using Defined Resources
1118
+ * ```typescript
1119
+ * // After augmentation, you can use type-safe resource operations
1120
+ * import { ResourceConfig, ResourceName, ResourceActions } from "reslib/resources";
1121
+ *
1122
+ * // Type-safe resource access
1123
+ * type UserResource = ResourceConfig<"users">;
1124
+ * type PostResource = ResourceConfig<"posts">;
1125
+ *
1126
+ * // Type-safe action names
1127
+ * type UserActionNames = ResourceActionName<"users">;
1128
+ * // Result: "read" | "create" | "update" | "delete" | "activate" | "deactivate" | "resetPassword"
1129
+ *
1130
+ * // Type-safe action access
1131
+ * type UserActions = ResourceActions<"users">;
1132
+ * // Result: Complete actions record for users resource
1133
+ *
1134
+ * // Runtime usage with type safety
1135
+ * function processUserAction(action: UserActionNames, userId: string) {
1136
+ * console.log(`Processing ${action} for user ${userId}`);
1137
+ *
1138
+ * // TypeScript ensures action is a valid user action
1139
+ * switch (action) {
1140
+ * case "create":
1141
+ * return createUser();
1142
+ * case "activate":
1143
+ * return activateUser(userId);
1144
+ * case "resetPassword":
1145
+ * return resetUserPassword(userId);
1146
+ * // TypeScript will catch invalid actions
1147
+ * }
1148
+ * }
1149
+ * ```
1150
+ *
1151
+ * #### Resource Registry Implementation
1152
+ * ```typescript
1153
+ * // Create a type-safe resource registry
1154
+ * class ResourceRegistry {
1155
+ * private resources = new Map<ResourceName, ResourceConfig<ResourceName>>();
1156
+ *
1157
+ * register<TResourceName extends ResourceName>(
1158
+ * name: TResourceName,
1159
+ * config: ResourceConfig<TResourceName>
1160
+ * ) {
1161
+ * this.resources.set(name, config);
1162
+ * }
1163
+ *
1164
+ * get<TResourceName extends ResourceName>(
1165
+ * name: TResourceName
1166
+ * ): ResourceConfig<TResourceName> | undefined {
1167
+ * return this.resources.get(name) as ResourceConfig<TResourceName>;
1168
+ * }
1169
+ *
1170
+ * getAllActions<TResourceName extends ResourceName>(
1171
+ * name: TResourceName
1172
+ * ): ResourceActions<TResourceName> {
1173
+ * const resource = this.get(name);
1174
+ * if (!resource) throw new Error(`Resource ${name} not found`);
1175
+ * return resource.actions;
1176
+ * }
1177
+ * }
1178
+ *
1179
+ * // Usage
1180
+ * const registry = new ResourceRegistry();
1181
+ *
1182
+ * registry.register("users", {
1183
+ * actions: {
1184
+ * read: { label: "Read User" },
1185
+ * create: { label: "Create User" },
1186
+ * update: { label: "Update User" }
1187
+ * }
1188
+ * });
1189
+ *
1190
+ * const userActions = registry.getAllActions("users");
1191
+ * // TypeScript knows this contains only user actions
1192
+ * ```
1193
+ *
1194
+ * #### Permission System Integration
1195
+ * ```typescript
1196
+ * // Define permissions based on resource actions
1197
+ * type Permission<TResourceName extends ResourceName> = {
1198
+ * resource: TResourceName;
1199
+ * action: ResourceActionName<TResourceName>;
1200
+ * granted: boolean;
1201
+ * };
1202
+ *
1203
+ * class PermissionManager {
1204
+ * private permissions = new Map<string, Permission<ResourceName>>();
1205
+ *
1206
+ * grant<TResourceName extends ResourceName>(
1207
+ * resource: TResourceName,
1208
+ * action: ResourceActionName<TResourceName>
1209
+ * ) {
1210
+ * const key = `${resource}:${action}`;
1211
+ * this.permissions.set(key, { resource, action, granted: true });
1212
+ * }
1213
+ *
1214
+ * check<TResourceName extends ResourceName>(
1215
+ * resource: TResourceName,
1216
+ * action: ResourceActionName<TResourceName>
1217
+ * ): boolean {
1218
+ * const key = `${resource}:${action}`;
1219
+ * return this.permissions.get(key)?.granted ?? false;
1220
+ * }
1221
+ * }
1222
+ *
1223
+ * // Usage
1224
+ * const permManager = new PermissionManager();
1225
+ *
1226
+ * permManager.grant("users", "create");
1227
+ * permManager.grant("users", "update");
1228
+ * permManager.grant("posts", "publish");
1229
+ *
1230
+ * // Type-safe permission checks
1231
+ * if (permManager.check("users", "create")) {
1232
+ * // User can create users
1233
+ * }
1234
+ *
1235
+ * // This would cause a TypeScript error:
1236
+ * // permManager.check("users", "invalidAction"); // ✗ Error: not a valid user action
1237
+ * ```
1238
+ *
1239
+ * ### Best Practices
1240
+ * - **Consistent Naming**: Use lowercase, plural resource names (e.g., "users", "products").
1241
+ * - **Comprehensive Actions**: Define all relevant actions for each resource's lifecycle.
1242
+ * - **Documentation**: Document custom resources and their actions clearly for team members.
1243
+ * - **Versioning**: Consider the impact on existing code when adding new resources or actions.
1244
+ * - **Validation**: Use TypeScript's type system to enforce resource constraints at compile time.
1245
+ *
1246
+ * ### Integration with Other Types
1247
+ * - **ResourceConfig<T>**: Provides type-safe access to individual resource configurations.
1248
+ * - **ResourceName**: Union type of all defined resource names.
1249
+ * - **ResourceActions<T>**: Type-safe access to a resource's actions.
1250
+ * - **ResourceActionName<T>**: Union type of action names for a specific resource.
1251
+ * - **ResourceBase**: The base interface that all resource definitions must implement.
1252
+ *
1253
+ * ### Migration Notes
1254
+ * If you're upgrading from a version where resources were defined differently,
1255
+ * update your module augmentations to use this new structure for better type safety.
1256
+ * Existing code using the old structure may need to be updated to match the new interface.
1257
+ *
1258
+ * @interface Resources
1259
+ * @public
1260
+ *
1261
+ * @see {@link ResourceBase} - The base interface that resource definitions must implement
1262
+ * @see {@link ResourceConfig} - How to access individual resource configurations
1263
+ * @see {@link ResourceName} - The union type of all defined resource names
1264
+ * @see {@link ResourceActions} - How to access resource actions with type safety
1265
+ * @example
1266
+ * ```typescript
1267
+ * // Complete example of extending Resources
1268
+ * declare module "reslib/resources" {
1269
+ * interface Resources {
1270
+ * // User management resource
1271
+ * users: {
1272
+ * actions: {
1273
+ * read: { label: "Read User" };
1274
+ * create: { label: "Create User" };
1275
+ * update: { label: "Update User" };
1276
+ * delete: { label: "Delete User" };
1277
+ * activate: { label: "Activate User" };
1278
+ * deactivate: { label: "Deactivate User" };
1279
+ * }
1280
+ * };
1281
+ *
1282
+ * // Content management resource
1283
+ * posts: {
1284
+ * actions: {
1285
+ * read: { label: "Read Post" };
1286
+ * create: { label: "Create Post" };
1287
+ * update: { label: "Update Post" };
1288
+ * delete: { label: "Delete Post" };
1289
+ * publish: { label: "Publish Post" };
1290
+ * archive: { label: "Archive Post" };
1291
+ * }
1292
+ * };
1293
+ *
1294
+ * // E-commerce resource
1295
+ * products: {
1296
+ * actions: {
1297
+ * read: { label: "View Product" };
1298
+ * create: { label: "Add Product" };
1299
+ * update: { label: "Edit Product" };
1300
+ * delete: { label: "Remove Product" };
1301
+ * restock: { label: "Restock Product" };
1302
+ * discontinue: { label: "Discontinue Product" };
1303
+ * }
1304
+ * };
1305
+ *
1306
+ * // Order management resource
1307
+ * orders: {
1308
+ * actions: {
1309
+ * read: { label: "View Order" };
1310
+ * create: { label: "Create Order" };
1311
+ * update: { label: "Update Order" };
1312
+ * cancel: { label: "Cancel Order" };
1313
+ * ship: { label: "Ship Order" };
1314
+ * deliver: { label: "Mark Delivered" };
1315
+ * refund: { label: "Process Refund" };
1316
+ * }
1317
+ * };
1318
+ * }
1319
+ * }
1320
+ *
1321
+ * // Usage examples with type safety
1322
+ * type UserResource = ResourceConfig<"users">;
1323
+ * type UserActions = ResourceActionName<"users">;
1324
+ *
1325
+ * function handleUserAction(action: UserActions, userId: string) {
1326
+ * // TypeScript ensures action is a valid user action
1327
+ * console.log(`Handling ${action} for user ${userId}`);
1328
+ * }
1329
+ *
1330
+ * // Valid usage
1331
+ * handleUserAction("create", "123");
1332
+ * handleUserAction("activate", "456");
1333
+ *
1334
+ * // Invalid usage (TypeScript error)
1335
+ * // handleUserAction("invalidAction", "123"); // ✗ Error
1336
+ * ```
1337
+ */
1338
+ export interface Resources {
1339
+ }
1340
+ type ValidatedResources = {
1341
+ [K in keyof Resources]: ValidateResource<Resources[K]>;
1342
+ };
1343
+ type ValidateResource<T> = T extends ResourceBase ? T : never;
1344
+ /**
1345
+ * ## ResourceName Type
1346
+ *
1347
+ * A union type representing all valid resource names defined in the global Resources interface.
1348
+ * This type provides compile-time safety by ensuring that only resources that have been
1349
+ * properly defined and validated can be referenced throughout the application.
1350
+ *
1351
+ * ### Purpose
1352
+ * The `ResourceName` type serves as the foundation for type-safe resource operations by
1353
+ * creating a union of all resource names that have been defined via module augmentation.
1354
+ * It ensures that developers can only reference resources that actually exist and conform
1355
+ * to the expected structure, preventing typos and invalid resource references.
1356
+ *
1357
+ * ### How It Works
1358
+ * - **Module Augmentation**: Resources are defined by extending the `Resources` interface
1359
+ * - **Validation**: `ValidatedResources` ensures each resource implements `ResourceBase`
1360
+ * - **Key Extraction**: `keyof ValidatedResources` creates a union of all valid resource names
1361
+ * - **Type Safety**: Any operation using `ResourceName` is guaranteed to reference a valid resource
1362
+ *
1363
+ * ### Type Construction
1364
+ * ```typescript
1365
+ * ResourceName = keyof ValidatedResources
1366
+ * ```
1367
+ *
1368
+ * Where `ValidatedResources` maps each resource to its validated configuration.
1369
+ *
1370
+ * ### Examples
1371
+ *
1372
+ * #### Basic Resource Definition and Usage
1373
+ * ```typescript
1374
+ * // Define resources via module augmentation
1375
+ * declare module "reslib/resources" {
1376
+ * interface Resources {
1377
+ * users: {
1378
+ * actions: {
1379
+ * read: { label: "Read User" };
1380
+ * create: { label: "Create User" };
1381
+ * update: { label: "Update User" };
1382
+ * }
1383
+ * };
1384
+ * posts: {
1385
+ * actions: {
1386
+ * read: { label: "Read Post" };
1387
+ * create: { label: "Create Post" };
1388
+ * publish: { label: "Publish Post" };
1389
+ * }
1390
+ * };
1391
+ * products: {
1392
+ * actions: {
1393
+ * read: { label: "View Product" };
1394
+ * create: { label: "Add Product" };
1395
+ * update: { label: "Edit Product" };
1396
+ * }
1397
+ * };
1398
+ * }
1399
+ * }
1400
+ *
1401
+ * // ResourceName automatically becomes: "users" | "posts" | "products"
1402
+ * type AvailableResources = ResourceName; // "users" | "posts" | "products"
1403
+ *
1404
+ * // Type-safe resource operations
1405
+ * function getResourceConfig(name: ResourceName): ResourceConfig<ResourceName> {
1406
+ * // TypeScript ensures name is a valid resource
1407
+ * return getResourceConfiguration(name);
1408
+ * }
1409
+ *
1410
+ * getResourceConfig("users"); // ✓ Valid
1411
+ * getResourceConfig("posts"); // ✓ Valid
1412
+ * getResourceConfig("products"); // ✓ Valid
1413
+ * // getResourceConfig("invalid"); // ✗ TypeScript error
1414
+ * ```
1415
+ *
1416
+ * #### Generic Functions with Resource Names
1417
+ * ```typescript
1418
+ * // Generic function that works with any resource
1419
+ * function createResourceHandler<T extends ResourceName>(resourceName: T) {
1420
+ * return {
1421
+ * name: resourceName,
1422
+ * config: {} as ResourceConfig<T>,
1423
+ * actions: [] as ResourceActionName<T>[]
1424
+ * };
1425
+ * }
1426
+ *
1427
+ * // Usage with type safety
1428
+ * const userHandler = createResourceHandler("users");
1429
+ * // TypeScript knows this is specifically for users
1430
+ *
1431
+ * const postHandler = createResourceHandler("posts");
1432
+ * // TypeScript knows this is specifically for posts
1433
+ * ```
1434
+ *
1435
+ * #### Resource Registry with Type Safety
1436
+ * ```typescript
1437
+ * // Type-safe resource registry
1438
+ * class ResourceRegistry {
1439
+ * private resources = new Map<ResourceName, ResourceConfig<ResourceName>>();
1440
+ *
1441
+ * register<T extends ResourceName>(
1442
+ * name: T,
1443
+ * config: ResourceConfig<T>
1444
+ * ): void {
1445
+ * this.resources.set(name, config);
1446
+ * }
1447
+ *
1448
+ * get<T extends ResourceName>(name: T): ResourceConfig<T> | undefined {
1449
+ * return this.resources.get(name) as ResourceConfig<T> | undefined;
1450
+ * }
1451
+ *
1452
+ * has(name: ResourceName): boolean {
1453
+ * return this.resources.has(name);
1454
+ * }
1455
+ *
1456
+ * getAllResourceNames(): ResourceName[] {
1457
+ * return Array.from(this.resources.keys());
1458
+ * }
1459
+ * }
1460
+ *
1461
+ * // Usage
1462
+ * const registry = new ResourceRegistry();
1463
+ *
1464
+ * registry.register("users", {
1465
+ * actions: {
1466
+ * read: { label: "Read User" },
1467
+ * create: { label: "Create User" }
1468
+ * }
1469
+ * });
1470
+ *
1471
+ * registry.register("posts", {
1472
+ * actions: {
1473
+ * read: { label: "Read Post" },
1474
+ * create: { label: "Create Post" }
1475
+ * }
1476
+ * });
1477
+ *
1478
+ * // Type-safe access
1479
+ * const userConfig = registry.get("users"); // ResourceConfig<"users">
1480
+ * const postConfig = registry.get("posts"); // ResourceConfig<"posts">
1481
+ * ```
1482
+ *
1483
+ * #### Permission System with Resource Names
1484
+ * ```typescript
1485
+ * // Permission type using ResourceName
1486
+ * type ResourcePermission = {
1487
+ * resource: ResourceName;
1488
+ * action: string; // Could be ResourceActionName<ResourceName> for full type safety
1489
+ * granted: boolean;
1490
+ * };
1491
+ *
1492
+ * class PermissionManager {
1493
+ * private permissions = new Map<string, ResourcePermission>();
1494
+ *
1495
+ * grantPermission(resource: ResourceName, action: string): void {
1496
+ * const key = `${resource}:${action}`;
1497
+ * this.permissions.set(key, { resource, action, granted: true });
1498
+ * }
1499
+ *
1500
+ * checkPermission(resource: ResourceName, action: string): boolean {
1501
+ * const key = `${resource}:${action}`;
1502
+ * return this.permissions.get(key)?.granted ?? false;
1503
+ * }
1504
+ *
1505
+ * getAllPermissionsForResource(resource: ResourceName): ResourcePermission[] {
1506
+ * return Array.from(this.permissions.values())
1507
+ * .filter(perm => perm.resource === resource);
1508
+ * }
1509
+ * }
1510
+ *
1511
+ * // Usage
1512
+ * const permManager = new PermissionManager();
1513
+ *
1514
+ * permManager.grantPermission("users", "read");
1515
+ * permManager.grantPermission("users", "create");
1516
+ * permManager.grantPermission("posts", "read");
1517
+ *
1518
+ * permManager.checkPermission("users", "read"); // true
1519
+ * permManager.checkPermission("users", "delete"); // false
1520
+ * permManager.checkPermission("invalid", "read"); // ✗ TypeScript error
1521
+ * ```
1522
+ *
1523
+ * #### API Route Generation
1524
+ * ```typescript
1525
+ * // Generate API routes for all defined resources
1526
+ * function generateApiRoutes(resources: ResourceName[]): string[] {
1527
+ * const routes: string[] = [];
1528
+ *
1529
+ * for (const resource of resources) {
1530
+ * routes.push(`/api/${resource}`);
1531
+ * routes.push(`/api/${resource}/:id`);
1532
+ * }
1533
+ *
1534
+ * return routes;
1535
+ * }
1536
+ *
1537
+ * // Usage
1538
+ * const allRoutes = generateApiRoutes(["users", "posts", "products"]);
1539
+ * // Result: ["/api/users", "/api/users/:id", "/api/posts", "/api/posts/:id", ...]
1540
+ * ```
1541
+ *
1542
+ * ### Best Practices
1543
+ * - **Module Augmentation**: Always define resources via `declare module` to extend the `Resources` interface
1544
+ * - **Consistent Naming**: Use lowercase, plural resource names (e.g., "users", "products", "orders")
1545
+ * - **Type Constraints**: Use `T extends ResourceName` in generic functions for type safety
1546
+ * - **Validation**: Resources must implement `ResourceBase` to be included in `ResourceName`
1547
+ * - **Documentation**: Document custom resources and their purposes for team members
1548
+ *
1549
+ * ### Integration with Other Types
1550
+ * - **`Resources`**: The global interface that defines all resource configurations
1551
+ * - **`ResourceConfig<T>`**: Provides type-safe access to individual resource configurations
1552
+ * - **`ResourceActionName<T>`**: Union type of action names for a specific resource
1553
+ * - **`ResourceActions<T>`**: Type-safe access to a resource's actions
1554
+ * - **`ResourceBase`**: The base interface that all resources must implement
1555
+ *
1556
+ * ### Migration Notes
1557
+ * When adding new resources, ensure they are defined via module augmentation of the `Resources`
1558
+ * interface. The `ResourceName` type will automatically include new resources without requiring
1559
+ * code changes elsewhere. Existing code using string literals for resource names can be updated
1560
+ * to use `ResourceName` for better type safety.
1561
+ *
1562
+ * @type ResourceName
1563
+ * @public
1564
+ *
1565
+ * @see {@link Resources} - The global interface defining all resource configurations
1566
+ * @see {@link ResourceConfig} - How to access individual resource configurations
1567
+ * @see {@link ResourceActionName} - Action names for specific resources
1568
+ * @example
1569
+ * ```typescript
1570
+ * // Complete example of using ResourceName for type safety
1571
+ * import "reslib/resources";
1572
+ *
1573
+ * declare module "reslib/resources" {
1574
+ * interface Resources {
1575
+ * users: {
1576
+ * actions: {
1577
+ * read: { label: "Read User" };
1578
+ * create: { label: "Create User" };
1579
+ * update: { label: "Update User" };
1580
+ * delete: { label: "Delete User" };
1581
+ * };
1582
+ * permissions: {
1583
+ * adminOnly: string[];
1584
+ * publicAccess: string[];
1585
+ * };
1586
+ * };
1587
+ *
1588
+ * posts: {
1589
+ * actions: {
1590
+ * read: { label: "Read Post" };
1591
+ * create: { label: "Create Post" };
1592
+ * publish: { label: "Publish Post" };
1593
+ * archive: { label: "Archive Post" };
1594
+ * };
1595
+ * categories: string[];
1596
+ * };
1597
+ *
1598
+ * products: {
1599
+ * actions: {
1600
+ * read: { label: "View Product" };
1601
+ * create: { label: "Add Product" };
1602
+ * update: { label: "Edit Product" };
1603
+ * discontinue: { label: "Discontinue Product" };
1604
+ * };
1605
+ * pricing: {
1606
+ * currency: string;
1607
+ * taxRate: number;
1608
+ * };
1609
+ * };
1610
+ * }
1611
+ * }
1612
+ *
1613
+ * // ResourceName is automatically: "users" | "posts" | "products"
1614
+ * type AvailableResources = ResourceName;
1615
+ *
1616
+ * // Type-safe resource operations
1617
+ * function processResource<T extends ResourceName>(name: T) {
1618
+ * console.log(`Processing resource: ${name}`);
1619
+ *
1620
+ * // TypeScript knows the exact configuration available
1621
+ * const config = {} as ResourceConfig<T>;
1622
+ *
1623
+ * // TypeScript knows the exact actions available
1624
+ * const actions = [] as ResourceActionName<T>[];
1625
+ *
1626
+ * return { name, config, actions };
1627
+ * }
1628
+ *
1629
+ * // Usage with full type safety
1630
+ * const userProcessor = processResource("users");
1631
+ * // userProcessor.name: "users"
1632
+ * // userProcessor.config: ResourceConfig<"users">
1633
+ * // userProcessor.actions: ResourceActionName<"users">[]
1634
+ *
1635
+ * const postProcessor = processResource("posts");
1636
+ * // postProcessor.name: "posts"
1637
+ * // postProcessor.config: ResourceConfig<"posts">
1638
+ * // postProcessor.actions: ResourceActionName<"posts">[]
1639
+ *
1640
+ * // Invalid usage (TypeScript errors)
1641
+ * // processResource("invalidResource"); // ✗ Error: not in ResourceName
1642
+ * ```
1643
+ */
1644
+ export type ResourceName = keyof ValidatedResources;
1645
+ /**
1646
+ * ## ResourceConfig Type
1647
+ *
1648
+ * A type-safe accessor for individual resource configurations from the global Resources interface.
1649
+ * This type provides compile-time guarantees that resource configurations conform to the expected structure
1650
+ * and enables type-safe operations on specific resources throughout the application.
1651
+ *
1652
+ * ### Purpose
1653
+ * The `ResourceConfig` type serves as a bridge between the global `Resources` interface and individual
1654
+ * resource operations. It ensures that when you reference a specific resource by name, you get the
1655
+ * exact configuration defined for that resource, with full type safety and IntelliSense support.
1656
+ *
1657
+ * ### How It Works
1658
+ * This type uses TypeScript's indexed access types to extract the configuration for a specific resource:
1659
+ *
1660
+ * 1. **Type Validation**: Leverages `ValidatedResources` to ensure the resource configuration
1661
+ * implements the `ResourceBase` interface
1662
+ * 2. **Indexed Access**: Uses `ValidatedResources[TResourceName]` to extract the specific resource config
1663
+ * 3. **Type Safety**: Provides compile-time guarantees about the structure and available actions
1664
+ * 4. **Extensibility**: Automatically reflects changes when new resources are added via module augmentation
1665
+ *
1666
+ * ### Template Parameters
1667
+ * - **TResourceName**: The name of the resource (must be a key of the Resources interface).
1668
+ * This parameter is constrained to `ResourceName`, ensuring only defined resources can be accessed.
1669
+ *
1670
+ * ### Type Construction
1671
+ * ```typescript
1672
+ * ResourceConfig<TResourceName> = ValidatedResources[TResourceName]
1673
+ * ```
1674
+ *
1675
+ * Where `ValidatedResources` ensures each resource configuration extends `ResourceBase`.
1676
+ *
1677
+ * ### Examples
1678
+ *
1679
+ * #### Basic Resource Access
1680
+ * ```typescript
1681
+ * // After defining resources via module augmentation
1682
+ * declare module "reslib/resources" {
1683
+ * interface Resources {
1684
+ * users: {
1685
+ * actions: {
1686
+ * read: { label: "Read User" };
1687
+ * create: { label: "Create User" };
1688
+ * update: { label: "Update User" };
1689
+ * }
1690
+ * };
1691
+ * posts: {
1692
+ * actions: {
1693
+ * read: { label: "Read Post" };
1694
+ * create: { label: "Create Post" };
1695
+ * publish: { label: "Publish Post" };
1696
+ * }
1697
+ * };
1698
+ * }
1699
+ * }
1700
+ *
1701
+ * // Type-safe access to resource configurations
1702
+ * type UserConfig = ResourceConfig<"users">;
1703
+ * // Result: The complete configuration object for the users resource
1704
+ *
1705
+ * type PostConfig = ResourceConfig<"posts">;
1706
+ * // Result: The complete configuration object for the posts resource
1707
+ * ```
1708
+ *
1709
+ * #### Type-Safe Resource Operations
1710
+ * ```typescript
1711
+ * // Function that works with any resource configuration
1712
+ * function createResourceHandler<TResourceName extends ResourceName>(
1713
+ * resourceName: TResourceName,
1714
+ * config: ResourceConfig<TResourceName>
1715
+ * ) {
1716
+ * console.log(`Setting up handlers for ${resourceName}`);
1717
+ *
1718
+ * // TypeScript knows the exact actions available for this resource
1719
+ * for (const actionName in config.actions) {
1720
+ * console.log(`Action: ${actionName}`);
1721
+ * // actionName is typed as keyof config.actions
1722
+ * }
1723
+ *
1724
+ * return {
1725
+ * getConfig: (): ResourceConfig<TResourceName> => config,
1726
+ * getActionNames: (): (keyof ResourceConfig<TResourceName>['actions'])[] => {
1727
+ * return Object.keys(config.actions) as (keyof ResourceConfig<TResourceName>['actions'])[];
1728
+ * }
1729
+ * };
1730
+ * }
1731
+ *
1732
+ * // Usage with type safety
1733
+ * const userHandler = createResourceHandler("users", {
1734
+ * actions: {
1735
+ * read: { label: "Read User" },
1736
+ * create: { label: "Create User" },
1737
+ * update: { label: "Update User" }
1738
+ * }
1739
+ * });
1740
+ *
1741
+ * // TypeScript ensures only valid user actions are used
1742
+ * const userActions = userHandler.getActionNames();
1743
+ * // Result: ("read" | "create" | "update")[]
1744
+ * ```
1745
+ *
1746
+ * #### Resource Registry with Type Safety
1747
+ * ```typescript
1748
+ * // Type-safe resource registry
1749
+ * class ResourceRegistry {
1750
+ * private resources = new Map<ResourceName, ResourceConfig<ResourceName>>();
1751
+ *
1752
+ * register<TResourceName extends ResourceName>(
1753
+ * name: TResourceName,
1754
+ * config: ResourceConfig<TResourceName>
1755
+ * ) {
1756
+ * this.resources.set(name, config);
1757
+ * }
1758
+ *
1759
+ * get<TResourceName extends ResourceName>(
1760
+ * name: TResourceName
1761
+ * ): ResourceConfig<TResourceName> | undefined {
1762
+ * return this.resources.get(name) as ResourceConfig<TResourceName> | undefined;
1763
+ * }
1764
+ *
1765
+ * getAllActions<TResourceName extends ResourceName>(
1766
+ * name: TResourceName
1767
+ * ): ResourceConfig<TResourceName>['actions'] {
1768
+ * const resource = this.get(name);
1769
+ * if (!resource) throw new Error(`Resource ${name} not found`);
1770
+ * return resource.actions;
1771
+ * }
1772
+ * }
1773
+ *
1774
+ * // Usage
1775
+ * const registry = new ResourceRegistry();
1776
+ *
1777
+ * registry.register("users", {
1778
+ * actions: {
1779
+ * read: { label: "Read User" },
1780
+ * create: { label: "Create User" },
1781
+ * update: { label: "Update User" }
1782
+ * }
1783
+ * });
1784
+ *
1785
+ * const userConfig = registry.get("users");
1786
+ * // TypeScript knows this is ResourceConfig<"users">
1787
+ *
1788
+ * const userActions = registry.getAllActions("users");
1789
+ * // TypeScript knows this contains only user actions
1790
+ * ```
1791
+ *
1792
+ * #### Advanced Configuration with Custom Properties
1793
+ * ```typescript
1794
+ * // Resources with additional configuration properties
1795
+ * declare module "reslib/resources" {
1796
+ * interface Resources {
1797
+ * users: {
1798
+ * actions: {
1799
+ * read: { label: "Read User" };
1800
+ * create: { label: "Create User" };
1801
+ * update: { label: "Update User" };
1802
+ * };
1803
+ * // Custom properties
1804
+ * permissions: {
1805
+ * adminOnly: string[];
1806
+ * publicAccess: string[];
1807
+ * };
1808
+ * validationRules: {
1809
+ * passwordMinLength: number;
1810
+ * requireEmailVerification: boolean;
1811
+ * };
1812
+ * };
1813
+ * }
1814
+ * }
1815
+ *
1816
+ * // Type-safe access to custom properties
1817
+ * function configureUserResource(config: ResourceConfig<"users">) {
1818
+ * // TypeScript knows about custom properties
1819
+ * console.log("Admin actions:", config.permissions.adminOnly);
1820
+ * console.log("Password min length:", config.validationRules.passwordMinLength);
1821
+ *
1822
+ * // Standard actions are still available
1823
+ * const actions = config.actions;
1824
+ * // actions is typed with user-specific actions
1825
+ * }
1826
+ *
1827
+ * const userConfig: ResourceConfig<"users"> = {
1828
+ * actions: {
1829
+ * read: { label: "Read User" },
1830
+ * create: { label: "Create User" },
1831
+ * update: { label: "Update User" }
1832
+ * },
1833
+ * permissions: {
1834
+ * adminOnly: ["delete", "ban"],
1835
+ * publicAccess: ["read", "create"]
1836
+ * },
1837
+ * validationRules: {
1838
+ * passwordMinLength: 8,
1839
+ * requireEmailVerification: true
1840
+ * }
1841
+ * };
1842
+ *
1843
+ * configureUserResource(userConfig);
1844
+ * ```
1845
+ *
1846
+ * #### Generic Resource Processing
1847
+ * ```typescript
1848
+ * // Generic function that processes any resource
1849
+ * function processResource<TResourceName extends ResourceName>(
1850
+ * name: TResourceName,
1851
+ * config: ResourceConfig<TResourceName>,
1852
+ * processor: (config: ResourceConfig<TResourceName>) => void
1853
+ * ) {
1854
+ * console.log(`Processing resource: ${name}`);
1855
+ * processor(config);
1856
+ * }
1857
+ *
1858
+ * // Usage with different resources
1859
+ * processResource("users", userConfig, (config) => {
1860
+ * // config is typed as ResourceConfig<"users">
1861
+ * console.log("User actions:", Object.keys(config.actions));
1862
+ * });
1863
+ *
1864
+ * processResource("posts", postConfig, (config) => {
1865
+ * // config is typed as ResourceConfig<"posts">
1866
+ * console.log("Post actions:", Object.keys(config.actions));
1867
+ * });
1868
+ * ```
1869
+ *
1870
+ * ### Best Practices
1871
+ * - **Type Constraints**: Always use `TResourceName extends ResourceName` to constrain resource names
1872
+ * - **Generic Functions**: Use generics to create reusable functions that work with any resource type
1873
+ * - **Module Augmentation**: Define resources via module augmentation for better organization
1874
+ * - **Type Safety**: Leverage TypeScript's inference to avoid manual type assertions
1875
+ * - **Consistent Naming**: Use lowercase, plural resource names (e.g., "users", "products")
1876
+ * - **Documentation**: Document custom resource properties for team members
1877
+ *
1878
+ * ### Integration with Other Types
1879
+ * - **`Resources`**: The global interface that `ResourceConfig` accesses
1880
+ * - **`ResourceName`**: Union type of all defined resource names
1881
+ * - **`ResourceActions<TResourceName>`**: Type-safe access to a resource's actions
1882
+ * - **`ResourceActionName<TResourceName>`**: Union type of action names for a specific resource
1883
+ * - **`ResourceBase`**: The base interface that all resource configurations must implement
1884
+ *
1885
+ * ### Migration Notes
1886
+ * When upgrading from direct resource object usage, replace explicit types with `ResourceConfig<TResourceName>`
1887
+ * to gain type safety and automatic updates when resource definitions change. The type provides the same
1888
+ * runtime behavior while adding compile-time guarantees.
1889
+ *
1890
+ * @type ResourceConfig
1891
+ * @template TResourceName - The name of the resource (must be a key of Resources)
1892
+ * @public
1893
+ *
1894
+ * @see {@link Resources} - The global interface defining all resource configurations
1895
+ * @see {@link ResourceName} - Union type of all defined resource names
1896
+ * @see {@link ResourceActions} - How to access resource actions with type safety
1897
+ * @see {@link ResourceBase} - The base interface that resource definitions must implement
1898
+ * @example
1899
+ * ```typescript
1900
+ * // Complete example of using ResourceConfig
1901
+ * import "reslib/resources";
1902
+ *
1903
+ * declare module "reslib/resources" {
1904
+ * interface Resources {
1905
+ * users: {
1906
+ * actions: {
1907
+ * read: { label: "Read User" };
1908
+ * create: { label: "Create User" };
1909
+ * update: { label: "Update User" };
1910
+ * delete: { label: "Delete User" };
1911
+ * };
1912
+ * permissions: {
1913
+ * adminOnly: string[];
1914
+ * publicAccess: string[];
1915
+ * };
1916
+ * };
1917
+ *
1918
+ * products: {
1919
+ * actions: {
1920
+ * read: { label: "View Product" };
1921
+ * create: { label: "Add Product" };
1922
+ * update: { label: "Edit Product" };
1923
+ * discontinue: { label: "Discontinue Product" };
1924
+ * };
1925
+ * categories: string[];
1926
+ * pricing: {
1927
+ * currency: string;
1928
+ * taxRate: number;
1929
+ * };
1930
+ * };
1931
+ * }
1932
+ * }
1933
+ *
1934
+ * // Type-safe resource configuration access
1935
+ * type UserConfig = ResourceConfig<"users">;
1936
+ * type ProductConfig = ResourceConfig<"products">;
1937
+ *
1938
+ * // Function that works with any resource configuration
1939
+ * function setupResource<TResourceName extends ResourceName>(
1940
+ * name: TResourceName,
1941
+ * config: ResourceConfig<TResourceName>
1942
+ * ) {
1943
+ * console.log(`Setting up ${name} resource`);
1944
+ *
1945
+ * // Access standard properties
1946
+ * const actions = Object.keys(config.actions);
1947
+ * console.log(`Available actions: ${actions.join(', ')}`);
1948
+ *
1949
+ * // Access resource-specific properties with type safety
1950
+ * if (name === "users") {
1951
+ * const userConfig = config as ResourceConfig<"users">;
1952
+ * console.log(`Admin actions: ${userConfig.permissions.adminOnly.join(', ')}`);
1953
+ * } else if (name === "products") {
1954
+ * const productConfig = config as ResourceConfig<"products">;
1955
+ * console.log(`Categories: ${productConfig.categories.join(', ')}`);
1956
+ * console.log(`Currency: ${productConfig.pricing.currency}`);
1957
+ * }
1958
+ * }
1959
+ *
1960
+ * // Usage examples
1961
+ * const userResource: ResourceConfig<"users"> = {
1962
+ * actions: {
1963
+ * read: { label: "Read User" },
1964
+ * create: { label: "Create User" },
1965
+ * update: { label: "Update User" },
1966
+ * delete: { label: "Delete User" }
1967
+ * },
1968
+ * permissions: {
1969
+ * adminOnly: ["delete"],
1970
+ * publicAccess: ["read", "create"]
1971
+ * }
1972
+ * };
1973
+ *
1974
+ * const productResource: ResourceConfig<"products"> = {
1975
+ * actions: {
1976
+ * read: { label: "View Product" },
1977
+ * create: { label: "Add Product" },
1978
+ * update: { label: "Edit Product" },
1979
+ * discontinue: { label: "Discontinue Product" }
1980
+ * },
1981
+ * categories: ["electronics", "clothing", "books"],
1982
+ * pricing: {
1983
+ * currency: "USD",
1984
+ * taxRate: 0.08
1985
+ * }
1986
+ * };
1987
+ *
1988
+ * setupResource("users", userResource);
1989
+ * setupResource("products", productResource);
1990
+ * ```
1991
+ */
1992
+ export type ResourceConfig<TResourceName extends ResourceName> = ValidatedResources[TResourceName];
1993
+ /**
1994
+ * Type representing the action names for a specific resource.
1995
+ * This type extracts the literal action name strings from a resource's actions.
1996
+ *
1997
+ * This type provides compile-time safety by ensuring that only valid action names
1998
+ * for a specific resource can be used. It preserves literal types, enabling better
1999
+ * autocomplete and error detection.
2000
+ *
2001
+ * @type ResourceActionName
2002
+ * @template TResourceName - The name of the resource (optional, defaults to all resources)
2003
+ *
2004
+ * @example
2005
+ * ```typescript
2006
+ * // Basic usage with specific resource
2007
+ * import "reslib/resources";
2008
+ *
2009
+ * declare module "reslib/resources" {
2010
+ * interface Resources {
2011
+ * users: {
2012
+ * actions: {
2013
+ * read: { label: "Read User" };
2014
+ * create: { label: "Create User" };
2015
+ * update: { label: "Update User" };
2016
+ * archive: { label: "Archive User" };
2017
+ * }
2018
+ * };
2019
+ * }
2020
+ * }
2021
+ *
2022
+ * // Type-safe action names for users resource
2023
+ * type UserActionName = ResourceActionName<"users">;
2024
+ * // Result: "read" | "create" | "update" | "archive"
2025
+ *
2026
+ * function performUserAction(action: UserActionName) {
2027
+ * console.log(`Performing ${action} on user`);
2028
+ * }
2029
+ *
2030
+ * performUserAction("read"); // ✓ Valid
2031
+ * performUserAction("create"); // ✓ Valid
2032
+ * // performUserAction("delete"); // ✗ TypeScript error - not a valid user action
2033
+ * ```
2034
+ *
2035
+ * @example
2036
+ * ```typescript
2037
+ * // Generic function with resource-specific actions
2038
+ * function createActionHandler<TResourceName extends ResourceName>(
2039
+ * resourceName: TResourceName,
2040
+ * actionName: ResourceActionName<TResourceName>
2041
+ * ) {
2042
+ * return {
2043
+ * execute: () => console.log(`Executing ${actionName} on ${resourceName}`),
2044
+ * getActionName: (): ResourceActionName<TResourceName> => actionName
2045
+ * };
2046
+ * }
2047
+ *
2048
+ * // Usage with type safety
2049
+ * const userReadHandler = createActionHandler("users", "read");
2050
+ * // TypeScript knows actionName must be a valid user action
2051
+ *
2052
+ * const userCreateHandler = createActionHandler("users", "create");
2053
+ * // TypeScript knows actionName must be a valid user action
2054
+ *
2055
+ * // This would cause a TypeScript error:
2056
+ * // const invalidHandler = createActionHandler("users", "delete");
2057
+ * // Error: "delete" is not assignable to ResourceActionName<"users">
2058
+ * ```
2059
+ *
2060
+ * @example
2061
+ * ```typescript
2062
+ * // Runtime action validation
2063
+ * function isValidAction<TResourceName extends ResourceName>(
2064
+ * resourceName: TResourceName,
2065
+ * actionName: string
2066
+ * ): actionName is ResourceActionName<TResourceName> {
2067
+ * // This would typically check against the resource's defined actions
2068
+ * const validActions = getResourceActions(resourceName);
2069
+ * return validActions.includes(actionName as ResourceActionName<TResourceName>);
2070
+ * }
2071
+ *
2072
+ * // Usage
2073
+ * if (isValidAction("users", "read")) {
2074
+ * // TypeScript now knows actionName is ResourceActionName<"users">
2075
+ * const handler = createActionHandler("users", "read");
2076
+ * }
2077
+ * ```
2078
+ *
2079
+ * @example
2080
+ * ```typescript
2081
+ * // Action name arrays with type safety
2082
+ * function getAllActionNames<TResourceName extends ResourceName>(
2083
+ * resourceName: TResourceName
2084
+ * ): ResourceActionName<TResourceName>[] {
2085
+ * // Implementation would return all action names for the resource
2086
+ * return [] as ResourceActionName<TResourceName>[];
2087
+ * }
2088
+ *
2089
+ * // Usage
2090
+ * const userActions = getAllActionNames("users");
2091
+ * // TypeScript knows userActions contains only valid user action names
2092
+ *
2093
+ * userActions.forEach(action => {
2094
+ * // action is typed as ResourceActionName<"users">
2095
+ * console.log(`User action: ${action}`);
2096
+ * });
2097
+ * ```
2098
+ */
2099
+ export type ResourceActionName<TResourceName extends ResourceName = ResourceName> = GetResourceActionNames<ResourceConfig<TResourceName>>;
2100
+ /**
2101
+ * @interface ResourceActionTuple
2102
+ * Represents a tuple that contains a resource name and an action name.
2103
+ * This type is a union of two possible tuple formats: `ResourceActionTupleArray` and `ResourceActionTupleObject`.
2104
+ *
2105
+ * @template TResourceName - The name of the resource. Defaults to `ResourceName`.
2106
+ *
2107
+ * @example
2108
+ * ```typescript
2109
+ * // Using ResourceActionTupleArray
2110
+ * const actionTuple: ResourceActionTuple = ["users", "read"];
2111
+ *
2112
+ * // Using ResourceActionTupleObject
2113
+ * const actionTuple: ResourceActionTuple = { resourceName: "users", action: "read" };
2114
+ * ```
2115
+ *
2116
+ * @typeParam TResourceName - The name of the resource.
2117
+ * @default ResourceName
2118
+ *
2119
+ * @typedef {(ResourceActionTupleArray<TResourceName> | ResourceActionTupleObject<TResourceName>)} ResourceActionTuple
2120
+ *
2121
+ * @see {@link ResourceActionTupleArray} for the `ResourceActionTupleArray` type.
2122
+ * @see {@link ResourceActionTupleObject} for the `ResourceActionTupleObject` type.
2123
+ */
2124
+ export type ResourceActionTuple<TResourceName extends ResourceName> = ResourceActionTupleArray<TResourceName> | ResourceActionTupleObject<TResourceName>;
2125
+ /**
2126
+ * @interface ResourceActionTupleArray
2127
+ * Represents a tuple that contains a resource name and an action name in an array format.
2128
+ * This type is a tuple with two elements: the resource name and the action name.
2129
+ *
2130
+ * @template TResourceName - The name of the resource. Defaults to `ResourceName`.
2131
+ *
2132
+ * @example
2133
+ * ```typescript
2134
+ * const actionTuple: ResourceActionTupleArray = ["users", "read"];
2135
+ * ```
2136
+ *
2137
+ * @typeParam TResourceName - The name of the resource.
2138
+ * @default ResourceName
2139
+ *
2140
+ * @typedef {[TResourceName, ResourceActionName<TResourceName>]} ResourceActionTupleArray
2141
+ */
2142
+ export type ResourceActionTupleArray<TResourceName extends ResourceName> = [
2143
+ /**
2144
+ * The name of the resource.
2145
+ *
2146
+ * @type {TResourceName}
2147
+ */
2148
+ TResourceName,
2149
+ /**
2150
+ * The name of the action.
2151
+ *
2152
+ * @type {ResourceActionName<TResourceName>}
2153
+ */
2154
+ ResourceActionName<TResourceName>
2155
+ ];
2156
+ /**
2157
+ * @interface ResourceActionTupleObject
2158
+ * Represents a tuple that contains a resource name and an action name in an object format.
2159
+ * This type is an object with two properties: `resourceName` and `action`.
2160
+ *
2161
+ * @template TResourceName - The name of the resource. Defaults to `ResourceName`.
2162
+ *
2163
+ * @example
2164
+ * ```typescript
2165
+ * const actionTuple: ResourceActionTupleObject = { resourceName: "users", action: "read" };
2166
+ * ```
2167
+ *
2168
+ * @typeParam TResourceName - The name of the resource.
2169
+ * @default ResourceName
2170
+ *
2171
+ * @interface ResourceActionTupleObject
2172
+ */
2173
+ export interface ResourceActionTupleObject<TResourceName extends ResourceName> {
2174
+ /**
2175
+ * The name of the resource.
2176
+ *
2177
+ * @type {TResourceName}
2178
+ */
2179
+ resourceName: TResourceName;
2180
+ /**
2181
+ * The name of the action.
2182
+ *
2183
+ * @type {ResourceActionName<TResourceName>}
2184
+ */
2185
+ action: ResourceActionName<TResourceName>;
2186
+ }
2187
+ /**
2188
+ * @interface ResourceAction
2189
+ *
2190
+ * Represents the structure of an action that can be performed on a resource within the application.
2191
+ * This interface defines the essential properties that describe the action, allowing for a
2192
+ * consistent representation of actions across different resources.
2193
+ *
2194
+ * ### Properties
2195
+ *
2196
+ * - `label` (optional): A user-friendly label for the action. This label is typically
2197
+ * displayed in the user interface (UI) to help users understand what the action does.
2198
+ * It should be concise and descriptive.
2199
+ *
2200
+ * - `title` (optional): A short text that appears when the user hovers over the action
2201
+ * in the UI. The title provides extra information about the action, helping users
2202
+ * understand its purpose without cluttering the interface.
2203
+ *
2204
+ * ### Example Usage
2205
+ *
2206
+ * Here is an example of how the `ResourceAction` interface can be utilized:
2207
+ *
2208
+ * ```typescript
2209
+ * // Define a resource action for creating a new document
2210
+ * const createDocumentAction: ResourceAction = {
2211
+ * label: "Create Document",
2212
+ * title: "Click to add a new document."
2213
+ * };
2214
+ *
2215
+ * // Function to display action information
2216
+ * function displayActionInfo(action: ResourceAction) {
2217
+ * console.log(`Action: ${action.label}`);
2218
+ * console.log(`Title: ${action.title}`);
2219
+ * }
2220
+ *
2221
+ * // Example of displaying action information
2222
+ * displayActionInfo(createDocumentAction);
2223
+ * // Output:
2224
+ * // Action: Create Document
2225
+ * // Title: Create a new document in the system
2226
+ * // Tooltip: Click to add a new document.
2227
+ * ```
2228
+ *
2229
+ * ### Notes
2230
+ *
2231
+ * - The `ResourceAction` interface is designed to be flexible, allowing developers to
2232
+ * define actions with varying levels of details based on the needs of their application.
2233
+ * - By providing clear labels, titles, and tooltips, developers can enhance the user
2234
+ * experience and make the application more intuitive.
2235
+ */
2236
+ export interface ResourceAction {
2237
+ label?: string;
2238
+ title?: string;
2239
+ }
2240
+ type ResourceActionsRecord<TActions> = TActions extends Record<string, ResourceAction> ? TActions & Partial<ResourceDefaultActions> : never;
2241
+ /**
2242
+ * Type representing the actions record for a specific resource.
2243
+ * This type extracts the actions from a resource's definition, ensuring type safety.
2244
+ *
2245
+ * This type provides access to the complete actions object for a resource,
2246
+ * maintaining the exact structure and types as defined in the resource's configuration.
2247
+ * It's useful when you need to work with the entire set of actions for a resource.
2248
+ *
2249
+ * @type ResourceActions
2250
+ * @template TResourceName - The name of the resource
2251
+ *
2252
+ * @example
2253
+ * ```typescript
2254
+ * // Basic usage - getting resource actions type
2255
+ * import "reslib/resources";
2256
+ *
2257
+ * declare module "reslib/resources" {
2258
+ * interface Resources {
2259
+ * users: {
2260
+ * actions: {
2261
+ * read: { label: "Read User", title: "View user details" };
2262
+ * create: { label: "Create User", title: "Add new user" };
2263
+ * update: { label: "Update User", title: "Modify user data" };
2264
+ * archive: { label: "Archive User", title: "Soft delete user" };
2265
+ * }
2266
+ * };
2267
+ * }
2268
+ * }
2269
+ *
2270
+ * // Type-safe access to user actions
2271
+ * type UserActions = ResourceActions<"users">;
2272
+ * // Result: The complete actions record for users resource
2273
+ *
2274
+ * const userActions: UserActions = {
2275
+ * read: { label: "Read User", title: "View user details" },
2276
+ * create: { label: "Create User", title: "Add new user" },
2277
+ * update: { label: "Update User", title: "Modify user data" },
2278
+ * archive: { label: "Archive User", title: "Soft delete user" }
2279
+ * };
2280
+ * ```
2281
+ *
2282
+ * @example
2283
+ * ```typescript
2284
+ * // Function that works with resource actions
2285
+ * function validateResourceActions<TResourceName extends ResourceName>(
2286
+ * resourceName: TResourceName,
2287
+ * actions: ResourceActions<TResourceName>
2288
+ * ): boolean {
2289
+ * // Check if all required actions are present
2290
+ * const requiredActions: (keyof ResourceActions<TResourceName>)[] = ['read', 'create', 'update'];
2291
+ *
2292
+ * return requiredActions.every(action =>
2293
+ * action in actions && actions[action] !== undefined
2294
+ * );
2295
+ * }
2296
+ *
2297
+ * // Usage
2298
+ * const validUserActions = validateResourceActions("users", {
2299
+ * read: { label: "Read" },
2300
+ * create: { label: "Create" },
2301
+ * update: { label: "Update" },
2302
+ * archive: { label: "Archive" }
2303
+ * }); // Returns true
2304
+ * ```
2305
+ *
2306
+ * @example
2307
+ * ```typescript
2308
+ * // Building action handlers with type safety
2309
+ * function createActionHandlers<TResourceName extends ResourceName>(
2310
+ * resourceName: TResourceName,
2311
+ * actions: ResourceActions<TResourceName>
2312
+ * ) {
2313
+ * const handlers: Record<string, () => void> = {};
2314
+ *
2315
+ * // TypeScript knows the exact action names available
2316
+ * for (const actionName in actions) {
2317
+ * handlers[actionName] = () => {
2318
+ * const action = actions[actionName as keyof ResourceActions<TResourceName>];
2319
+ * console.log(`Executing ${action?.label} on ${resourceName}`);
2320
+ * };
2321
+ * }
2322
+ *
2323
+ * return handlers;
2324
+ * }
2325
+ *
2326
+ * // Usage
2327
+ * const userActionHandlers = createActionHandlers("users", {
2328
+ * read: { label: "Read User" },
2329
+ * create: { label: "Create User" },
2330
+ * update: { label: "Update User" }
2331
+ * });
2332
+ *
2333
+ * userActionHandlers.read(); // ✓ Valid - calls read handler
2334
+ * userActionHandlers.create(); // ✓ Valid - calls create handler
2335
+ * // userActionHandlers.delete(); // ✗ TypeScript error - delete not in user actions
2336
+ * ```
2337
+ *
2338
+ * @example
2339
+ * ```typescript
2340
+ * // Permission system based on resource actions
2341
+ * class PermissionManager {
2342
+ * private permissions = new Map<ResourceName, Set<string>>();
2343
+ *
2344
+ * grantPermission<TResourceName extends ResourceName>(
2345
+ * resourceName: TResourceName,
2346
+ * actions: (keyof ResourceActions<TResourceName>)[]
2347
+ * ) {
2348
+ * const current = this.permissions.get(resourceName) || new Set();
2349
+ * actions.forEach(action => current.add(action as string));
2350
+ * this.permissions.set(resourceName, current);
2351
+ * }
2352
+ *
2353
+ * hasPermission<TResourceName extends ResourceName>(
2354
+ * resourceName: TResourceName,
2355
+ * action: keyof ResourceActions<TResourceName>
2356
+ * ): boolean {
2357
+ * const resourcePerms = this.permissions.get(resourceName);
2358
+ * return resourcePerms?.has(action as string) ?? false;
2359
+ * }
2360
+ * }
2361
+ *
2362
+ * // Usage
2363
+ * const permManager = new PermissionManager();
2364
+ * permManager.grantPermission("users", ["read", "create"]);
2365
+ *
2366
+ * permManager.hasPermission("users", "read"); // true
2367
+ * permManager.hasPermission("users", "update"); // false
2368
+ * // permManager.hasPermission("users", "invalid"); // ✗ TypeScript error
2369
+ * ```
2370
+ */
2371
+ export type ResourceActions<TResourceName extends ResourceName> = Resources[TResourceName] extends {
2372
+ actions: Record<string, ResourceAction>;
2373
+ } ? ResourceActionsRecord<Resources[TResourceName]['actions']> : never;
2374
+ type GetResourceActionNames<TResource extends {
2375
+ actions?: Record<string, ResourceAction>;
2376
+ }> = keyof ResourceActionsRecord<TResource['actions']> & string;
2377
+ /**
2378
+ * ## ResourceDefaultActions Interface
2379
+ *
2380
+ * A foundational interface defining the standard CRUD (Create, Read, Update, Delete) actions
2381
+ * that can be performed on resources, plus an "all" action for comprehensive permissions.
2382
+ * This interface serves as the base set of actions that resource configurations can extend,
2383
+ * override, or supplement with custom actions.
2384
+ *
2385
+ * ### Purpose
2386
+ * The `ResourceDefaultActions` interface establishes a consistent set of core actions that
2387
+ * most resources will support. It provides a standardized foundation for resource management
2388
+ * while allowing flexibility for custom actions specific to particular resources.
2389
+ *
2390
+ * ### How It Works
2391
+ * - **Base Actions**: Defines the five fundamental actions (read, create, update, delete, all)
2392
+ * - **Extensibility**: Used in `ResourceActionsRecord` to create action records that can be extended
2393
+ * - **Type Safety**: Each action is typed as `ResourceAction`, ensuring consistent structure
2394
+ * - **Optional Override**: Resources can override these defaults or add custom actions alongside them
2395
+ *
2396
+ * ### Default Actions
2397
+ *
2398
+ * - **`read`**: Retrieve/view resource data (GET operations)
2399
+ * - **`create`**: Create new resource instances (POST operations)
2400
+ * - **`update`**: Modify existing resource instances (PUT/PATCH operations)
2401
+ * - **`delete`**: Remove resource instances (DELETE operations)
2402
+ * - **`all`**: Perform any action on the resource (wildcard permission)
2403
+ *
2404
+ * ### Template Parameters
2405
+ * This interface doesn't use generic parameters itself, but serves as a foundation for
2406
+ * action-based type operations and resource configurations.
2407
+ *
2408
+ * ### Examples
2409
+ *
2410
+ * #### Basic Resource with Default Actions
2411
+ * ```typescript
2412
+ * // A simple resource using only default actions
2413
+ * const userResource: ResourceBase = {
2414
+ * name: "users",
2415
+ * label: "Users",
2416
+ * actions: {
2417
+ * read: { label: "View Users" },
2418
+ * create: { label: "Create User" },
2419
+ * update: { label: "Update User" },
2420
+ * delete: { label: "Delete User" },
2421
+ * all: { label: "Full User Access" }
2422
+ * }
2423
+ * };
2424
+ * ```
2425
+ *
2426
+ * #### Resource Extending Default Actions
2427
+ * ```typescript
2428
+ * // Resource with default actions plus custom ones
2429
+ * const blogResource: ResourceBase = {
2430
+ * name: "posts",
2431
+ * label: "Blog Posts",
2432
+ * actions: {
2433
+ * // Default actions
2434
+ * read: { label: "View Posts" },
2435
+ * create: { label: "Write Post" },
2436
+ * update: { label: "Edit Post" },
2437
+ * delete: { label: "Delete Post" },
2438
+ * all: { label: "Full Post Access" },
2439
+ *
2440
+ * // Custom actions
2441
+ * publish: { label: "Publish Post" },
2442
+ * archive: { label: "Archive Post" },
2443
+ * feature: { label: "Feature Post" }
2444
+ * }
2445
+ * };
2446
+ * ```
2447
+ *
2448
+ * #### Permission System Using Default Actions
2449
+ * ```typescript
2450
+ * // Permission checking with default actions
2451
+ * class PermissionManager {
2452
+ * private permissions = new Map<string, Set<string>>();
2453
+ *
2454
+ * grantDefaultActions(resourceName: string) {
2455
+ * const key = `resource:${resourceName}`;
2456
+ * const actions = this.permissions.get(key) || new Set();
2457
+ *
2458
+ * // Grant all default actions
2459
+ * actions.add('read');
2460
+ * actions.add('create');
2461
+ * actions.add('update');
2462
+ * actions.add('delete');
2463
+ *
2464
+ * this.permissions.set(key, actions);
2465
+ * }
2466
+ *
2467
+ * hasPermission(resourceName: string, action: keyof ResourceDefaultActions): boolean {
2468
+ * const key = `resource:${resourceName}`;
2469
+ * const actions = this.permissions.get(key);
2470
+ * return actions?.has(action) ?? false;
2471
+ * }
2472
+ * }
2473
+ *
2474
+ * // Usage
2475
+ * const permManager = new PermissionManager();
2476
+ * permManager.grantDefaultActions('users');
2477
+ *
2478
+ * permManager.hasPermission('users', 'read'); // true
2479
+ * permManager.hasPermission('users', 'create'); // true
2480
+ * permManager.hasPermission('users', 'delete'); // true
2481
+ * permManager.hasPermission('users', 'all'); // false (not granted)
2482
+ * ```
2483
+ *
2484
+ * #### UI Component with Action-Based Rendering
2485
+ * ```typescript
2486
+ * // Component that renders different UI based on available actions
2487
+ * interface ResourceActionButtonProps {
2488
+ * resourceName: string;
2489
+ * action: keyof ResourceDefaultActions;
2490
+ * onClick: () => void;
2491
+ * children: React.ReactNode;
2492
+ * }
2493
+ *
2494
+ * function ResourceActionButton({
2495
+ * resourceName,
2496
+ * action,
2497
+ * onClick,
2498
+ * children
2499
+ * }: ResourceActionButtonProps) {
2500
+ * const hasPermission = usePermission(resourceName, action);
2501
+ *
2502
+ * if (!hasPermission) return null;
2503
+ *
2504
+ * return (
2505
+ * <button onClick={onClick} data-action={action}>
2506
+ * {children}
2507
+ * </button>
2508
+ * );
2509
+ * }
2510
+ *
2511
+ * // Usage in a resource management component
2512
+ * function UserManagement() {
2513
+ * return (
2514
+ * <div>
2515
+ * <ResourceActionButton resourceName="users" action="create">
2516
+ * Add User
2517
+ * </ResourceActionButton>
2518
+ *
2519
+ * <ResourceActionButton resourceName="users" action="read">
2520
+ * View Users
2521
+ * </ResourceActionButton>
2522
+ *
2523
+ * <ResourceActionButton resourceName="users" action="update">
2524
+ * Edit User
2525
+ * </ResourceActionButton>
2526
+ *
2527
+ * <ResourceActionButton resourceName="users" action="delete">
2528
+ * Delete User
2529
+ * </ResourceActionButton>
2530
+ * </div>
2531
+ * );
2532
+ * }
2533
+ * ```
2534
+ *
2535
+ * #### API Route Protection
2536
+ * ```typescript
2537
+ * // Middleware for protecting API routes based on default actions
2538
+ * function requireAction(resourceName: string, action: keyof ResourceDefaultActions) {
2539
+ * return (req: Request, res: Response, next: NextFunction) => {
2540
+ * const user = getCurrentUser(req);
2541
+ * const hasPermission = checkUserPermission(user, resourceName, action);
2542
+ *
2543
+ * if (!hasPermission) {
2544
+ * return res.status(403).json({
2545
+ * error: 'Forbidden',
2546
+ * message: `You don't have permission to ${action} ${resourceName}`
2547
+ * });
2548
+ * }
2549
+ *
2550
+ * next();
2551
+ * };
2552
+ * }
2553
+ *
2554
+ * // Usage in Express routes
2555
+ * app.get('/api/users', requireAction('users', 'read'), getUsers);
2556
+ * app.post('/api/users', requireAction('users', 'create'), createUser);
2557
+ * app.put('/api/users/:id', requireAction('users', 'update'), updateUser);
2558
+ * app.delete('/api/users/:id', requireAction('users', 'delete'), deleteUser);
2559
+ * ```
2560
+ *
2561
+ * #### Form Validation Based on Actions
2562
+ * ```typescript
2563
+ * // Form component that adapts based on available actions
2564
+ * interface SmartFormProps<T> {
2565
+ * resourceName: string;
2566
+ * initialData?: T;
2567
+ * onSubmit: (data: T) => void;
2568
+ * }
2569
+ *
2570
+ * function SmartForm<T>({ resourceName, initialData, onSubmit }: SmartFormProps<T>) {
2571
+ * const canCreate = usePermission(resourceName, 'create');
2572
+ * const canUpdate = usePermission(resourceName, 'update');
2573
+ * const isEditing = !!initialData;
2574
+ *
2575
+ * // Don't render form if no appropriate permissions
2576
+ * if (isEditing && !canUpdate) return { error: 'No permission to edit' };
2577
+ * if (!isEditing && !canCreate) return { error: 'No permission to create' };
2578
+ *
2579
+ * return (
2580
+ * <form onSubmit={handleSubmit(onSubmit)}>
2581
+ * <button type="submit">
2582
+ * {isEditing ? 'Update' : 'Create'}
2583
+ * </button>
2584
+ * </form>
2585
+ * );
2586
+ * }
2587
+ * ```
2588
+ *
2589
+ * ### Best Practices
2590
+ * - **Consistent Action Names**: Always use the standard action names (read, create, update, delete, all)
2591
+ * - **Clear Labels**: Provide descriptive labels for each action in resource definitions
2592
+ * - **Permission Granularity**: Use specific actions rather than relying only on "all"
2593
+ * - **Documentation**: Document custom actions that extend beyond the defaults
2594
+ * - **UI Consistency**: Use these actions consistently across different UI components
2595
+ *
2596
+ * ### Integration with Other Types
2597
+ * - **`ResourceActions<T>`**: Uses this interface as the base for resource-specific actions
2598
+ * - **`ResourceActionName<T>`**: Provides type-safe action names for specific resources
2599
+ * - **`ResourceBase`**: Resources can extend or override these default actions
2600
+ * - **`ResourceAction`**: The type definition for individual actions
2601
+ *
2602
+ * ### Migration Notes
2603
+ * When upgrading from custom action definitions, map your existing actions to these standard
2604
+ * names where possible. The "all" action can be used for comprehensive permissions that
2605
+ * previously used different naming conventions.
2606
+ *
2607
+ * @interface ResourceDefaultActions
2608
+ * @public
2609
+ *
2610
+ * @see {@link ResourceActions} - How these actions are used in resource configurations
2611
+ * @see {@link ResourceAction} - The structure of individual actions
2612
+ * @see {@link ResourceBase} - How resources define their available actions
2613
+ * @example
2614
+ * ```typescript
2615
+ * // Complete example of using ResourceDefaultActions in a resource definition
2616
+ * import "reslib/resources";
2617
+ *
2618
+ * declare module "reslib/resources" {
2619
+ * interface Resources {
2620
+ * users: {
2621
+ * actions: ResourceDefaultActions & {
2622
+ * // Extend with custom actions
2623
+ * resetPassword: { label: "Reset Password" };
2624
+ * activate: { label: "Activate Account" };
2625
+ * deactivate: { label: "Deactivate Account" };
2626
+ * }
2627
+ * };
2628
+ *
2629
+ * products: {
2630
+ * actions: ResourceDefaultActions & {
2631
+ * // Product-specific actions
2632
+ * restock: { label: "Restock Product" };
2633
+ * discontinue: { label: "Discontinue Product" };
2634
+ * feature: { label: "Feature Product" };
2635
+ * }
2636
+ * };
2637
+ * }
2638
+ * }
2639
+ *
2640
+ * // Type-safe usage
2641
+ * type UserActions = ResourceActions<"users">;
2642
+ * // Includes: read, create, update, delete, all, resetPassword, activate, deactivate
2643
+ *
2644
+ * type ProductActions = ResourceActions<"products">;
2645
+ * // Includes: read, create, update, delete, all, restock, discontinue, feature
2646
+ *
2647
+ * // Permission checking function
2648
+ * function canPerformAction<T extends ResourceName>(
2649
+ * resource: T,
2650
+ * action: keyof ResourceActions<T>
2651
+ * ): boolean {
2652
+ * // Implementation would check user permissions
2653
+ * return true; // Simplified for example
2654
+ * }
2655
+ *
2656
+ * // Usage
2657
+ * canPerformAction("users", "create"); // ✓ Valid - default action
2658
+ * canPerformAction("users", "resetPassword"); // ✓ Valid - custom action
2659
+ * canPerformAction("users", "restock"); // ✗ TypeScript error - not a user action
2660
+ * ```
2661
+ */
2662
+ export interface ResourceDefaultActions {
2663
+ /**
2664
+ * The read action for the resource.
2665
+ * This action is used to retrieve a specific resource.
2666
+ *
2667
+ * @type {ResourceAction}
2668
+ * @example
2669
+ * ```typescript
2670
+ * const readAction: ResourceAction = {
2671
+ * label: "Read Resource",
2672
+ * title: "Click to read a specific resource.",
2673
+ * };
2674
+ * ```
2675
+ */
2676
+ read: ResourceAction;
2677
+ /**
2678
+ * The create action for the resource.
2679
+ * This action is used to create a new resource.
2680
+ *
2681
+ * @type {ResourceAction}
2682
+ * @example
2683
+ * ```typescript
2684
+ * const createAction: ResourceAction = {
2685
+ * label: "Create Resource",
2686
+ * title: "Click to create a new resource.",
2687
+ * };
2688
+ * ```
2689
+ */
2690
+ create: ResourceAction;
2691
+ /**
2692
+ * The update action for the resource.
2693
+ * This action is used to update a specific resource.
2694
+ *
2695
+ * @type {ResourceAction}
2696
+ * @example
2697
+ * ```typescript
2698
+ * const updateAction: ResourceAction = {
2699
+ * label: "Update Resource",
2700
+ * title: "Click to update a specific resource.",
2701
+ * };
2702
+ * ```
2703
+ */
2704
+ update: ResourceAction;
2705
+ /**
2706
+ * The delete action for the resource.
2707
+ * This action is used to delete a specific resource.
2708
+ *
2709
+ * @type {ResourceAction}
2710
+ * @example
2711
+ * ```typescript
2712
+ * const deleteAction: ResourceAction = {
2713
+ * label: "Delete Resource",
2714
+ * title: "Click to delete a specific resource.",
2715
+ * };
2716
+ * ```
2717
+ */
2718
+ delete: ResourceAction;
2719
+ /**
2720
+ * The all action for the resource.
2721
+ * This action is used to perform all actions on the resource.
2722
+ *
2723
+ * @type {ResourceAction}
2724
+ * @example
2725
+ * ```typescript
2726
+ * const allAction: ResourceAction = {
2727
+ * label: "All Actions",
2728
+ * title: "Click to perform all actions on the resource.",
2729
+ * };
2730
+ * ```
2731
+ */
2732
+ all: ResourceAction;
2733
+ }
2734
+ /**
2735
+ * ## ResourceBase Interface
2736
+ *
2737
+ * The foundational interface that defines the structure and properties required for all resources
2738
+ * in the application. This interface serves as the base contract that all resource definitions
2739
+ * must implement to be considered valid within the resource management system.
2740
+ *
2741
+ * ### Purpose
2742
+ * The `ResourceBase` interface establishes the minimum structure that every resource must have,
2743
+ * ensuring consistency and type safety across all resource definitions. It acts as a constraint
2744
+ * that validates resource configurations during module augmentation, preventing invalid or
2745
+ * incomplete resource definitions from being accepted by the type system.
2746
+ *
2747
+ * ### How It Works
2748
+ * - **Module Augmentation**: Resources are defined by extending the global `Resources` interface
2749
+ * - **Validation**: The `ValidateResource<T>` type ensures each resource implements `ResourceBase`
2750
+ * - **Type Safety**: Only resources that conform to this interface are included in `ResourceName`
2751
+ * - **Extensibility**: Generic parameters allow resources to specify their own action types
2752
+ *
2753
+ * ### Template Parameters
2754
+ * - **TResourceName**: The specific resource name type (extends `ResourceName`)
2755
+ * - **Actions**: The record of actions available for this resource (extends `Record<string, ResourceAction>`)
2756
+ *
2757
+ * ### Examples
2758
+ *
2759
+ * #### Basic Resource Definition
2760
+ * ```typescript
2761
+ * // Define a simple user resource
2762
+ * const userResource: ResourceBase<"users"> = {
2763
+ * name: "users",
2764
+ * label: "Users",
2765
+ * title: "User Management",
2766
+ * actions: {
2767
+ * read: { label: "Read User" },
2768
+ * create: { label: "Create User" },
2769
+ * update: { label: "Update User" }
2770
+ * }
2771
+ * };
2772
+ * ```
2773
+ *
2774
+ * #### Advanced Resource with Custom Actions
2775
+ * ```typescript
2776
+ * // Define a product resource with custom actions
2777
+ * const productResource: ResourceBase<"products", {
2778
+ * read: ResourceAction;
2779
+ * create: ResourceAction;
2780
+ * update: ResourceAction;
2781
+ * discontinue: ResourceAction;
2782
+ * restock: ResourceAction;
2783
+ * }> = {
2784
+ * name: "products",
2785
+ * label: "Products",
2786
+ * title: "Product Catalog Management",
2787
+ * actions: {
2788
+ * read: { label: "View Product", title: "Display product details" },
2789
+ * create: { label: "Add Product", title: "Create new product entry" },
2790
+ * update: { label: "Edit Product", title: "Modify product information" },
2791
+ * discontinue: { label: "Discontinue Product", title: "Mark product as discontinued" },
2792
+ * restock: { label: "Restock Product", title: "Update product inventory" }
2793
+ * }
2794
+ * };
2795
+ * ```
2796
+ *
2797
+ * #### Module Augmentation Usage
2798
+ * ```typescript
2799
+ * // In your application's types file
2800
+ * import "reslib/resources";
2801
+ *
2802
+ * declare module "reslib/resources" {
2803
+ * interface Resources {
2804
+ * // All of these must implement ResourceBase
2805
+ * users: {
2806
+ * name: "users";
2807
+ * label: "Users";
2808
+ * actions: {
2809
+ * read: { label: "Read User" };
2810
+ * create: { label: "Create User" };
2811
+ * };
2812
+ * };
2813
+ *
2814
+ * posts: {
2815
+ * name: "posts";
2816
+ * label: "Posts";
2817
+ * title: "Blog Posts";
2818
+ * actions: {
2819
+ * read: { label: "Read Post" };
2820
+ * publish: { label: "Publish Post" };
2821
+ * };
2822
+ * };
2823
+ * }
2824
+ * }
2825
+ *
2826
+ * // TypeScript will enforce ResourceBase structure
2827
+ * // Invalid resources will cause compilation errors
2828
+ * ```
2829
+ *
2830
+ * #### Type-Safe Resource Operations
2831
+ * ```typescript
2832
+ * // Using ResourceBase for type-safe operations
2833
+ * function createResourceHandler<T extends ResourceBase>(
2834
+ * resource: T
2835
+ * ): ResourceHandler<T> {
2836
+ * return {
2837
+ * name: resource.name,
2838
+ * label: resource.label,
2839
+ * actions: Object.keys(resource.actions),
2840
+ * // TypeScript knows resource has name, label, and actions
2841
+ * };
2842
+ * }
2843
+ *
2844
+ * const userHandler = createResourceHandler(userResource);
2845
+ * // userHandler.name: "users"
2846
+ * // userHandler.label: "Users"
2847
+ * // userHandler.actions: string[]
2848
+ * ```
2849
+ *
2850
+ * #### Resource Validation
2851
+ * ```typescript
2852
+ * // Custom validation using ResourceBase structure
2853
+ * function validateResource(resource: any): resource is ResourceBase {
2854
+ * return (
2855
+ * typeof resource === 'object' &&
2856
+ * typeof resource.name === 'string' &&
2857
+ * typeof resource.actions === 'object' &&
2858
+ * resource.actions !== null
2859
+ * );
2860
+ * }
2861
+ *
2862
+ * // Usage
2863
+ * if (validateResource(someResource)) {
2864
+ * // TypeScript knows this is a ResourceBase
2865
+ * console.log(`Valid resource: ${someResource.name}`);
2866
+ * }
2867
+ * ```
2868
+ *
2869
+ * ### Best Practices
2870
+ * - **Consistent Naming**: Use lowercase resource names (e.g., "users", "products")
2871
+ * - **Descriptive Labels**: Provide clear, user-friendly labels for UI display
2872
+ * - **Comprehensive Actions**: Define all relevant actions for the resource's lifecycle
2873
+ * - **Optional Properties**: Use `label` and `title` for better UX, but they're optional
2874
+ * - **Type Safety**: Leverage the generic parameters for precise action typing
2875
+ * - **Documentation**: Document custom actions and their purposes
2876
+ *
2877
+ * ### Integration with Other Types
2878
+ * - **`Resources`**: Global interface where resources are defined via module augmentation
2879
+ * - **`ResourceName`**: Union type of all valid resource names (requires ResourceBase compliance)
2880
+ * - **`ResourceConfig<T>`**: Provides type-safe access to individual resource configurations
2881
+ * - **`ResourceActions<T>`**: Type-safe access to a resource's actions
2882
+ * - **`ValidateResource<T>`**: Type-level validation that checks ResourceBase implementation
2883
+ * - **`ValidatedResources`**: Maps all resources to ensure they extend ResourceBase
2884
+ *
2885
+ * ### Migration Notes
2886
+ * When adding new resources, ensure they implement all required `ResourceBase` properties.
2887
+ * The `name` property must match the key used in the `Resources` interface. Existing
2888
+ * resources that don't conform to this interface will cause TypeScript compilation errors
2889
+ * after upgrading, helping catch configuration issues early.
2890
+ *
2891
+ * @interface ResourceBase
2892
+ * @template TResourceName - The specific resource name type
2893
+ * @template Actions - The record of actions for this resource
2894
+ * @public
2895
+ *
2896
+ * @see {@link Resources} - Global interface for resource definitions
2897
+ * @see {@link ResourceName} - Union of all valid resource names
2898
+ * @see {@link ResourceConfig} - Type-safe resource configuration access
2899
+ * @see {@link ValidateResource} - Type-level validation of resource structure
2900
+ * @example
2901
+ * ```typescript
2902
+ * // Complete example of ResourceBase usage
2903
+ * import "reslib/resources";
2904
+ *
2905
+ * // Define custom action types for better type safety
2906
+ * interface UserActions {
2907
+ * read: ResourceAction;
2908
+ * create: ResourceAction;
2909
+ * update: ResourceAction;
2910
+ * delete: ResourceAction;
2911
+ * activate: ResourceAction;
2912
+ * deactivate: ResourceAction;
2913
+ * }
2914
+ *
2915
+ * // Create a fully typed resource
2916
+ * const userResource: ResourceBase<"users", UserActions> = {
2917
+ * name: "users",
2918
+ * label: "Users",
2919
+ * title: "User Account Management",
2920
+ * actions: {
2921
+ * read: {
2922
+ * label: "Read User",
2923
+ * title: "View user account details"
2924
+ * },
2925
+ * create: {
2926
+ * label: "Create User",
2927
+ * title: "Add new user account"
2928
+ * },
2929
+ * update: {
2930
+ * label: "Update User",
2931
+ * title: "Modify user account information"
2932
+ * },
2933
+ * delete: {
2934
+ * label: "Delete User",
2935
+ * title: "Remove user account"
2936
+ * },
2937
+ * activate: {
2938
+ * label: "Activate User",
2939
+ * title: "Enable user account access"
2940
+ * },
2941
+ * deactivate: {
2942
+ * label: "Deactivate User",
2943
+ * title: "Disable user account access"
2944
+ * }
2945
+ * }
2946
+ * };
2947
+ *
2948
+ * // Module augmentation for global availability
2949
+ * declare module "reslib/resources" {
2950
+ * interface Resources {
2951
+ * users: typeof userResource;
2952
+ * }
2953
+ * }
2954
+ *
2955
+ * // Type-safe usage throughout the application
2956
+ * type UserName = "users"; // From ResourceName union
2957
+ * type UserConfig = ResourceConfig<"users">; // Full type safety
2958
+ * type UserActionNames = ResourceActionName<"users">; // "read" | "create" | "update" | ...
2959
+ * ```
2960
+ */
2961
+ export interface ResourceBase<TResourceName extends ResourceName = ResourceName, Actions extends Record<string, ResourceAction> = Record<string, ResourceAction>> {
2962
+ /**
2963
+ * The internal name of the resource.
2964
+ *
2965
+ * This name is used within the system for referencing the resource programmatically.
2966
+ * It is often a short, unique identifier for the resource.
2967
+ *
2968
+ * @example
2969
+ * ```typescript
2970
+ * const userResource: ResourceBase = { name: "user" };
2971
+ * ```
2972
+ */
2973
+ name: TResourceName;
2974
+ /**
2975
+ * A user-friendly label for the resource.
2976
+ *
2977
+ * This is typically a shorter name intended for display in UI elements, such as dropdowns or buttons.
2978
+ * It helps users identify the resource within the user interface.
2979
+ *
2980
+ * @example
2981
+ * ```typescript
2982
+ * const productResource: ResourceBase = { label: "Product" };
2983
+ * ```
2984
+ */
2985
+ label?: string;
2986
+ /**
2987
+ * A short text that appears when the user hovers over the resource.
2988
+ * The title provides additional context or information about the resource.
2989
+ *
2990
+ * Typically used in user interfaces to clarify what a particular resource represents or to give instructions.
2991
+ *
2992
+ * @example
2993
+ * ```typescript
2994
+ * const userResource: ResourceBase = { title: "This resource manages user information." };
2995
+ * ```
2996
+ */
2997
+ title?: string;
2998
+ /**
2999
+ * The actions associated with this resource.
3000
+ * This is a well-typed record that preserves key inference while satisfying Record<string, ResourceAction>.
3001
+ *
3002
+ * @example
3003
+ * ```typescript
3004
+ * const userResource: ResourceBase = {
3005
+ * actions: {
3006
+ * read: { label: "Read User" },
3007
+ * create: { label: "Create User" },
3008
+ * archive: { label: "Archive User" } // Custom action
3009
+ * }
3010
+ * };
3011
+ *
3012
+ * // TypeScript infers: "read" | "create" | "archive"
3013
+ * type UserActionNames = GetResourceActionNames<typeof userResource>;
3014
+ *
3015
+ * // Still compatible with generic Record<string, ResourceAction>
3016
+ * const genericActions: Record<string, ResourceAction> = userResource.actions;
3017
+ * ```
3018
+ */
3019
+ actions: ResourceActionsRecord<Actions>;
3020
+ }
3021
+ /**
3022
+ * @type ResourcePrimaryKey
3023
+ *
3024
+ * Represents the type of primary keys that can be utilized in a resource.
3025
+ * This type is a union that provides flexibility in defining unique identifiers
3026
+ * for resources, accommodating various data structures and use cases.
3027
+ *
3028
+ * ### Possible Forms:
3029
+ *
3030
+ * - **Record<string, string | number>**: An object where the keys are strings
3031
+ * and the values can be either strings or numbers. This allows for composite keys
3032
+ * that consist of multiple fields.
3033
+ * - **Example**:
3034
+ * ```typescript
3035
+ * const compositeKey: TPrimaryKey = { userId: "user123", orderId: 456 };
3036
+ * // A composite key representing a user and their order
3037
+ * ```
3038
+ *
3039
+ * ### Notes:
3040
+ * - This type is particularly useful in scenarios where resources may have
3041
+ * different types of identifiers, such as in databases or APIs.
3042
+ * - Using a `Record` allows for more complex primary key structures, which can
3043
+ * be beneficial in applications that require composite keys.
3044
+ *
3045
+ * ### Use Cases:
3046
+ * - Defining primary keys in database models.
3047
+ * - Creating unique identifiers for API resources.
3048
+ * - Handling composite keys in data structures.
3049
+ *
3050
+ * ### Related Types:
3051
+ * - Consider using `ResourceBase` for defining the overall structure of a resource
3052
+ * that utilizes this primary key type.
3053
+ *
3054
+ * ### Example Usage:
3055
+ * Here’s how you might use the `ResourcePrimaryKey` type in a function that
3056
+ * retrieves a resource by its primary key:
3057
+ *
3058
+ * ```typescript
3059
+ * function getResourceById(id: TPrimaryKey): ResourceMeta {
3060
+ * // Implementation to list the resource based on the provided primary key
3061
+ * }
3062
+ *
3063
+ * const resource = getResourceById("user123"); // Fetching by string ID
3064
+ * const anotherResource = getResourceById(456); // Fetching by numeric ID
3065
+ * const compositeResource = getResourceById({ userId: "user123", orderId: 456 }); // Fetching by composite key
3066
+ * ```
3067
+ *
3068
+ * ### Summary:
3069
+ * The `ResourcePrimaryKey` type provides a versatile way to define primary keys
3070
+ * for resources, supporting simple and complex identifiers. This flexibility is
3071
+ * essential for applications that manage diverse data structures and require
3072
+ * unique identification of resources.
3073
+ */
3074
+ export type ResourcePrimaryKey = string | number | object;
3075
+ /**
3076
+ * @interface ResourceDataService
3077
+ *
3078
+ * Represents a data provider interface for managing resources.
3079
+ * This interface defines methods for performing CRUD (Create, Read, Update, Delete)
3080
+ * operations on resources, allowing for flexible data management.
3081
+ *
3082
+ * @template DataType - The type of the resource data being managed. Defaults to `any`,
3083
+ * allowing for flexibility in the type of data handled by the provider.
3084
+ *
3085
+ * @template TPrimaryKey - The type of the primary key used to identify resources.
3086
+ *
3087
+ *
3088
+ * ### Methods:
3089
+ *
3090
+ * - **create(record: Partial<DataType>)**: Creates a new resource record.
3091
+ * - **Parameters**:
3092
+ * - `record`: The data for the new resource to be created.
3093
+ * - **Returns**: A promise that resolves to an `DataType`,
3094
+ * indicating the success or failure of the operation.
3095
+ * - **Example**:
3096
+ * ```typescript
3097
+ * const result = await dataProvider.create({ name: "New ResourceMeta" });
3098
+ * ```
3099
+ *
3100
+ * - **update(primaryKey: TPrimaryKey, updatedData: Partial<DataType>)**: Updates an existing resource record.
3101
+ * - **Parameters**:
3102
+ * - `primaryKey`: The primary key of the resource to update.
3103
+ * - `updatedData`: An object containing the updated data for the resource.
3104
+ * - **Returns**: A promise that resolves to an `DataType`,
3105
+ * indicating the success or failure of the update operation.
3106
+ * - **Example**:
3107
+ * ```typescript
3108
+ * const result = await dataProvider.update("resourceId", { name: "Updated ResourceMeta" });
3109
+ * ```
3110
+ *
3111
+ * - **delete(primaryKey: TPrimaryKey)**: Deletes a resource record by its primary key.
3112
+ * - **Parameters**:
3113
+ * - `primaryKey`: The primary key of the resource to delete.
3114
+ * indicating the success or failure of the delete operation.
3115
+ * - **Example**:
3116
+ * ```typescript
3117
+ * const result = await dataProvider.delete("resourceId");
3118
+ * ```
3119
+ *
3120
+ * - **findOne(primaryKey: TPrimaryKey)**: Retrieves a single resource record by its primary key.
3121
+ * - **Parameters**:
3122
+ * - `primaryKey`: The primary key of the resource to retrieve.
3123
+ * - **Returns**: A promise that resolves to an `DataType | null`,
3124
+ * containing the requested resource record or null if not found.
3125
+ * - **Example**:
3126
+ * ```typescript
3127
+ * const result = await dataProvider.findOne("resourceId");
3128
+ * ```
3129
+ *
3130
+ * - **findOneOrFail(primaryKey: TPrimaryKey)**: Retrieves a single resource record by its primary key or throws an error if not found.
3131
+ * - **Parameters**:
3132
+ * - `primaryKey`: The primary key of the resource to retrieve.
3133
+ * - **Returns**: A promise that resolves to an `DataType`,
3134
+ * containing the requested resource record.
3135
+ * - **Example**:
3136
+ * ```typescript
3137
+ * const result = await dataProvider.findOneOrFail("resourceId");
3138
+ * ```
3139
+ *
3140
+ * - **find(options?: ResourceQueryOptions<DataType>)**: Retrieves multiple resource records based on query options.
3141
+ * - **Parameters**:
3142
+ * - `options`: Optional query options to filter the results.
3143
+ * - **Returns**: A promise that resolves to an `ResourcePaginatedResult<DataType>`,
3144
+ * containing the list of resource records.
3145
+ * - **Example**:
3146
+ * ```typescript
3147
+ * const result = await dataProvider.find({ limit: 10, skip: 0 });
3148
+ * ```
3149
+ *
3150
+ * - **findAndCount(options?: ResourceQueryOptions<DataType>)**: Retrieves multiple resource records and the total count based on query options.
3151
+ * - **Parameters**:
3152
+ * - `options`: Optional query options to filter the results.
3153
+ * - **Returns**: A promise that resolves to an `ResourcePaginatedResult<DataType>`,
3154
+ * containing the list of resource records and the total count.
3155
+ * - **Example**:
3156
+ * ```typescript
3157
+ * const result = await dataProvider.findAndCount({ limit: 10, skip: 0 });
3158
+ * ```
3159
+ *
3160
+ * - **createMany(data: Partial<DataType>[])**: Creates multiple resource records.
3161
+ * - **Parameters**:
3162
+ * - `data`: An array of data for the new resources to be created.
3163
+ * - **Returns**: A promise that resolves to an `DataType[]`,
3164
+ * indicating the success or failure of the operation.
3165
+ * - **Example**:
3166
+ * ```typescript
3167
+ * const result = await dataProvider.createMany([{ name: "ResourceMeta 1" }, { name: "ResourceMeta 2" }]);
3168
+ * ```
3169
+ *
3170
+ * - **updateMany(data: ResourceManyCriteria<TPrimaryKey,DataType>)**: Updates multiple resource records.
3171
+ * - **Parameters**:
3172
+ * - `data`: An object containing the updated data for the resources.
3173
+ * - **Returns**: A promise that resolves to an `DataType[]`,
3174
+ * indicating the success or failure of the update operation.
3175
+ * - **Example**:
3176
+ * ```typescript
3177
+ * const result = await dataProvider.updateMany({ status: "active" });
3178
+ * ```
3179
+ *
3180
+ * - **deleteMany(criteria: ResourceQueryOptions<DataType>)**: Deletes multiple resource records based on criteria.
3181
+ * - **Parameters**:
3182
+ * - `criteria`: The criteria to filter which resources to delete.
3183
+ * - **Returns**: A promise that resolves to an `number`,
3184
+ * indicating the success or failure of the delete operation.
3185
+ * - **Example**:
3186
+ * ```typescript
3187
+ * const result = await dataProvider.deleteMany({ filters: { status: "inactive" } });
3188
+ * ```
3189
+ *
3190
+ * - **count(options?: ResourceQueryOptions<DataType>)**: Counts the total number of resource records based on query options.
3191
+ * - **Parameters**:
3192
+ * - `options`: Optional query options to filter the count.
3193
+ * - **Returns**: A promise that resolves to an `number`,
3194
+ * containing the total count of resource records.
3195
+ * - **Example**:
3196
+ * ```typescript
3197
+ * const result = await dataProvider.count({ filters: { status: "active" } });
3198
+ * ```
3199
+ *
3200
+ * - **exists(primaryKey: TPrimaryKey)**: Checks if a resource record exists by its primary key.
3201
+ * - **Parameters**:
3202
+ * - `primaryKey`: The primary key of the resource to check.
3203
+ * - **Returns**: A promise that resolves to an `boolean`,
3204
+ * indicating whether the resource exists.
3205
+ * - **Example**:
3206
+ * ```typescript
3207
+ * const result = await dataProvider.exists("resourceId");
3208
+ * ```
3209
+ *
3210
+ * - **distinct?(field: keyof DataType, options?: ResourceQueryOptions<DataType>)**: Retrieves distinct values for a specified field.
3211
+ * - **Parameters**:
3212
+ * - `field`: The field for which to retrieve distinct values.
3213
+ * - `options`: Optional query options to filter the results.
3214
+ * - **Returns**: A promise that resolves to an `DataType[]`,
3215
+ * containing the distinct values.
3216
+ * - **Example**:
3217
+ * ```typescript
3218
+ * const result = await dataProvider.distinct("category");
3219
+ * ```
3220
+ *
3221
+ * - **aggregate?(pipeline: any[])**: Performs aggregation operations on the resource data.
3222
+ * - **Parameters**:
3223
+ * - `pipeline`: An array representing the aggregation pipeline.
3224
+ * - **Returns**: A promise that resolves to an `number`,
3225
+ * containing the aggregated results.
3226
+ * - **Example**:
3227
+ * ```typescript
3228
+ * const result = await dataProvider.aggregate([{ $group: { _id: "$category", count: { $sum: 1 } } }]);
3229
+ * ```
3230
+ *
3231
+ * ### Notes:
3232
+ * - This interface provides a standard way to interact with resource data,
3233
+ * ensuring that all operations return consistent results.
3234
+ * - The use of promises allows for asynchronous operations, making it suitable
3235
+ * for use in modern web applications.
3236
+ *
3237
+ * ### Example Usage:
3238
+ * Here’s how you might implement the `ResourceDataService` interface:
3239
+ *
3240
+ * ```typescript
3241
+ * class MyDataProvider implements ResourceDataService<MyResourceType> {
3242
+ * async create(record: MyResourceType) {
3243
+ * // Implementation for creating a resource
3244
+ * }
3245
+ *
3246
+ * async list() {
3247
+ * // Implementation for fetching resources
3248
+ * }
3249
+ *
3250
+ * // Implement other methods...
3251
+ * }
3252
+ * ```
3253
+ *
3254
+ * ### Summary:
3255
+ * The `ResourceDataService` interface defines a comprehensive set of methods
3256
+ * for managing resources, facilitating CRUD operations and ensuring a consistent
3257
+ * approach to data handling in applications.
3258
+ */
3259
+ export interface ResourceDataService<DataType = unknown, TPrimaryKey extends ResourcePrimaryKey = ResourcePrimaryKey> {
3260
+ /***
3261
+ * Creates a new resource record.
3262
+ * @template T - The type of the resource data being created.
3263
+ * @param record The data for the new resource to be created.
3264
+ * @returns A promise that resolves to an `DataType`,
3265
+ * indicating the success or failure of the operation.
3266
+ * @example
3267
+ * ```typescript
3268
+ * const result = await dataProvider.create({ name: "New ResourceMeta" });
3269
+ * ```
3270
+ */
3271
+ create<T extends DataType>(record: T): Promise<DataType>;
3272
+ /***
3273
+ * Updates an existing resource record.
3274
+ * @template T - The type of the resource data being updated.
3275
+ * @param primaryKey The primary key of the resource to update.
3276
+ * @param updateData An object containing the updated data for the resource.
3277
+ * @returns A promise that resolves to an `DataType`,
3278
+ * indicating the success or failure of the update operation.
3279
+ * @example
3280
+ * ```typescript
3281
+ * const result = await dataProvider.update("resourceId", { name: "Updated ResourceMeta" });
3282
+ * ```
3283
+ */
3284
+ update<T extends Partial<DataType>>(primaryKey: TPrimaryKey, updateData: T): Promise<DataType>;
3285
+ /***
3286
+ * Deletes a resource record by its primary key.
3287
+ * @param primaryKey The primary key of the resource to delete.
3288
+ * @returns A promise that resolves to an `Promise<boolean>`,
3289
+ * indicating the success or failure of the delete operation.
3290
+ * @example
3291
+ * ```typescript
3292
+ * const result = await dataProvider.delete("resourceId");
3293
+ * ```
3294
+ */
3295
+ delete(primaryKey: TPrimaryKey): Promise<boolean>;
3296
+ /***
3297
+ * Retrieves a single resource record by its primary key.
3298
+ * @param options The primary key or query options of the resource to retrieve.
3299
+ * @returns A promise that resolves to an `DataType | null`,
3300
+ * containing the requested resource record or null if not found.
3301
+ * @example
3302
+ * ```typescript
3303
+ * const result = await dataProvider.findOne("resourceId");
3304
+ * ```
3305
+ * @example
3306
+ * ```typescript
3307
+ * const result = await dataProvider.findOne({ firstName: 1 });
3308
+ * ```
3309
+ */
3310
+ findOne(options: TPrimaryKey | ResourceQueryOptions<DataType>): Promise<DataType | null>;
3311
+ /***
3312
+ * Retrieves a single resource record by its primary key or throws an error if not found.
3313
+ * @param primaryKey The primary key or query options of the resource to retrieve.
3314
+ * @returns A promise that resolves to an `DataType`,
3315
+ * containing the requested resource record.
3316
+ * @example
3317
+ * ```typescript
3318
+ * const result = await dataProvider.findOneOrFail("resourceId");
3319
+ * ```
3320
+ */
3321
+ findOneOrFail(options: TPrimaryKey | ResourceQueryOptions<DataType>): Promise<DataType>;
3322
+ /***
3323
+ * Retrieves multiple resource records based on query options.
3324
+ * @param options Optional query options to filter the results.
3325
+ * @returns A promise that resolves to an `DataType[]`,
3326
+ * containing the list of resource records.
3327
+ * @example
3328
+ * ```typescript
3329
+ * const result = await dataProvider.find({ limit: 10, skip: 0 });
3330
+ * ```
3331
+ */
3332
+ find(options?: ResourceQueryOptions<DataType>): Promise<DataType[]>;
3333
+ /***
3334
+ * Retrieves multiple resource records and the total count based on query options.
3335
+ * @param options Optional query options to filter the results.
3336
+ * @returns A promise that resolves to an `DataType[]`,
3337
+ * containing the list of resource records and the total count.
3338
+ * @example
3339
+ * ```typescript
3340
+ * const result = await dataProvider.findAndCount({ limit: 10, skip: 0 });
3341
+ * ```
3342
+ */
3343
+ findAndCount(options?: ResourceQueryOptions<DataType>): Promise<[DataType[], number]>;
3344
+ /***
3345
+ * Retrieves multiple resource records and paginates the results.
3346
+ * @param options Optional query options to filter the results.
3347
+ * @returns A promise that resolves to an `ResourcePaginatedResult<DataType>`,
3348
+ * containing the list of resource records and the total count.
3349
+ * @example
3350
+ * ```typescript
3351
+ * const result = await dataProvider.findAndPaginate({ limit: 10, skip: 0 });
3352
+ */
3353
+ findAndPaginate(options?: ResourceQueryOptions<DataType>): Promise<ResourcePaginatedResult<DataType>>;
3354
+ /***
3355
+ * Creates multiple resource records.
3356
+ * @template T - The type of the resource data being created.
3357
+ * @param data An array of data for the new resources to be created.
3358
+ * @returns A promise that resolves to an `DataType[]`,
3359
+ * indicating the success or failure of the operation.
3360
+ * @example
3361
+ * ```typescript
3362
+ * const result = await dataProvider.createMany([{ name: "ResourceMeta 1" }, { name: "ResourceMeta 2" }]);
3363
+ * ```
3364
+ */
3365
+ createMany<T extends DataType>(data: T[]): Promise<DataType[]>;
3366
+ /***
3367
+ * Updates multiple resource records.
3368
+ * @template T - The type of the resource data being updated.
3369
+ * @param criteria An object containing the filter criteria for the resources.
3370
+ * @param data An object containing the updated data for the resources.
3371
+ * @returns A promise that resolves to an `DataType[]`,
3372
+ * indicating the success or failure of the update operation.
3373
+ * @example
3374
+ * ```typescript
3375
+ * const result = await dataProvider.updateMany({ status: "active" });
3376
+ * ```
3377
+ */
3378
+ updateMany<T extends Partial<DataType>>(criteria: ResourceManyCriteria<DataType, TPrimaryKey>, data: T): Promise<number>;
3379
+ /**
3380
+ *
3381
+ * @param criteria The criteria to filter which resources to delete.
3382
+ * @returns A promise that resolves to an `number`,
3383
+ * indicating the success or failure of the delete operation.
3384
+ * @example
3385
+ * ```typescript
3386
+ * const result = await dataProvider.deleteMany({ filters: { status: "inactive" } });
3387
+ * ```
3388
+ */
3389
+ deleteMany(criteria: ResourceManyCriteria<DataType, TPrimaryKey>): Promise<number>;
3390
+ /***
3391
+ * Counts the total number of resource records based on query options.
3392
+ * @param options Optional query options to filter the count.
3393
+ * @returns A promise that resolves to an `number`,
3394
+ * containing the total count of resource records.
3395
+ * @example
3396
+ * ```typescript
3397
+ * const result = await dataProvider.count({ filters: { status: "active" } });
3398
+ * ```
3399
+ */
3400
+ count(options?: ResourceQueryOptions<DataType>): Promise<number>;
3401
+ /**
3402
+ *
3403
+ * @param primaryKey The primary key of the resource to check.
3404
+ * @returns A promise that resolves to an `boolean`,
3405
+ * indicating whether the resource exists.
3406
+ * @example
3407
+ * ```typescript
3408
+ * const result = await dataProvider.exists("resourceId");
3409
+ * ```
3410
+ */
3411
+ exists(primaryKey: TPrimaryKey): Promise<boolean>;
3412
+ }
3413
+ /**
3414
+ * @type ResourceManyCriteria
3415
+ *
3416
+ * Represents the criteria used for multiple actions on a resource.
3417
+ * This type allows for flexible definitions of what constitutes an update,
3418
+ * accommodating various scenarios based on the primary key or partial data.
3419
+ *
3420
+ * ### Type Parameters
3421
+ * - **TPrimaryKey**: The type of the primary key used to identify resources.
3422
+ * Defaults to `ResourcePrimaryKey`, which can be a string, number, or object.
3423
+ * - **DataType**: The type of data associated with the resource. Defaults to `Dictionary`,
3424
+ * which is a generic dictionary type allowing for any key-value pairs.
3425
+ *
3426
+ * ### Possible Forms
3427
+ * The `ResourceManyCriteria` can take one of the following forms:
3428
+ *
3429
+ * 1. **Array of Primary Keys**:
3430
+ * - An array of primary keys that uniquely identify the resources to be updated.
3431
+ * - **Example**:
3432
+ * ```typescript
3433
+ * const updateCriteria: ResourceManyCriteria<string> = ["user123", "user456"];
3434
+ * ```
3435
+ *
3436
+ * 2. **Partial Data Object**:
3437
+ * - An object containing partial data that represents the fields to be updated.
3438
+ * - **Example**:
3439
+ * ```typescript
3440
+ * const updateCriteria: ResourceManyCriteria<string, { name: string; age: number }> = {
3441
+ * name: "John Doe",
3442
+ * age: 30
3443
+ * };
3444
+ * ```
3445
+ *
3446
+ * 3. **Record of Data Fields**:
3447
+ * - A record where each key corresponds to a field in the resource, allowing for
3448
+ * updates to specific fields.
3449
+ * - **Example**:
3450
+ * ```typescript
3451
+ * const updateCriteria: ResourceManyCriteria<string, { name: string; age: number }> = {
3452
+ * name: "Jane Doe",
3453
+ * age: 25
3454
+ * };
3455
+ * ```
3456
+ *
3457
+ * ### Notes
3458
+ * - This type is particularly useful in scenarios where resources can be updated
3459
+ * based on different criteria, such as updating multiple records at once or
3460
+ * modifying specific fields of a resource.
3461
+ * - By leveraging TypeScript's generics, this type provides strong typing and
3462
+ * flexibility, ensuring that the criteria used for updates are well-defined and
3463
+ * type-safe.
3464
+ *
3465
+ * ### Example Usage
3466
+ * Here’s how you might use the `ResourceManyCriteria` type in a function that
3467
+ * updates resources:
3468
+ *
3469
+ * ```typescript
3470
+ * function updateResources(criteria: ResourceManyCriteria<string, { name: string; age: number }>) {
3471
+ * // Implementation to update resources based on the provided criteria
3472
+ * }
3473
+ *
3474
+ * // Example of updating resources by primary keys
3475
+ * updateResources(["user123", "user456"]);
3476
+ *
3477
+ * // Example of updating resources with partial data
3478
+ * updateResources({ name: "John Doe", age: 30 });
3479
+ * ```
3480
+ * @typeParam DataType - The type of data associated with the resource.
3481
+ * @default any
3482
+ * @typeParam TPrimaryKey - The type of the primary key used to identify resources.
3483
+ * @default ResourcePrimaryKey
3484
+ * @see {@link ResourcePrimaryKey} for the `ResourcePrimaryKey` type.
3485
+ * @see {@link MongoQuery} for the `MongoQuery` type.
3486
+ * @example
3487
+ * // Example of using ResourceManyCriteria
3488
+ * const criteria: ResourceManyCriteria<string, { name: string; age: number }> = {
3489
+ * name: "John Doe",
3490
+ * age: 30
3491
+ * };
3492
+ * @Example
3493
+ * // Example of using ResourceManyCriteria with an array of primary keys
3494
+ * const criteria: ResourceManyCriteria<string, { name: string; age: number }> = [
3495
+ * "user123",
3496
+ * "user456"
3497
+ * ];
3498
+ */
3499
+ export type ResourceManyCriteria<DataType = unknown, TPrimaryKey extends ResourcePrimaryKey = ResourcePrimaryKey> = TPrimaryKey[] | MongoQuery<DataType>;
3500
+ /**
3501
+ * Interface representing options for fetching resources.
3502
+ *
3503
+ * This interface allows you to specify various options when retrieving resources,
3504
+ * including filters to narrow down the results based on specific criteria.
3505
+ *
3506
+ * @template DataType - The type of data being fetched. Defaults to 'any'.
3507
+ * @example
3508
+ * // Example of using ResourceQueryOptions
3509
+ * const fetchOptions: ResourceQueryOptions<MyDataType, string> = {
3510
+ * filters: {
3511
+ * status: { $eq: "active" }, // Filter for active resources
3512
+ * category: { $in: ["A", "B"] } // Filter for categories A or B
3513
+ * },
3514
+ * orderBy: { createdAt: 'desc' }, // Sort by creation date descending
3515
+ * limit: 20, // Limit results to 20
3516
+ * skip: 0 // Do not skip any results
3517
+ * };
3518
+ */
3519
+ export interface ResourceQueryOptions<DataType = unknown> {
3520
+ /** Fields to include in the response. */
3521
+ fields?: Array<keyof DataType extends never ? string : keyof DataType>;
3522
+ relations?: string[];
3523
+ orderBy?: ResourceQueryOrderBy<DataType>;
3524
+ limit?: number;
3525
+ skip?: number;
3526
+ page?: number;
3527
+ /** Include relationships or nested resources. */
3528
+ include?: ResourceName[];
3529
+ /** Include only distinct results or specific fields for distinct values. */
3530
+ distinct?: boolean | Array<keyof DataType>;
3531
+ /** Include soft-deleted resources. */
3532
+ includeDeleted?: boolean;
3533
+ /** Cache the results for performance optimization. */
3534
+ cache?: boolean;
3535
+ /** Time-to-Live for cache, in seconds. */
3536
+ cacheTTL?: number;
3537
+ /**
3538
+ * Where clause to filter the results.
3539
+ * Resources are filtered using a MongoDB-like query syntax.
3540
+ * This allows you to specify conditions for filtering resources based on various criteria.
3541
+ *
3542
+ * @type {MongoQuery}
3543
+ * @see {@link https://www.mongodb.com/docs/manual/reference/operator/query/} for more information on MongoDB query operators.
3544
+ * @example
3545
+ * const queryOptions: ResourceQueryOptions<{ id: number, name: string }> = {
3546
+ * where: {
3547
+ * name : "John",
3548
+ * surname : "Doe"
3549
+ * },
3550
+ * orderBy: { name: 'asc' },
3551
+ * limit: 10,
3552
+ * skip: 0
3553
+ * };
3554
+ * @see {@link MongoQuery} for more information on where clauses.
3555
+ * @example
3556
+ * const queryOptions: ResourceQueryOptions<{ id: number, name: string }> = {
3557
+ * where: {
3558
+ * name : "John",
3559
+ * surname : "Doe"
3560
+ * },
3561
+ * orderBy: { name: 'asc' },
3562
+ * limit: 10,
3563
+ * skip: 0
3564
+ * };
3565
+ */
3566
+ where?: MongoQuery<DataType>;
3567
+ }
3568
+ /**
3569
+ * @interface ResourcePaginatedResult
3570
+ *
3571
+ * Represents the result of a paginated resource list operation.
3572
+ * This interface encapsulates the data retrieved from a paginated API response,
3573
+ * along with metadata about the pagination state and navigation links.
3574
+ *
3575
+ * @template DataType - The type of the resources being fetched. Defaults to `any`.
3576
+ *
3577
+ * ### Properties:
3578
+ *
3579
+ * - **data**: An array of fetched resources.
3580
+ * - **Type**: `DataType[]`
3581
+ * - **Description**: This property contains the list of resources retrieved from the API.
3582
+ * - **Example**:
3583
+ * ```typescript
3584
+ * const result: ResourcePaginatedResult<User> = {
3585
+ * data: [
3586
+ * { id: 1, name: "John Doe" },
3587
+ * { id: 2, name: "Jane Smith" }
3588
+ * ],
3589
+ * meta: { totalItems: 100, currentPage: 1, pageSize: 10, totalPages: 10 },
3590
+ * links: { first: null, previous: null, next: "http://api.example.com/users?page=2", last: "http://api.example.com/users?page=10" }
3591
+ * };
3592
+ * ```
3593
+ *
3594
+ * - **meta**: Metadata about the pagination state.
3595
+ * - **Type**: `Object`
3596
+ * - **Description**: This property provides information about the total number of items, the current page, the page size, and the total number of pages.
3597
+ * - **Properties**:
3598
+ * - **totalItems**: The total number of items available across all pages.
3599
+ * - **Type**: `number`
3600
+ * - **Example**: `100` indicates there are 100 items in total.
3601
+ * - **currentPage**: The current page number being viewed.
3602
+ * - **Type**: `number`
3603
+ * - **Example**: `1` indicates the first page.
3604
+ * - **pageSize**: The number of items displayed per page.
3605
+ * - **Type**: `number`
3606
+ * - **Example**: `10` indicates that 10 items are shown per page.
3607
+ * - **totalPages**: The total number of pages available.
3608
+ * - **Type**: `number`
3609
+ * - **Example**: `10` indicates there are 10 pages in total.
3610
+ *
3611
+ * - **links**: Navigation links for paginated results.
3612
+ * - **Type**: `Object`
3613
+ * - **Description**: This property contains URLs for navigating through the paginated results.
3614
+ * - **Properties**:
3615
+ * - **first**: URL to the first page of results.
3616
+ * - **Type**: `string | null`
3617
+ * - **Example**: `"http://api.example.com/users?page=1"` or `null` if there is no first page.
3618
+ * - **previous**: URL to the previous page of results.
3619
+ * - **Type**: `string | null`
3620
+ * - **Example**: `"http://api.example.com/users?page=1"` or `null` if there is no previous page.
3621
+ * - **next**: URL to the next page of results.
3622
+ * - **Type**: `string | null`
3623
+ * - **Example**: `"http://api.example.com/users?page=2"` or `null` if there is no next page.
3624
+ * - **last**: URL to the last page of results.
3625
+ * - **Type**: `string | null`
3626
+ * - **Example**: `"http://api.example.com/users?page=10"` or `null` if there is no last page.
3627
+ *
3628
+ * ### Example Usage:
3629
+ * Here’s how you might use the `ResourcePaginatedResult` interface in a function that fetches paginated user data:
3630
+ *
3631
+ * ```typescript
3632
+ * async function fetchUsers(page: number): Promise<ResourcePaginatedResult<User>> {
3633
+ * const response = await list(`http://api.example.com/users?page=${page}`);
3634
+ * const result: ResourcePaginatedResult<User> = await response.json();
3635
+ * return result;
3636
+ * }
3637
+ *
3638
+ * fetchUsers(1).then(result => {
3639
+ * console.log(`Total Users: ${result.meta.totalItems}`);
3640
+ * console.log(`Current Page: ${result.meta.currentPage}`);
3641
+ * console.log(`Users on this page:`, result.data);
3642
+ * });
3643
+ * ```
3644
+ *
3645
+ * ### Notes:
3646
+ * - This interface is particularly useful for APIs that return large datasets,
3647
+ * allowing clients to retrieve data in manageable chunks.
3648
+ * - The `links` property facilitates easy navigation between pages, enhancing user experience.
3649
+ */
3650
+ export interface ResourcePaginatedResult<DataType = unknown> {
3651
+ /** List of fetched resources. */
3652
+ data: DataType[];
3653
+ statusCode?: number;
3654
+ success?: boolean;
3655
+ error?: any;
3656
+ message?: string;
3657
+ status?: string;
3658
+ errors?: string | Error[];
3659
+ /** Pagination metadata. */
3660
+ meta?: ResourcePaginationMeta;
3661
+ /** Links for navigation in paginated results. */
3662
+ links?: {
3663
+ /** URL or index to the first page. */
3664
+ first?: string | number;
3665
+ /** URL or index to the previous page. */
3666
+ previous?: string | number;
3667
+ /** URL or index to the next page. */
3668
+ next?: string | number;
3669
+ /** URL or index to the last page. */
3670
+ last?: string | number;
3671
+ };
3672
+ }
3673
+ /**
3674
+ * @typedef ResourcePaginationMeta
3675
+ * Represents the pagination metadata for a resource.
3676
+ *
3677
+ * This type defines the structure of the pagination metadata returned by a resource query operation.
3678
+ * It includes information about the total number of items, the current page, the page size, and other
3679
+ * pagination-related properties.
3680
+ *
3681
+ * @property {number} total - The total number of items available.
3682
+ * @property {number} [currentPage] - The current page number.
3683
+ * @property {number} [pageSize] - The number of items per page.
3684
+ * @property {number} [totalPages] - The total number of pages.
3685
+ * @property {number} [nextPage] - The next page number.
3686
+ * @property {number} [previousPage] - The previous page number.
3687
+ * @property {number} [lastPage] - The last page number.
3688
+ * @property {boolean} [hasNextPage] - Whether there is a next page.
3689
+ * @property {boolean} [hasPreviousPage] - Whether there is a previous page.
3690
+ */
3691
+ export interface ResourcePaginationMeta {
3692
+ /** The total number of items available. */
3693
+ total: number;
3694
+ /** The current page number. */
3695
+ currentPage?: number;
3696
+ /** The number of items per page. */
3697
+ pageSize?: number;
3698
+ /** The total number of pages. */
3699
+ totalPages?: number;
3700
+ nextPage?: number;
3701
+ previousPage?: number;
3702
+ lastPage?: number;
3703
+ /***
3704
+ * Whether there is a next page.
3705
+ */
3706
+ hasNextPage?: boolean;
3707
+ /***
3708
+ * Whether there is a previous page.
3709
+ */
3710
+ hasPreviousPage?: boolean;
3711
+ }
3712
+ /**
3713
+ * Type representing default events that can occur on a resource.
3714
+ * This includes both action names and data service method names.
3715
+ *
3716
+ * This type combines resource-specific action names with standard data service
3717
+ * operations to provide a comprehensive set of events that can be tracked or
3718
+ * handled for a given resource. It's useful for event-driven architectures,
3719
+ * logging, auditing, and reactive systems.
3720
+ *
3721
+ * @type ResourceDefaultEvent
3722
+ * @template TResourceName - The name of the resource
3723
+ *
3724
+ * @example
3725
+ * ```typescript
3726
+ * // Basic usage - event type for a specific resource
3727
+ * import "reslib/resources";
3728
+ *
3729
+ * declare module "reslib/resources" {
3730
+ * interface Resources {
3731
+ * users: {
3732
+ * actions: {
3733
+ * read: { label: "Read User" };
3734
+ * create: { label: "Create User" };
3735
+ * update: { label: "Update User" };
3736
+ * archive: { label: "Archive User" };
3737
+ * }
3738
+ * };
3739
+ * }
3740
+ * }
3741
+ *
3742
+ * // All possible events for the users resource
3743
+ * type UserEvent = ResourceDefaultEvent<"users">;
3744
+ * // Result: "read" | "create" | "update" | "archive" | "create" | "update" | "delete" | "findOne" | "find" | ...
3745
+ *
3746
+ * // Note: Includes both resource actions and data service methods
3747
+ * ```
3748
+ *
3749
+ * @example
3750
+ * ```typescript
3751
+ * // Event-driven resource management
3752
+ * class ResourceEventEmitter<TResourceName extends ResourceName> {
3753
+ * private listeners = new Map<ResourceDefaultEvent<TResourceName>, Function[]>();
3754
+ *
3755
+ * on(event: ResourceDefaultEvent<TResourceName>, listener: Function) {
3756
+ * const current = this.listeners.get(event) || [];
3757
+ * current.push(listener);
3758
+ * this.listeners.set(event, current);
3759
+ * }
3760
+ *
3761
+ * emit(event: ResourceDefaultEvent<TResourceName>, data?: any) {
3762
+ * const listeners = this.listeners.get(event) || [];
3763
+ * listeners.forEach(listener => listener(data));
3764
+ * }
3765
+ * }
3766
+ *
3767
+ * // Usage
3768
+ * const userEmitter = new ResourceEventEmitter<"users">();
3769
+ *
3770
+ * userEmitter.on("create", (userData) => {
3771
+ * console.log("User created:", userData);
3772
+ * // Send welcome email, update analytics, etc.
3773
+ * });
3774
+ *
3775
+ * userEmitter.on("findOne", (userId) => {
3776
+ * console.log("User accessed:", userId);
3777
+ * // Log access, update last accessed time, etc.
3778
+ * });
3779
+ *
3780
+ * // Trigger events
3781
+ * userEmitter.emit("create", { id: 1, name: "John" });
3782
+ * userEmitter.emit("findOne", 1);
3783
+ * ```
3784
+ *
3785
+ * @example
3786
+ * ```typescript
3787
+ * // Audit logging with typed events
3788
+ * interface AuditLog<TResourceName extends ResourceName> {
3789
+ * resource: TResourceName;
3790
+ * event: ResourceDefaultEvent<TResourceName>;
3791
+ * userId: string;
3792
+ * timestamp: Date;
3793
+ * data?: any;
3794
+ * }
3795
+ *
3796
+ * class ResourceAuditor {
3797
+ * private logs: AuditLog<ResourceName>[] = [];
3798
+ *
3799
+ * log<TResourceName extends ResourceName>(
3800
+ * resource: TResourceName,
3801
+ * event: ResourceDefaultEvent<TResourceName>,
3802
+ * userId: string,
3803
+ * data?: any
3804
+ * ) {
3805
+ * this.logs.push({
3806
+ * resource,
3807
+ * event,
3808
+ * userId,
3809
+ * timestamp: new Date(),
3810
+ * data
3811
+ * });
3812
+ * }
3813
+ *
3814
+ * getLogsForResource<TResourceName extends ResourceName>(
3815
+ * resource: TResourceName
3816
+ * ): AuditLog<TResourceName>[] {
3817
+ * return this.logs.filter(log => log.resource === resource) as AuditLog<TResourceName>[];
3818
+ * }
3819
+ * }
3820
+ *
3821
+ * // Usage
3822
+ * const auditor = new ResourceAuditor();
3823
+ *
3824
+ * auditor.log("users", "create", "user123", { name: "John Doe" });
3825
+ * auditor.log("users", "update", "user456", { id: 1, name: "Jane Doe" });
3826
+ * auditor.log("users", "find", "user789"); // Data service method
3827
+ *
3828
+ * const userLogs = auditor.getLogsForResource("users");
3829
+ * // TypeScript knows these are user-related events
3830
+ * ```
3831
+ *
3832
+ * @example
3833
+ * ```typescript
3834
+ * // Reactive resource hooks
3835
+ * function useResourceEvent<TResourceName extends ResourceName>(
3836
+ * resource: TResourceName,
3837
+ * event: ResourceDefaultEvent<TResourceName>,
3838
+ * callback: (data?: any) => void
3839
+ * ) {
3840
+ * // Implementation would set up event listeners
3841
+ * console.log(`Setting up ${event} listener for ${resource}`);
3842
+ * // Return cleanup function, etc.
3843
+ * }
3844
+ *
3845
+ * // Usage in a React-like component
3846
+ * function UserComponent() {
3847
+ * // Type-safe event handling
3848
+ * useResourceEvent("users", "create", (userData) => {
3849
+ * console.log("New user created:", userData);
3850
+ * // Update UI, refresh data, etc.
3851
+ * });
3852
+ *
3853
+ * useResourceEvent("users", "update", (updateData) => {
3854
+ * console.log("User updated:", updateData);
3855
+ * // Refresh user data, show notification, etc.
3856
+ * });
3857
+ *
3858
+ * useResourceEvent("users", "findOne", (userId) => {
3859
+ * console.log("User profile viewed:", userId);
3860
+ * // Track analytics, etc.
3861
+ * });
3862
+ *
3863
+ * return <div>User Management Component</div>;
3864
+ * }
3865
+ * ```
3866
+ *
3867
+ * @example
3868
+ * ```typescript
3869
+ * // Middleware system with typed events
3870
+ * type MiddlewareFn<TResourceName extends ResourceName> = (
3871
+ * event: ResourceDefaultEvent<TResourceName>,
3872
+ * data: any,
3873
+ * next: () => void
3874
+ * ) => void;
3875
+ *
3876
+ * class ResourceMiddleware<TResourceName extends ResourceName> {
3877
+ * private middlewares: MiddlewareFn<TResourceName>[] = [];
3878
+ *
3879
+ * use(middleware: MiddlewareFn<TResourceName>) {
3880
+ * this.middlewares.push(middleware);
3881
+ * }
3882
+ *
3883
+ * async execute(event: ResourceDefaultEvent<TResourceName>, data: any) {
3884
+ * let index = 0;
3885
+ *
3886
+ * const next = () => {
3887
+ * if (index < this.middlewares.length) {
3888
+ * this.middlewares[index++](event, data, next);
3889
+ * }
3890
+ * };
3891
+ *
3892
+ * next();
3893
+ * }
3894
+ * }
3895
+ *
3896
+ * // Usage
3897
+ * const userMiddleware = new ResourceMiddleware<"users">();
3898
+ *
3899
+ * userMiddleware.use((event, data, next) => {
3900
+ * console.log(`Pre-${event} validation`);
3901
+ * // Validate permissions, data, etc.
3902
+ * next();
3903
+ * });
3904
+ *
3905
+ * userMiddleware.use((event, data, next) => {
3906
+ * console.log(`Post-${event} logging`);
3907
+ * // Log the event, send notifications, etc.
3908
+ * next();
3909
+ * });
3910
+ *
3911
+ * // Execute middleware for events
3912
+ * userMiddleware.execute("create", { name: "John" });
3913
+ * userMiddleware.execute("findOne", 123);
3914
+ * ```
3915
+ */
3916
+ export type ResourceDefaultEvent<TResourceName extends ResourceName> = ResourceActionName<TResourceName> | keyof ResourceDataService;
3917
+ /**
3918
+ * Represents contextual information about a resource for operations like translations, logging, and error handling.
3919
+ *
3920
+ * This interface provides a standardized way to pass resource identification and contextual data
3921
+ * throughout the application. It's primarily used for internationalization, error messages, and
3922
+ * logging where resource-specific information is needed.
3923
+ *
3924
+ * @interface ResourceContext
3925
+ *
3926
+ * @example
3927
+ * ```typescript
3928
+ * // Basic usage in translations
3929
+ * const context: ResourceContext = {
3930
+ * resourceName: "user",
3931
+ * resourceLabel: "User",
3932
+ * operation: "create",
3933
+ * count: 5
3934
+ * };
3935
+ *
3936
+ * // Used in error messages
3937
+ * i18n.t("resources.notFound", context);
3938
+ * // Results in: "User with ID 123 not found"
3939
+ * ```
3940
+ *
3941
+ * @example
3942
+ * ```typescript
3943
+ * // Extended with custom properties
3944
+ * const extendedContext: ResourceContext = {
3945
+ * resourceName: "product",
3946
+ * resourceLabel: "Product",
3947
+ * category: "electronics",
3948
+ * price: 99.99
3949
+ * };
3950
+ * ```
3951
+ */
3952
+ export interface ResourceContext extends Record<string, any> {
3953
+ /** The unique programmatic name of the resource */
3954
+ resourceName: ResourceName;
3955
+ /** The human-readable label of the resource for display purposes */
3956
+ resourceLabel: string;
3957
+ }
3958
+ /**
3959
+ * @interface ResourceTranslations
3960
+ *
3961
+ * Represents the translation structure for resources in the application.
3962
+ * This type defines the expected structure of translations for each resource,
3963
+ * including labels, titles, and action-specific translations.
3964
+ *
3965
+ * @example
3966
+ * ```typescript
3967
+ * // resources actions translations structure :
3968
+ * // Here is an example of the structure of the translations for the "user" resource:
3969
+ * const userTranslations: ResourceTranslations = {
3970
+ * user: {
3971
+ * label: "User",
3972
+ * title: "Manage user data",
3973
+ * create: {
3974
+ * label: "Create User",
3975
+ * title: "Click to add a new user.",
3976
+ * },
3977
+ * read: {
3978
+ * label: "View User",
3979
+ * title: "Click to view a specific user.",
3980
+ * },
3981
+ * update: {
3982
+ * label: "Update User",
3983
+ * title: "Click to update a specific user.",
3984
+ * zero: "No users to update.",
3985
+ * one: "Updated one user.",
3986
+ * other: "Updated %{count} users.",
3987
+ * },
3988
+ * delete: {
3989
+ * label: "Delete User",
3990
+ * title: "Click to delete a specific user.",
3991
+ * zero: "No users to delete.",
3992
+ * one: "Deleted one user.",
3993
+ * other: "Deleted %{count} users.",
3994
+ * },
3995
+ * }
3996
+ * };
3997
+ * ```
3998
+ */
3999
+ export type ResourceTranslations = {
4000
+ [Name in ResourceName]: ResourceTranslation<Name>;
4001
+ }[ResourceName];
4002
+ /**
4003
+ * @interface ResourceTranslation
4004
+ *
4005
+ * Represents the translation structure for a specific resource in the application.
4006
+ * This generic type defines the expected structure of translations for a given resource,
4007
+ * dynamically generating the translation keys based on the resource's defined actions.
4008
+ *
4009
+ * @template Name - The name of the resource for which translations are defined.
4010
+ * Must be a valid `ResourceName`.
4011
+ *
4012
+ * ### Structure:
4013
+ *
4014
+ * - **Core Properties**:
4015
+ * - `label`: The display name of the resource (required).
4016
+ * - `title`: The title or heading for the resource (optional).
4017
+ * - `description`: A detailed description of the resource (optional).
4018
+ * - `forbiddenError`: Error message when access to the resource is forbidden (required).
4019
+ * - `notFoundError`: Error message when the resource is not found (required).
4020
+ *
4021
+ * - **Action Translations**: Dynamically generated based on the resource's actions.
4022
+ * Each action defined in the resource's `actions` property will have:
4023
+ * - `label`: The display label for the action.
4024
+ * - `title`: The tooltip or help text for the action.
4025
+ * - `zero`: Message when no items are affected (for pluralization).
4026
+ * - `one`: Message when one item is affected (for pluralization).
4027
+ * - `other`: Message when multiple items are affected (for pluralization).
4028
+ *
4029
+ * - **Additional Properties**: Any additional translation keys can be added via `Record<string, any>`.
4030
+ *
4031
+ * ### Type Generation:
4032
+ *
4033
+ * The type uses conditional types and mapped types to dynamically generate the structure:
4034
+ * - It checks if the resource has an `actions` property.
4035
+ * - For each action, it creates a translation object with the required fields.
4036
+ * - It combines this with the core properties and allows for additional custom properties.
4037
+ *
4038
+ * @example
4039
+ * ```typescript
4040
+ * // For a resource with actions: { read: {...}, create: {...}, update: {...}, delete: {...} }
4041
+ * const userTranslations: ResourceTranslation<"user"> = {
4042
+ * label: "User",
4043
+ * title: "Manage user data",
4044
+ * description: "User management and administration",
4045
+ * forbiddenError: "You do not have permission to access this resource.",
4046
+ * notFoundError: "The requested user was not found.",
4047
+ *
4048
+ * // Action-specific translations (auto-generated based on resource actions)
4049
+ * read: {
4050
+ * label: "View User",
4051
+ * title: "Click to view a specific user.",
4052
+ * zero: "No users found.",
4053
+ * one: "Viewing one user.",
4054
+ * other: "Viewing %{count} users."
4055
+ * },
4056
+ * create: {
4057
+ * label: "Create User",
4058
+ * title: "Click to add a new user.",
4059
+ * zero: "No users created.",
4060
+ * one: "Created one user.",
4061
+ * other: "Created %{count} users."
4062
+ * },
4063
+ * update: {
4064
+ * label: "Update User",
4065
+ * title: "Click to update a specific user.",
4066
+ * zero: "No users updated.",
4067
+ * one: "Updated one user.",
4068
+ * other: "Updated %{count} users."
4069
+ * },
4070
+ * delete: {
4071
+ * label: "Delete User",
4072
+ * title: "Click to delete a specific user.",
4073
+ * zero: "No users deleted.",
4074
+ * one: "Deleted one user.",
4075
+ * other: "Deleted %{count} users."
4076
+ * },
4077
+ *
4078
+ * // Additional custom translations
4079
+ * customAction: "Custom action performed",
4080
+ * validationError: "Please check your input"
4081
+ * };
4082
+ * ```
4083
+ *
4084
+ * ### Notes:
4085
+ *
4086
+ * - The action translations are automatically inferred from the resource's action definitions.
4087
+ * - The `zero`, `one`, and `other` fields support pluralization in internationalization.
4088
+ * - The `%{count}` placeholder can be used in pluralization messages for dynamic counts.
4089
+ * - Additional properties allow for custom translations specific to the resource's needs.
4090
+ * - This type ensures type safety by tying translations directly to the resource structure.
4091
+ */
4092
+ export type ResourceTranslation<Name extends ResourceName> = {
4093
+ /**
4094
+ * The display name of the resource (required).
4095
+ */
4096
+ label: string;
4097
+ /**
4098
+ * The title or heading for the resource (optional).
4099
+ */
4100
+ title?: string;
4101
+ /**
4102
+ * A detailed description of the resource (optional).
4103
+ */
4104
+ description?: string;
4105
+ /**
4106
+ * Error message when access to the resource is forbidden (required).
4107
+ */
4108
+ forbiddenError: string;
4109
+ /**
4110
+ * Error message when the resource is not found (required).
4111
+ */
4112
+ notFoundError: string;
4113
+ } & (Resources[Name] extends {
4114
+ actions: infer Actions;
4115
+ } ? Actions extends Record<string, ResourceAction> ? {
4116
+ [Key in keyof Actions]: {
4117
+ /**
4118
+ * The display label for the action.
4119
+ */
4120
+ label?: string;
4121
+ /**
4122
+ * The tooltip or help text for the action.
4123
+ */
4124
+ title?: string;
4125
+ /**
4126
+ * Message when no items are affected (for pluralization).
4127
+ */
4128
+ zero?: string;
4129
+ /**
4130
+ * Message when one item is affected (for pluralization).
4131
+ */
4132
+ one?: string;
4133
+ /**
4134
+ * Message when multiple items are affected (for pluralization).
4135
+ */
4136
+ other?: string;
4137
+ };
4138
+ }[keyof Actions] : {} : {}) & Dictionary;