@nhtio/lucid-resourceful 0.1.0-master-0588a748

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 (68) hide show
  1. package/LICENSE.md +9 -0
  2. package/README.md +5 -0
  3. package/decorator_utils-1yWqd_Gg.cjs +6792 -0
  4. package/decorator_utils-1yWqd_Gg.cjs.map +1 -0
  5. package/decorator_utils-BUuBwQYK.js +6793 -0
  6. package/decorator_utils-BUuBwQYK.js.map +1 -0
  7. package/definitions-B66EPk0H.js +381 -0
  8. package/definitions-B66EPk0H.js.map +1 -0
  9. package/definitions-BrN-oCRI.cjs +380 -0
  10. package/definitions-BrN-oCRI.cjs.map +1 -0
  11. package/definitions.cjs +15 -0
  12. package/definitions.cjs.map +1 -0
  13. package/definitions.d.ts +5 -0
  14. package/definitions.mjs +15 -0
  15. package/definitions.mjs.map +1 -0
  16. package/errors-B1rr67uM.js +3004 -0
  17. package/errors-B1rr67uM.js.map +1 -0
  18. package/errors-D8jb9VxY.cjs +3000 -0
  19. package/errors-D8jb9VxY.cjs.map +1 -0
  20. package/errors.cjs +22 -0
  21. package/errors.cjs.map +1 -0
  22. package/errors.d.ts +94 -0
  23. package/errors.mjs +22 -0
  24. package/errors.mjs.map +1 -0
  25. package/index-Cv6KC1rC.cjs +670 -0
  26. package/index-Cv6KC1rC.cjs.map +1 -0
  27. package/index-DDaZ2qr2.js +671 -0
  28. package/index-DDaZ2qr2.js.map +1 -0
  29. package/index.cjs +12706 -0
  30. package/index.cjs.map +1 -0
  31. package/index.d.ts +14 -0
  32. package/index.mjs +12708 -0
  33. package/index.mjs.map +1 -0
  34. package/joi.cjs +5 -0
  35. package/joi.cjs.map +1 -0
  36. package/joi.d.ts +5 -0
  37. package/joi.mjs +5 -0
  38. package/joi.mjs.map +1 -0
  39. package/package.json +65 -0
  40. package/private/constants.d.ts +11 -0
  41. package/private/controller_factory.d.ts +1 -0
  42. package/private/data_type_schemas.d.ts +12 -0
  43. package/private/data_types.d.ts +437 -0
  44. package/private/decorator_schemas.d.ts +34 -0
  45. package/private/decorator_utils.d.ts +305 -0
  46. package/private/decorators.d.ts +209 -0
  47. package/private/helpers.d.ts +34 -0
  48. package/private/joi/bigint.d.ts +85 -0
  49. package/private/joi/index.d.ts +65 -0
  50. package/private/lucene_to_lucid_translator.d.ts +201 -0
  51. package/private/mixin.d.ts +563 -0
  52. package/private/schema_types.d.ts +157 -0
  53. package/private/type_guards.d.ts +42 -0
  54. package/private/types.d.ts +102 -0
  55. package/private/utils.d.ts +10 -0
  56. package/types.cjs +2 -0
  57. package/types.cjs.map +1 -0
  58. package/types.d.ts +28 -0
  59. package/types.mjs +2 -0
  60. package/types.mjs.map +1 -0
  61. package/utils/casters.d.ts +1 -0
  62. package/utils/consumers.d.ts +1 -0
  63. package/utils/preparers.d.ts +1 -0
  64. package/utils.cjs +50 -0
  65. package/utils.cjs.map +1 -0
  66. package/utils.d.ts +20 -0
  67. package/utils.mjs +51 -0
  68. package/utils.mjs.map +1 -0
@@ -0,0 +1,563 @@
1
+ import type { BaseModel } from '@adonisjs/lucid/orm';
2
+ import type { HttpContext } from '@adonisjs/core/http';
3
+ import type { ApplicationService } from '@adonisjs/core/types';
4
+ import type { AnySchema, ObjectSchema } from 'joi';
5
+ import type { EventMap, Key, Listener } from '@nhtio/tiny-typed-emitter';
6
+ import type { NormalizeConstructor } from '@adonisjs/core/types/helpers';
7
+ import type { DatabaseQueryBuilderContract } from '@adonisjs/lucid/types/querybuilder';
8
+ import type { LucidModel } from '@adonisjs/lucid/types/model';
9
+ import type { ExternalDocumentationObject, PromiseAble, ResourcefulColumnDefinition, ResourcefulComputedAccessorDefinition, ResourcefulDataType, ResourcefulGeneralAccessControlFilter, ResourcefulModelOpenApiSchema, ResourcefulPropertySchema, ResourcefulRelationshipDefinition, ResourcefulResourceAccessControlFilter, ResourcefulModelSerializableAttributes } from '@nhtio/lucid-resourceful/types';
10
+ /**
11
+ * Result object returned by the resourceful index/list operation.
12
+ *
13
+ * Contains paginated records along with metadata about the query execution
14
+ * and pagination state. The records are filtered according to field-level
15
+ * access control and only contain the requested fields.
16
+ *
17
+ * @template ReturnType - The shape of records after field selection and ACL filtering
18
+ */
19
+ export interface ResourcefulIndexResult<ReturnType = any> {
20
+ /** Array of records with only the requested and accessible fields */
21
+ records: Array<Partial<ReturnType>>;
22
+ /** Total number of records matching the filter (before pagination) */
23
+ total: number;
24
+ /** The current page number (1-based) */
25
+ page: number;
26
+ /** Number of records per page */
27
+ perPage: number;
28
+ /** SQL query string used for counting total records */
29
+ countQuery: string;
30
+ /** SQL query string used for fetching the paginated records */
31
+ recordsQuery: string;
32
+ }
33
+ /**
34
+ * Function type for generating payload validation schemas based on request context.
35
+ *
36
+ * These functions are called during create and update operations to generate
37
+ * context-specific validation schemas using Joi. They provide the core model-level
38
+ * validation that applies regardless of request-specific hooks.
39
+ *
40
+ * @param ctx - HTTP context containing request information and authentication
41
+ * @param app - Application service instance for accessing app-level services
42
+ * @returns Promise resolving to a Joi schema for validating the request payload
43
+ */
44
+ export interface ResourcefulPayloadValidatorGetter {
45
+ (ctx: HttpContext, app: ApplicationService): PromiseAble<AnySchema>;
46
+ }
47
+ /**
48
+ * Function type for generating request-specific payload validation schemas.
49
+ *
50
+ * These functions are provided via hooks during create and update operations
51
+ * to add additional validation constraints beyond the base model validation.
52
+ * They enable request-specific validation logic based on context.
53
+ *
54
+ * @param ctx - HTTP context containing request information and authentication
55
+ * @param app - Application service instance for accessing app-level services
56
+ * @returns Promise resolving to a Joi ObjectSchema for additional validation, or null to skip
57
+ */
58
+ export interface ResourcefulPayloadSchemaGetter {
59
+ (ctx: HttpContext, app: ApplicationService): PromiseAble<ObjectSchema | null>;
60
+ }
61
+ /**
62
+ * Function type for applying query-level scoping to database queries.
63
+ *
64
+ * These callbacks are applied to queries during CRUD operations to enforce
65
+ * data access boundaries based on request context. They modify the query
66
+ * in-place by adding WHERE clauses, JOINs, or other constraints.
67
+ *
68
+ * @param ctx - HTTP context containing request information and authentication
69
+ * @param app - Application service instance for accessing app-level services
70
+ * @param query - Database query builder to modify with scoping constraints
71
+ * @returns Promise that resolves when the query has been modified
72
+ */
73
+ export interface ResourcefulQueryScopeCallback {
74
+ (ctx: HttpContext, app: ApplicationService, query: DatabaseQueryBuilderContract): PromiseAble<void>;
75
+ }
76
+ /**
77
+ * Array of query scope callback functions.
78
+ *
79
+ * Used for operations that need to apply query-level scoping (index, read, delete).
80
+ * Callbacks are applied in sequence to build up the complete set of access constraints.
81
+ */
82
+ export type ResourcefulScopeHooks = ResourcefulQueryScopeCallback[];
83
+ /**
84
+ * Array of payload validation schema getter functions.
85
+ *
86
+ * Used for operations that accept request payloads (create, update).
87
+ * Each function can return additional validation constraints based on request context.
88
+ */
89
+ export type ResourcefulValidationHooks = ResourcefulPayloadSchemaGetter[];
90
+ /**
91
+ * Combined hook interface providing both query scoping and payload validation.
92
+ *
93
+ * Used by the update operation which needs both query scoping (to find the record)
94
+ * and payload validation (to validate the update data).
95
+ */
96
+ export interface ResourcefulHooks {
97
+ /** Query scope callbacks for constraining database queries */
98
+ queryScopeCallbacks: ResourcefulScopeHooks;
99
+ /** Payload validation schema getters for additional validation */
100
+ payloadValidationSchemas: ResourcefulValidationHooks;
101
+ }
102
+ export type ResourcefulMixinEventMap<Model extends LucidModel = LucidModel, ModelInstance = InstanceType<Model>> = EventMap<{
103
+ 'acl:error': [unknown, HttpContext, ApplicationService, ModelInstance | undefined];
104
+ 'validation:scope:error': [unknown, HttpContext, ApplicationService, string, ResourcefulDataType];
105
+ }>;
106
+ /**
107
+ * Enhanced Lucid model interface providing resourceful CRUD functionality.
108
+ *
109
+ * This interface extends the base LucidModel with metadata-driven CRUD operations,
110
+ * field-level access control, query scoping, OpenAPI schema generation, and event
111
+ * handling capabilities. Models implementing this interface gain static methods
112
+ * for handling HTTP requests with built-in validation, pagination, filtering,
113
+ * and comprehensive security features.
114
+ *
115
+ * The interface defines both metadata storage properties and operational methods
116
+ * that work together to provide a complete resourceful API layer on top of
117
+ * AdonisJS Lucid ORM models.
118
+ *
119
+ * @extends LucidModel
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * import { BaseModel, column } from '@ioc:Adonis/Lucid/Orm'
124
+ * import { withResourceful, resourceful } from 'lucid-resourceful'
125
+ *
126
+ * class User extends withResourceful()(BaseModel) implements ResourcefulModel {
127
+ * @column({ isPrimary: true })
128
+ * @resourceful({ type: 'number', nullable: false })
129
+ * public id: number
130
+ *
131
+ * @column()
132
+ * @resourceful({ type: 'string', nullable: false })
133
+ * public name: string
134
+ *
135
+ * // Automatically gains all ResourcefulModel methods
136
+ * // User.$onResourcefulIndex, User.$onResourcefulRead, etc.
137
+ * }
138
+ * ```
139
+ */
140
+ export interface ResourcefulModel extends LucidModel {
141
+ /** The display name for this model used in API documentation and error messages */
142
+ $resourcefulName: string;
143
+ /** Optional description for OpenAPI schema documentation */
144
+ $resourcefulMetaDescription?: string;
145
+ /** Optional external documentation reference for OpenAPI schema */
146
+ $resourcefulMetaExternalDocs?: ExternalDocumentationObject;
147
+ /** Optional example value for OpenAPI schema documentation */
148
+ $resourcefulMetaExample?: string;
149
+ /** Map of column property names to their resourceful metadata definitions */
150
+ $resourcefulColumns: Map<string, ResourcefulColumnDefinition<ResourcefulPropertySchema>>;
151
+ /** Map of relationship property names to their resourceful metadata definitions */
152
+ $resourcefulRelationships: Map<string, ResourcefulRelationshipDefinition>;
153
+ /** Map of computed accessor property names to their resourceful metadata definitions */
154
+ $resourcefulComputedAccessors: Map<string, ResourcefulComputedAccessorDefinition<ResourcefulPropertySchema>>;
155
+ /** Access control filter functions organized by CRUD operation type */
156
+ $resourcefulAccessControlFilters: ResourcefulMixinOptions['accessControlFilters'];
157
+ /** Error handling strategy when ACL evaluation fails */
158
+ $resourcefulOnACLError: ResourcefulMixinOptions['onACLError'];
159
+ /** Query scope callback functions for constraining database queries */
160
+ $resourcefulQueryScopeCallbacks: ResourcefulMixinOptions['queryScopeCallbacks'];
161
+ /** Payload validation schema builder functions for create and update operations */
162
+ $resourcefulPayloadValidationSchemaBuilders: ResourcefulMixinOptions['payloadValidationSchemaBuilders'];
163
+ /**
164
+ * Registers an event listener for resourceful model events.
165
+ *
166
+ * This method provides a way to listen for events emitted during resourceful
167
+ * operations such as ACL errors or validation scope errors. Useful for logging,
168
+ * monitoring, or implementing custom error handling logic.
169
+ *
170
+ * @template K - The event key type from the resourceful event map
171
+ * @param event - The name of the event to listen for ('acl:error', 'validation:scope:error')
172
+ * @param listener - Function to call when the event is emitted
173
+ * @returns The model class for method chaining
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * User.$onResourcefulEvent('acl:error', (error, ctx, app, instance) => {
178
+ * console.error('ACL error occurred:', error);
179
+ * });
180
+ * ```
181
+ */
182
+ $onResourcefulEvent<K>(event: Key<K, ResourcefulMixinEventMap<ResourcefulModel>>, listener: Listener<K, ResourcefulMixinEventMap<ResourcefulModel>>): this;
183
+ /**
184
+ * Registers a one-time event listener for resourceful model events.
185
+ *
186
+ * Similar to $onResourcefulEvent but the listener is automatically removed
187
+ * after being called once. Useful for handling events that should only
188
+ * trigger a single response.
189
+ *
190
+ * @template K - The event key type from the resourceful event map
191
+ * @param event - The name of the event to listen for
192
+ * @param listener - Function to call when the event is emitted
193
+ * @returns The model class for method chaining
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * User.$onceResourcefulEvent('validation:scope:error', (error, ctx, app, key, datatype) => {
198
+ * console.warn('Validation scope error (one-time):', error);
199
+ * });
200
+ * ```
201
+ */
202
+ $onceResourcefulEvent<K>(event: Key<K, ResourcefulMixinEventMap<ResourcefulModel>>, listener: Listener<K, ResourcefulMixinEventMap<ResourcefulModel>>): this;
203
+ /**
204
+ * Removes an event listener for resourceful model events.
205
+ *
206
+ * Unregisters a previously registered event listener. If no listener is
207
+ * provided, all listeners for the specified event are removed.
208
+ *
209
+ * @template K - The event key type from the resourceful event map
210
+ * @param event - The name of the event to stop listening for
211
+ * @param listener - Optional specific listener function to remove
212
+ * @returns The model class for method chaining
213
+ *
214
+ * @example
215
+ * ```typescript
216
+ * // Remove specific listener
217
+ * User.$offResourcefulEvent('acl:error', myErrorHandler);
218
+ *
219
+ * // Remove all listeners for an event
220
+ * User.$offResourcefulEvent('acl:error');
221
+ * ```
222
+ */
223
+ $offResourcefulEvent<K>(event: Key<K, ResourcefulMixinEventMap<ResourcefulModel>>, listener?: Listener<K, ResourcefulMixinEventMap<ResourcefulModel>>): this;
224
+ /**
225
+ * Performs paginated listing and searching of model records with comprehensive filtering.
226
+ *
227
+ * This method provides the core implementation for resourceful index/list operations,
228
+ * supporting pagination, field selection, access control, and Lucene query syntax for
229
+ * filtering. It validates all inputs, applies ACL filters, executes the query with
230
+ * proper field mapping between serialized names and database columns, and returns
231
+ * structured results with query metadata.
232
+ *
233
+ * @template SelectedFields - Array of field names that can be selected from the model's serializable attributes
234
+ * @template ReturnType - The resulting type after picking the selected fields from the model's serializable attributes
235
+ *
236
+ * @param filter - Lucene-style query string for filtering records (e.g., "name:john AND email:*.com").
237
+ * If null or undefined, defaults to empty string (no filtering).
238
+ * @param page - The page number for pagination (must be ≥ 1). Used with perPage to calculate offset.
239
+ * @param perPage - Number of records per page (must be ≥ 1 and ≤ 100 by default).
240
+ * @param fields - Array of field names to include in the response. If null, undefined, or empty,
241
+ * defaults to just the primary key field. Field names should use serialized names
242
+ * (as they appear in API responses), not database column names.
243
+ * @param ctx - HTTP context containing request information, authentication, and other request-scoped data.
244
+ * @param app - Application service instance providing access to application-level services and configuration.
245
+ * @param hooks - Optional array of query scope callbacks to apply additional filtering constraints.
246
+ *
247
+ * @returns Promise resolving to ResourcefulIndexResult containing:
248
+ * - `records`: Array of partial record objects with only the requested fields
249
+ * - `total`: Total number of records matching the filter (before pagination)
250
+ * - `page`: The requested page number (echoed back)
251
+ * - `perPage`: The requested per-page limit (echoed back)
252
+ * - `countQuery`: SQL query string used for counting total records
253
+ * - `recordsQuery`: SQL query string used for fetching the actual records
254
+ *
255
+ * @throws {E_MISSING_PRIMARY_KEY_EXCEPTION} When the model has no identifiable primary key
256
+ * @throws {E_FORBIDDEN} When access is denied by model-level or field-level ACL filters
257
+ * @throws {E_INVALID_COLUMN_ACCESS} When no fields are available for access after ACL filtering
258
+ * @throws {E_INVALID_RESOUREFUL_INDEX_REQUEST_EXCEPTION} When input validation fails
259
+ *
260
+ * @example
261
+ * ```typescript
262
+ * // Basic usage with pagination
263
+ * const result = await User.$onResourcefulIndex(
264
+ * 'name:john',
265
+ * 1,
266
+ * 10,
267
+ * ['id', 'name', 'email'],
268
+ * ctx,
269
+ * app
270
+ * );
271
+ *
272
+ * // Complex filtering with date ranges
273
+ * const result = await User.$onResourcefulIndex(
274
+ * 'name:john AND createdAt:[2021-01-01T00:00:00Z TO 2021-12-31T23:59:59Z]',
275
+ * 2,
276
+ * 25,
277
+ * ['id', 'name', 'createdAt'],
278
+ * ctx,
279
+ * app
280
+ * );
281
+ * ```
282
+ */
283
+ $onResourcefulIndex<SelectedFields extends Array<keyof ResourcefulModelSerializableAttributes<InstanceType<LucidModel>>>, ReturnType = Pick<ResourcefulModelSerializableAttributes<InstanceType<LucidModel>>, SelectedFields[number]>>(filter: string | null | undefined, page: number, perPage: number, fields: SelectedFields | null | undefined, ctx: HttpContext, app: ApplicationService, hooks?: ResourcefulScopeHooks): Promise<ResourcefulIndexResult<ReturnType>>;
284
+ /**
285
+ * Retrieves a single model record by its unique identifier with access control.
286
+ *
287
+ * This method implements secure record retrieval by first applying query scope callbacks
288
+ * to verify the record exists within the user's access scope, then fetching the full
289
+ * model instance for field-level ACL evaluation. Only fields that pass ACL checks
290
+ * are included in the response.
291
+ *
292
+ * @param uid - The unique identifier of the record to retrieve
293
+ * @param ctx - HTTP context containing request information and authentication
294
+ * @param app - Application service instance for accessing app-level services
295
+ * @param hooks - Optional array of query scope callbacks to apply additional filtering constraints
296
+ *
297
+ * @returns Promise resolving to the record object with only accessible fields
298
+ *
299
+ * @throws {E_MISSING_PRIMARY_KEY_EXCEPTION} When the model has no identifiable primary key
300
+ * @throws {E_RECORD_NOT_FOUND_EXCEPTION} When no record exists with the given ID or user lacks access
301
+ * @throws {E_FORBIDDEN} When access is denied by model-level or field-level ACL filters
302
+ *
303
+ * @example
304
+ * ```typescript
305
+ * // Retrieve a user by ID
306
+ * const user = await User.$onResourcefulRead(123, ctx, app);
307
+ *
308
+ * // With additional query scoping
309
+ * const user = await User.$onResourcefulRead(123, ctx, app, [
310
+ * (ctx, app, query) => query.where('tenant_id', ctx.auth.user.tenantId)
311
+ * ]);
312
+ * ```
313
+ */
314
+ $onResourcefulRead(uid: number, ctx: HttpContext, app: ApplicationService, hooks?: ResourcefulScopeHooks): Promise<any>;
315
+ /**
316
+ * Creates a new model record with payload validation and access control.
317
+ *
318
+ * This method handles secure record creation by validating the request payload
319
+ * against both model-level and request-specific validation schemas, checking
320
+ * field-level write permissions, and returning the created record with appropriate
321
+ * field filtering applied.
322
+ *
323
+ * @param payload - The data object containing field values for the new record
324
+ * @param ctx - HTTP context containing request information and authentication
325
+ * @param app - Application service instance for accessing app-level services
326
+ * @param hooks - Optional array of validation schema getters for additional payload validation
327
+ *
328
+ * @returns Promise resolving to the created record with only accessible fields
329
+ *
330
+ * @throws {E_MISSING_PRIMARY_KEY_EXCEPTION} When the model has no identifiable primary key
331
+ * @throws {E_INVALID_PAYLOAD_EXCEPTION} When core model validation fails
332
+ * @throws {E_FORBIDDEN_PAYLOAD_EXCEPTION} When request-specific validation fails
333
+ * @throws {E_FORBIDDEN} When access is denied by model-level or field-level ACL filters
334
+ *
335
+ * @example
336
+ * ```typescript
337
+ * // Create a new user
338
+ * const user = await User.$onResourcefulCreate({
339
+ * name: 'John Doe',
340
+ * email: 'john@example.com'
341
+ * }, ctx, app);
342
+ *
343
+ * // With additional validation
344
+ * const user = await User.$onResourcefulCreate(payload, ctx, app, [
345
+ * (ctx, app) => joi.object({ email: joi.string().domain('company.com') })
346
+ * ]);
347
+ * ```
348
+ */
349
+ $onResourcefulCreate(payload: any, ctx: HttpContext, app: ApplicationService, hooks?: ResourcefulValidationHooks): Promise<any>;
350
+ /**
351
+ * Updates an existing model record with payload validation and access control.
352
+ *
353
+ * This method implements secure record updates by first verifying the record exists
354
+ * and is accessible via the read operation, validating the update payload, checking
355
+ * field-level write permissions, and returning the updated record with appropriate
356
+ * field filtering applied.
357
+ *
358
+ * @param uid - The unique identifier of the record to update
359
+ * @param payload - The data object containing field values to update
360
+ * @param ctx - HTTP context containing request information and authentication
361
+ * @param app - Application service instance for accessing app-level services
362
+ * @param hooks - Optional object containing query scope callbacks and validation schema getters
363
+ *
364
+ * @returns Promise resolving to the updated record with only accessible fields
365
+ *
366
+ * @throws {E_MISSING_PRIMARY_KEY_EXCEPTION} When the model has no identifiable primary key
367
+ * @throws {E_RECORD_NOT_FOUND_EXCEPTION} When no record exists with the given ID or user lacks access
368
+ * @throws {E_INVALID_PAYLOAD_EXCEPTION} When core model validation fails
369
+ * @throws {E_FORBIDDEN_PAYLOAD_EXCEPTION} When request-specific validation fails
370
+ * @throws {E_FORBIDDEN} When access is denied by model-level or field-level ACL filters
371
+ *
372
+ * @example
373
+ * ```typescript
374
+ * // Update a user
375
+ * const user = await User.$onResourcefulUpdate(123, {
376
+ * name: 'Jane Doe'
377
+ * }, ctx, app);
378
+ *
379
+ * // With additional scoping and validation
380
+ * const user = await User.$onResourcefulUpdate(123, payload, ctx, app, {
381
+ * queryScopeCallbacks: [(ctx, app, query) => query.where('active', true)],
382
+ * payloadValidationSchemas: [(ctx, app) => customValidationSchema]
383
+ * });
384
+ * ```
385
+ */
386
+ $onResourcefulUpdate(uid: number, payload: any, ctx: HttpContext, app: ApplicationService, hooks?: Partial<ResourcefulHooks>): Promise<any>;
387
+ /**
388
+ * Deletes an existing model record with access control.
389
+ *
390
+ * This method implements secure record deletion by applying query scope callbacks
391
+ * to verify the record exists within the user's access scope, checking delete
392
+ * permissions via ACL filters, and then removing the record from the database.
393
+ *
394
+ * @param uid - The unique identifier of the record to delete
395
+ * @param ctx - HTTP context containing request information and authentication
396
+ * @param app - Application service instance for accessing app-level services
397
+ * @param hooks - Optional array of query scope callbacks to apply additional filtering constraints
398
+ *
399
+ * @returns Promise that resolves when the record has been successfully deleted
400
+ *
401
+ * @throws {E_MISSING_PRIMARY_KEY_EXCEPTION} When the model has no identifiable primary key
402
+ * @throws {E_RECORD_NOT_FOUND_EXCEPTION} When no record exists with the given ID or user lacks access
403
+ * @throws {E_FORBIDDEN} When access is denied by model-level ACL filters
404
+ *
405
+ * @example
406
+ * ```typescript
407
+ * // Delete a user
408
+ * await User.$onResourcefulDelete(123, ctx, app);
409
+ *
410
+ * // With additional query scoping
411
+ * await User.$onResourcefulDelete(123, ctx, app, [
412
+ * (ctx, app, query) => query.where('tenant_id', ctx.auth.user.tenantId)
413
+ * ]);
414
+ * ```
415
+ */
416
+ $onResourcefulDelete(uid: number, ctx: HttpContext, app: ApplicationService, hooks?: ResourcefulScopeHooks): Promise<void>;
417
+ /**
418
+ * Generates an OpenAPI schema object for this model with context-aware field filtering.
419
+ *
420
+ * This method creates a complete OpenAPI v3 schema representation of the model
421
+ * by evaluating field-level access control permissions for the given request context.
422
+ * Only fields that pass ACL checks are included in the generated schema, ensuring
423
+ * that API documentation accurately reflects what data is accessible to the current user.
424
+ *
425
+ * The method processes all resourceful properties (columns, computed accessors, and
426
+ * relationships) and converts them to their OpenAPI schema equivalents while respecting
427
+ * access control constraints and applying proper type mappings.
428
+ *
429
+ * @param ctx - HTTP context containing request information and authentication
430
+ * @param app - Application service instance for accessing app-level services
431
+ *
432
+ * @returns Promise resolving to a complete OpenAPI schema object with:
433
+ * - `type`: Always 'object' for model schemas
434
+ * - `title`: The model's resourceful name
435
+ * - `description`: Optional model description from metadata
436
+ * - `properties`: Object containing schema definitions for accessible fields
437
+ * - `required`: Array of required field names (non-nullable fields)
438
+ * - `externalDocs`: Optional external documentation reference
439
+ * - `example`: Optional example value for the schema
440
+ *
441
+ * @example
442
+ * ```typescript
443
+ * // Generate OpenAPI schema for current user context
444
+ * const schema = await User.$asOpenApiSchemaObject(ctx, app);
445
+ *
446
+ * // Result structure:
447
+ * {
448
+ * type: 'object',
449
+ * title: 'User',
450
+ * properties: {
451
+ * id: { type: 'number', readOnly: true },
452
+ * name: { type: 'string' },
453
+ * email: { type: 'string', format: 'email' }
454
+ * },
455
+ * required: ['id', 'name', 'email']
456
+ * }
457
+ * ```
458
+ *
459
+ * @see {@link ResourcefulModelOpenApiSchema} for the complete schema structure
460
+ */
461
+ $asOpenApiSchemaObject(ctx: HttpContext, app: ApplicationService): Promise<ResourcefulModelOpenApiSchema>;
462
+ }
463
+ export declare const ResourcefulErrorHandlerMethod: readonly ["bubble", "pass", "fail"];
464
+ export type ResourcefulErrorHandlerMethod = (typeof ResourcefulErrorHandlerMethod)[number];
465
+ export declare const ResourcefulACLOperationType: readonly ["read", "write"];
466
+ export type ResourcefulACLOperationType = (typeof ResourcefulACLOperationType)[number];
467
+ export interface AdvancedResourcefulMixinOptions {
468
+ propertyEvaluationConcurrency: number;
469
+ aclEvaluationConcurrency: number;
470
+ }
471
+ export interface ResourcefulMixinOptions<Model extends LucidModel = LucidModel, ModelInstance = InstanceType<Model>> {
472
+ name: string;
473
+ readRequiredForWrite: boolean;
474
+ accessControlFilters: {
475
+ list: ResourcefulGeneralAccessControlFilter[];
476
+ create: ResourcefulGeneralAccessControlFilter[];
477
+ read: ResourcefulResourceAccessControlFilter<Model, ModelInstance>[];
478
+ update: ResourcefulResourceAccessControlFilter<Model, ModelInstance>[];
479
+ delete: ResourcefulResourceAccessControlFilter<Model, ModelInstance>[];
480
+ };
481
+ payloadValidationSchemaBuilders: {
482
+ create: ResourcefulPayloadValidatorGetter[];
483
+ update: ResourcefulPayloadValidatorGetter[];
484
+ };
485
+ onACLError: ResourcefulErrorHandlerMethod;
486
+ onValidationScopeError: ResourcefulErrorHandlerMethod;
487
+ queryScopeCallbacks: {
488
+ list: ResourcefulQueryScopeCallback[];
489
+ access: ResourcefulQueryScopeCallback[];
490
+ };
491
+ description?: string;
492
+ externalDocs?: ExternalDocumentationObject;
493
+ example?: string;
494
+ advanced: AdvancedResourcefulMixinOptions;
495
+ }
496
+ /**
497
+ * Creates a mixin that adds resourceful CRUD functionality to Lucid models.
498
+ *
499
+ * This function implements the mixin pattern to enhance AdonisJS Lucid models with
500
+ * metadata-driven CRUD operations, field-level access control, query scoping,
501
+ * and OpenAPI schema generation capabilities. The resulting model gains static
502
+ * methods for handling HTTP requests with built-in validation, pagination,
503
+ * filtering, and security features.
504
+ *
505
+ * The mixin validates and normalizes configuration options, creates isolated
506
+ * metadata maps for each model class to prevent inheritance conflicts, and
507
+ * establishes an event emitter for monitoring ACL and validation operations.
508
+ *
509
+ * @param options - Configuration object for customizing mixin behavior
510
+ * @param options.name - Display name for the model (defaults to class name)
511
+ * @param options.readRequiredForWrite - Whether read access is required before write operations
512
+ * @param options.accessControlFilters - Object containing arrays of ACL filter functions for different operations
513
+ * @param options.accessControlFilters.list - Filters applied during listing/search operations
514
+ * @param options.accessControlFilters.create - Filters applied during record creation
515
+ * @param options.accessControlFilters.read - Filters applied during record reading
516
+ * @param options.accessControlFilters.update - Filters applied during record updates
517
+ * @param options.accessControlFilters.delete - Filters applied during record deletion
518
+ * @param options.onACLError - Error handling strategy when ACL evaluation fails ('throw', 'pass', 'fail')
519
+ * @param options.onValidationScopeError - Error handling strategy when validation scope functions fail
520
+ * @param options.queryScopeCallbacks - Object containing query scope callback functions
521
+ * @param options.queryScopeCallbacks.list - Callbacks applied to listing/search queries
522
+ * @param options.queryScopeCallbacks.access - Callbacks applied to individual record access queries
523
+ * @param options.description - Optional description for OpenAPI documentation
524
+ * @param options.externalDocs - Optional external documentation reference for OpenAPI
525
+ * @param options.example - Optional example value for OpenAPI documentation
526
+ * @param options.advanced - Advanced configuration options for performance tuning
527
+ * @param options.advanced.propertyEvaluationConcurrency - Concurrency limit for property ACL evaluation
528
+ * @param options.advanced.aclEvaluationConcurrency - Concurrency limit for ACL filter evaluation
529
+ *
530
+ * @returns A mixin function that accepts a Lucid model class and returns the enhanced model
531
+ *
532
+ * @throws {E_INVALID_RESOURCEFUL_MIXIN_OPTIONS} When the provided options fail validation
533
+ *
534
+ * @example
535
+ * ```typescript
536
+ * import { BaseModel, column } from '@ioc:Adonis/Lucid/Orm'
537
+ * import { withResourceful, resourceful } from 'lucid-resourceful'
538
+ *
539
+ * class User extends withResourceful({
540
+ * name: 'User',
541
+ * readRequiredForWrite: true,
542
+ * accessControlFilters: {
543
+ * read: [(ctx) => ctx.auth.user?.id === ctx.params.id],
544
+ * update: [(ctx) => ctx.auth.user?.isAdmin]
545
+ * }
546
+ * })(BaseModel) {
547
+ * @column({ isPrimary: true })
548
+ * @resourceful({ type: 'number', nullable: false })
549
+ * public id: number
550
+ *
551
+ * @column()
552
+ * @resourceful({ type: 'string', nullable: false })
553
+ * public name: string
554
+ * }
555
+ *
556
+ * // Generated controller with CRUD operations
557
+ * const UserController = User.generateController()
558
+ * ```
559
+ *
560
+ * @see {@link ResourcefulMixinOptions} for detailed configuration options
561
+ * @see {@link ResourcefulModel} for the enhanced model interface
562
+ */
563
+ export declare function withResourceful(options?: Partial<ResourcefulMixinOptions>): <Model extends NormalizeConstructor<typeof BaseModel>>(superclass: Model) => Model & ResourcefulModel;