@classytic/arc 1.0.0 → 1.0.5

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.
@@ -1,5 +1,5 @@
1
1
  import { FastifyInstance } from 'fastify';
2
- import { C as CreateAppOptions } from './types-0IPhH_NR.js';
2
+ import { C as CreateAppOptions } from './types-EBZBXrg-.js';
3
3
 
4
4
  /**
5
5
  * ArcFactory - Production-ready Fastify application factory
@@ -538,11 +538,16 @@ function generateSchemas(resources) {
538
538
  };
539
539
  for (const resource of resources) {
540
540
  const storedSchemas = resource.openApiSchemas;
541
- if (storedSchemas?.createBody) {
541
+ if (storedSchemas?.response) {
542
+ schemas[resource.name] = {
543
+ type: "object",
544
+ description: resource.displayName,
545
+ ...storedSchemas.response
546
+ };
547
+ } else if (storedSchemas?.createBody) {
542
548
  schemas[resource.name] = {
543
549
  type: "object",
544
550
  description: resource.displayName,
545
- ...storedSchemas.createBody,
546
551
  properties: {
547
552
  _id: { type: "string", description: "Unique identifier" },
548
553
  ...storedSchemas.createBody.properties ?? {},
@@ -550,6 +555,18 @@ function generateSchemas(resources) {
550
555
  updatedAt: { type: "string", format: "date-time", description: "Last update timestamp" }
551
556
  }
552
557
  };
558
+ } else {
559
+ schemas[resource.name] = {
560
+ type: "object",
561
+ description: resource.displayName,
562
+ properties: {
563
+ _id: { type: "string", description: "Unique identifier" },
564
+ createdAt: { type: "string", format: "date-time", description: "Creation timestamp" },
565
+ updatedAt: { type: "string", format: "date-time", description: "Last update timestamp" }
566
+ }
567
+ };
568
+ }
569
+ if (storedSchemas?.createBody) {
553
570
  schemas[`${resource.name}Input`] = {
554
571
  type: "object",
555
572
  description: `${resource.displayName} create input`,
@@ -563,15 +580,6 @@ function generateSchemas(resources) {
563
580
  };
564
581
  }
565
582
  } else {
566
- schemas[resource.name] = {
567
- type: "object",
568
- description: resource.displayName,
569
- properties: {
570
- _id: { type: "string", description: "Unique identifier" },
571
- createdAt: { type: "string", format: "date-time", description: "Creation timestamp" },
572
- updatedAt: { type: "string", format: "date-time", description: "Last update timestamp" }
573
- }
574
- };
575
583
  schemas[`${resource.name}Input`] = {
576
584
  type: "object",
577
585
  description: `${resource.displayName} input`
@@ -1,11 +1,11 @@
1
- export { A as ArcFactory, c as createApp } from '../createApp-pzUAkzbz.js';
2
- import { C as CreateAppOptions } from '../types-0IPhH_NR.js';
3
- export { M as MultipartOptions, R as RawBodyOptions, U as UnderPressureOptions } from '../types-0IPhH_NR.js';
1
+ export { A as ArcFactory, c as createApp } from '../createApp-9q_I1la4.js';
2
+ import { C as CreateAppOptions } from '../types-EBZBXrg-.js';
3
+ export { M as MultipartOptions, R as RawBodyOptions, U as UnderPressureOptions } from '../types-EBZBXrg-.js';
4
4
  import 'fastify';
5
5
  import '@fastify/cors';
6
6
  import '@fastify/helmet';
7
7
  import '@fastify/rate-limit';
8
- import '../index-DkAW8BXh.js';
8
+ import '../index-WBEvhmWM.js';
9
9
  import 'mongoose';
10
10
  import '../types-B99TBmFV.js';
11
11
 
@@ -1478,9 +1478,7 @@ async function loadPlugin(name, logger) {
1478
1478
  const err = error;
1479
1479
  const isModuleNotFound = err.message.includes("Cannot find module") || err.message.includes("Cannot find package") || err.message.includes("MODULE_NOT_FOUND") || err.message.includes("Could not resolve");
1480
1480
  if (isModuleNotFound && OPTIONAL_PLUGINS.has(name)) {
1481
- logger?.warn(
1482
- `ℹ️ Optional plugin '${name}' skipped (${packageName} not installed)`
1483
- );
1481
+ logger?.warn(`ℹ️ Optional plugin '${name}' skipped (${packageName} not installed)`);
1484
1482
  return null;
1485
1483
  }
1486
1484
  if (isModuleNotFound) {
@@ -1519,10 +1517,7 @@ async function createApp(options) {
1519
1517
  });
1520
1518
  if (config.helmet !== false) {
1521
1519
  const helmet = await loadPlugin("helmet");
1522
- await fastify.register(
1523
- helmet,
1524
- config.helmet ?? {}
1525
- );
1520
+ await fastify.register(helmet, config.helmet ?? {});
1526
1521
  fastify.log.info("✅ Helmet (security headers) enabled");
1527
1522
  } else {
1528
1523
  fastify.log.warn("⚠️ Helmet disabled - security headers not applied");
@@ -1542,20 +1537,14 @@ async function createApp(options) {
1542
1537
  }
1543
1538
  if (config.rateLimit !== false) {
1544
1539
  const rateLimit = await loadPlugin("rateLimit");
1545
- await fastify.register(
1546
- rateLimit,
1547
- config.rateLimit ?? { max: 100, timeWindow: "1 minute" }
1548
- );
1540
+ await fastify.register(rateLimit, config.rateLimit ?? { max: 100, timeWindow: "1 minute" });
1549
1541
  fastify.log.info("✅ Rate limiting enabled");
1550
1542
  } else {
1551
1543
  fastify.log.warn("⚠️ Rate limiting disabled");
1552
1544
  }
1553
1545
  if (config.underPressure !== false) {
1554
1546
  const underPressure = await loadPlugin("underPressure");
1555
- await fastify.register(
1556
- underPressure,
1557
- config.underPressure ?? { exposeStatusRoute: true }
1558
- );
1547
+ await fastify.register(underPressure, config.underPressure ?? { exposeStatusRoute: true });
1559
1548
  fastify.log.info("✅ Health monitoring (under-pressure) enabled");
1560
1549
  } else {
1561
1550
  fastify.log.info("ℹ️ Health monitoring disabled");
@@ -1575,10 +1564,7 @@ async function createApp(options) {
1575
1564
  files: 10
1576
1565
  }
1577
1566
  };
1578
- await fastify.register(multipart, {
1579
- ...multipartDefaults,
1580
- ...config.multipart
1581
- });
1567
+ await fastify.register(multipart, { ...multipartDefaults, ...config.multipart });
1582
1568
  fastify.log.info("✅ Multipart (file uploads) enabled");
1583
1569
  }
1584
1570
  }
@@ -1591,10 +1577,7 @@ async function createApp(options) {
1591
1577
  encoding: "utf8",
1592
1578
  runFirst: true
1593
1579
  };
1594
- await fastify.register(rawBody, {
1595
- ...rawBodyDefaults,
1596
- ...config.rawBody
1597
- });
1580
+ await fastify.register(rawBody, { ...rawBodyDefaults, ...config.rawBody });
1598
1581
  fastify.log.info("✅ Raw body parsing enabled");
1599
1582
  }
1600
1583
  }
@@ -1,4 +1,4 @@
1
- export { ac as HookContext, ad as HookHandler, aH as HookOperation, aG as HookPhase, aI as HookRegistration, H as HookSystem, aJ as HookSystemOptions, aB as afterCreate, aF as afterDelete, aD as afterUpdate, aA as beforeCreate, aE as beforeDelete, aC as beforeUpdate, az as createHookSystem, ab as hookSystem } from '../index-DkAW8BXh.js';
1
+ export { ac as HookContext, ad as HookHandler, aH as HookOperation, aG as HookPhase, aI as HookRegistration, H as HookSystem, aJ as HookSystemOptions, aB as afterCreate, aF as afterDelete, aD as afterUpdate, aA as beforeCreate, aE as beforeDelete, aC as beforeUpdate, az as createHookSystem, ab as hookSystem } from '../index-WBEvhmWM.js';
2
2
  import 'mongoose';
3
3
  import 'fastify';
4
4
  import '../types-B99TBmFV.js';
@@ -405,8 +405,8 @@ interface IRequestContext {
405
405
  headers: Record<string, string | undefined>;
406
406
  /** Organization ID (for multi-tenant apps) */
407
407
  organizationId?: string;
408
- /** Additional context data */
409
- context?: Record<string, unknown>;
408
+ /** Additional metadata and custom fields */
409
+ metadata?: Record<string, unknown>;
410
410
  }
411
411
  /**
412
412
  * Standard response from controller handlers
@@ -428,13 +428,13 @@ interface IControllerResponse<T = unknown> {
428
428
  /**
429
429
  * Controller handler - Arc's standard pattern
430
430
  *
431
- * Receives a context object, returns IControllerResponse.
431
+ * Receives a request context object, returns IControllerResponse.
432
432
  * Use with `wrapHandler: true` in additionalRoutes.
433
433
  *
434
434
  * @example
435
435
  * ```typescript
436
- * const createProduct: ControllerHandler<Product> = async (ctx) => {
437
- * const product = await productRepo.create(ctx.body);
436
+ * const createProduct: ControllerHandler<Product> = async (req) => {
437
+ * const product = await productRepo.create(req.body);
438
438
  * return { success: true, data: product, status: 201 };
439
439
  * };
440
440
  *
@@ -447,7 +447,7 @@ interface IControllerResponse<T = unknown> {
447
447
  * }]
448
448
  * ```
449
449
  */
450
- type ControllerHandler<T = unknown> = (context: IRequestContext) => Promise<IControllerResponse<T>>;
450
+ type ControllerHandler<T = unknown> = (req: IRequestContext) => Promise<IControllerResponse<T>>;
451
451
  /**
452
452
  * Fastify native handler
453
453
  *
@@ -480,14 +480,14 @@ type RouteHandler = ControllerHandler | FastifyHandler;
480
480
  * Controller interface for CRUD operations (strict)
481
481
  */
482
482
  interface IController<TDoc = unknown> {
483
- list(context: IRequestContext): Promise<IControllerResponse<{
483
+ list(req: IRequestContext): Promise<IControllerResponse<{
484
484
  docs: TDoc[];
485
485
  total: number;
486
486
  }>>;
487
- get(context: IRequestContext): Promise<IControllerResponse<TDoc>>;
488
- create(context: IRequestContext): Promise<IControllerResponse<TDoc>>;
489
- update(context: IRequestContext): Promise<IControllerResponse<TDoc>>;
490
- delete(context: IRequestContext): Promise<IControllerResponse<{
487
+ get(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
488
+ create(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
489
+ update(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
490
+ delete(req: IRequestContext): Promise<IControllerResponse<{
491
491
  message: string;
492
492
  }>>;
493
493
  }
@@ -832,6 +832,26 @@ interface OpenApiSchemas {
832
832
  updateBody?: unknown;
833
833
  params?: unknown;
834
834
  listQuery?: unknown;
835
+ /**
836
+ * Explicit response schema for OpenAPI documentation.
837
+ * If provided, this will be used as-is for the response schema.
838
+ * If not provided, response schema is auto-generated from createBody.
839
+ *
840
+ * Note: This is for OpenAPI docs only - does NOT affect Fastify serialization.
841
+ *
842
+ * @example
843
+ * response: {
844
+ * type: 'object',
845
+ * properties: {
846
+ * _id: { type: 'string' },
847
+ * name: { type: 'string' },
848
+ * email: { type: 'string' },
849
+ * // Exclude password, include virtuals
850
+ * fullName: { type: 'string' },
851
+ * }
852
+ * }
853
+ */
854
+ response?: unknown;
835
855
  [key: string]: unknown;
836
856
  }
837
857
  /** Handler for middleware functions */
@@ -1299,4 +1319,4 @@ interface ValidationResult {
1299
1319
  }
1300
1320
  type AdapterFactory<TDoc> = (config: unknown) => DataAdapter<TDoc>;
1301
1321
 
1302
- export { type InferDocType as $, type AuthHelpers as A, type CrudController as B, type CrudRouteKey as C, type DataAdapter as D, type FieldRule as E, type FieldMetadata as F, type CrudSchemas as G, HookSystem as H, type IntrospectionPluginOptions as I, type JWTPayload as J, type AdditionalRoute as K, type PresetFunction as L, type MiddlewareConfig as M, type EventDefinition as N, type OwnershipCheck as O, type PresetResult as P, type QueryOptions as Q, type RequestWithExtras as R, type ServiceContext as S, type ResourceMetadata as T, type UserOrganization as U, type ValidationResult as V, type RegistryEntry as W, type RegistryStats as X, type IntrospectionData as Y, type OrgScopeOptions as Z, type CrudRouterOptions as _, type AuthPluginOptions as a, type InferResourceDoc as a0, type TypedResourceConfig as a1, type TypedController as a2, type TypedRepository as a3, type ConfigError as a4, type ValidationResult$1 as a5, type ValidateOptions as a6, type HealthCheck as a7, type HealthOptions as a8, type GracefulShutdownOptions as a9, beforeCreate as aA, afterCreate as aB, beforeUpdate as aC, afterUpdate as aD, beforeDelete as aE, afterDelete as aF, type HookPhase as aG, type HookOperation as aH, type HookRegistration as aI, type HookSystemOptions as aJ, type RequestIdOptions as aa, hookSystem as ab, type HookContext as ac, type HookHandler as ad, type ParsedQuery as ae, type OpenApiSchemas as af, type AdapterFactory as ag, type ObjectId as ah, type UserLike as ai, getUserId as aj, type ArcDecorator as ak, type EventsDecorator as al, type ResourcePermissions as am, type ResourceHooks as an, type MiddlewareHandler as ao, type JwtContext as ap, type AuthenticatorContext as aq, type Authenticator as ar, type TokenPair as as, type PresetHook as at, type BaseControllerOptions as au, type PaginationParams as av, type InferDoc as aw, type ControllerHandler as ax, type FastifyHandler as ay, createHookSystem as az, ResourceRegistry as b, type RegisterOptions as c, type AnyRecord as d, type IController as e, type CrudRepository as f, type RouteSchemaOptions as g, type QueryParserInterface as h, type RepositoryLike as i, type IRequestContext as j, type ControllerQueryOptions as k, type RequestContext as l, type IControllerResponse as m, type PaginatedResult as n, type ResourceConfig as o, type SchemaMetadata as p, type RelationMetadata as q, resourceRegistry as r, defineResource as s, ResourceDefinition as t, type ApiResponse as u, type ControllerLike as v, type FastifyRequestExtras as w, type FastifyWithAuth as x, type FastifyWithDecorators as y, type RouteHandler as z };
1322
+ export { type InferDocType as $, type AuthHelpers as A, type CrudController as B, type CrudRouteKey as C, type DataAdapter as D, type FieldRule as E, type FieldMetadata as F, type CrudSchemas as G, HookSystem as H, type IntrospectionPluginOptions as I, type JWTPayload as J, type AdditionalRoute as K, type PresetFunction as L, type MiddlewareConfig as M, type EventDefinition as N, type OwnershipCheck as O, type PresetResult as P, type QueryParserInterface as Q, type RequestWithExtras as R, type ServiceContext as S, type ResourceMetadata as T, type UserOrganization as U, type ValidationResult as V, type RegistryEntry as W, type RegistryStats as X, type IntrospectionData as Y, type OrgScopeOptions as Z, type CrudRouterOptions as _, type AuthPluginOptions as a, type InferResourceDoc as a0, type TypedResourceConfig as a1, type TypedController as a2, type TypedRepository as a3, type ConfigError as a4, type ValidationResult$1 as a5, type ValidateOptions as a6, type HealthCheck as a7, type HealthOptions as a8, type GracefulShutdownOptions as a9, beforeCreate as aA, afterCreate as aB, beforeUpdate as aC, afterUpdate as aD, beforeDelete as aE, afterDelete as aF, type HookPhase as aG, type HookOperation as aH, type HookRegistration as aI, type HookSystemOptions as aJ, type RequestIdOptions as aa, hookSystem as ab, type HookContext as ac, type HookHandler as ad, type ParsedQuery as ae, type OpenApiSchemas as af, type AdapterFactory as ag, type ObjectId as ah, type UserLike as ai, getUserId as aj, type ArcDecorator as ak, type EventsDecorator as al, type ResourcePermissions as am, type ResourceHooks as an, type MiddlewareHandler as ao, type JwtContext as ap, type AuthenticatorContext as aq, type Authenticator as ar, type TokenPair as as, type PresetHook as at, type BaseControllerOptions as au, type PaginationParams as av, type InferDoc as aw, type ControllerHandler as ax, type FastifyHandler as ay, createHookSystem as az, ResourceRegistry as b, type RegisterOptions as c, type AnyRecord as d, type IController as e, type RouteSchemaOptions as f, type IRequestContext as g, type ControllerQueryOptions as h, type RequestContext as i, type IControllerResponse as j, type PaginatedResult as k, type ResourceConfig as l, type SchemaMetadata as m, type RelationMetadata as n, type RepositoryLike as o, defineResource as p, ResourceDefinition as q, resourceRegistry as r, type ApiResponse as s, type ControllerLike as t, type FastifyRequestExtras as u, type FastifyWithAuth as v, type FastifyWithDecorators as w, type QueryOptions as x, type CrudRepository as y, type RouteHandler as z };
package/dist/index.d.ts CHANGED
@@ -1,14 +1,14 @@
1
- import { d as AnyRecord, e as IController, f as CrudRepository, Q as QueryOptions, g as RouteSchemaOptions, h as QueryParserInterface, i as RepositoryLike, j as IRequestContext, S as ServiceContext, k as ControllerQueryOptions, l as RequestContext, H as HookSystem, m as IControllerResponse, n as PaginatedResult, o as ResourceConfig } from './index-DkAW8BXh.js';
2
- export { V as AdapterValidationResult, K as AdditionalRoute, u as ApiResponse, a as AuthPluginOptions, a4 as ConfigError, v as ControllerLike, B as CrudController, C as CrudRouteKey, _ as CrudRouterOptions, G as CrudSchemas, D as DataAdapter, N as EventDefinition, w as FastifyRequestExtras, x as FastifyWithAuth, y as FastifyWithDecorators, F as FieldMetadata, E as FieldRule, a9 as GracefulShutdownOptions, a7 as HealthCheck, a8 as HealthOptions, ac as HookContext, ad as HookHandler, $ as InferDocType, a0 as InferResourceDoc, Y as IntrospectionData, I as IntrospectionPluginOptions, J as JWTPayload, M as MiddlewareConfig, Z as OrgScopeOptions, O as OwnershipCheck, L as PresetFunction, P as PresetResult, W as RegistryEntry, X as RegistryStats, q as RelationMetadata, aa as RequestIdOptions, R as RequestWithExtras, t as ResourceDefinition, T as ResourceMetadata, z as RouteHandler, p as SchemaMetadata, a2 as TypedController, a3 as TypedRepository, a1 as TypedResourceConfig, U as UserOrganization, a6 as ValidateOptions, a5 as ValidationResult, s as defineResource, ab as hookSystem, r as resourceRegistry } from './index-DkAW8BXh.js';
1
+ import { d as AnyRecord, e as IController, f as RouteSchemaOptions, Q as QueryParserInterface, g as IRequestContext, S as ServiceContext, h as ControllerQueryOptions, i as RequestContext, H as HookSystem, j as IControllerResponse, k as PaginatedResult, l as ResourceConfig } from './index-WBEvhmWM.js';
2
+ export { V as AdapterValidationResult, K as AdditionalRoute, s as ApiResponse, a as AuthPluginOptions, a4 as ConfigError, t as ControllerLike, B as CrudController, y as CrudRepository, C as CrudRouteKey, _ as CrudRouterOptions, G as CrudSchemas, D as DataAdapter, N as EventDefinition, u as FastifyRequestExtras, v as FastifyWithAuth, w as FastifyWithDecorators, F as FieldMetadata, E as FieldRule, a9 as GracefulShutdownOptions, a7 as HealthCheck, a8 as HealthOptions, ac as HookContext, ad as HookHandler, $ as InferDocType, a0 as InferResourceDoc, Y as IntrospectionData, I as IntrospectionPluginOptions, J as JWTPayload, M as MiddlewareConfig, Z as OrgScopeOptions, O as OwnershipCheck, L as PresetFunction, P as PresetResult, x as QueryOptions, W as RegistryEntry, X as RegistryStats, n as RelationMetadata, o as RepositoryLike, aa as RequestIdOptions, R as RequestWithExtras, q as ResourceDefinition, T as ResourceMetadata, z as RouteHandler, m as SchemaMetadata, a2 as TypedController, a3 as TypedRepository, a1 as TypedResourceConfig, U as UserOrganization, a6 as ValidateOptions, a5 as ValidationResult, p as defineResource, ab as hookSystem, r as resourceRegistry } from './index-WBEvhmWM.js';
3
3
  export { MongooseAdapter, MongooseAdapterOptions, PrismaAdapter, PrismaAdapterOptions, createMongooseAdapter, createPrismaAdapter } from './adapters/index.js';
4
4
  export { RouteHandlerMethod } from 'fastify';
5
5
  export { P as PermissionCheck, a as PermissionContext, b as PermissionResult, U as UserBase } from './types-B99TBmFV.js';
6
6
  export { A as ArcError, F as ForbiddenError, N as NotFoundError, U as UnauthorizedError, V as ValidationError } from './errors-8WIxGS_6.js';
7
- export { e as gracefulShutdownPlugin, a as healthPlugin, _ as requestIdPlugin } from './arcCorePlugin-DTPWXcZN.js';
7
+ export { e as gracefulShutdownPlugin, a as healthPlugin, _ as requestIdPlugin } from './arcCorePlugin-Cqi7j5-_.js';
8
8
  export { DomainEvent, EventHandler, eventPlugin } from './events/index.js';
9
9
  export { allOf, allowPublic, anyOf, denyAll, requireAuth, requireOwnership, requireRoles, when } from './permissions/index.js';
10
- export { A as ArcFactory, c as createApp } from './createApp-pzUAkzbz.js';
11
- export { C as CreateAppOptions } from './types-0IPhH_NR.js';
10
+ export { A as ArcFactory, c as createApp } from './createApp-9q_I1la4.js';
11
+ export { C as CreateAppOptions } from './types-EBZBXrg-.js';
12
12
  import 'mongoose';
13
13
  import '@fastify/cors';
14
14
  import '@fastify/helmet';
@@ -47,15 +47,24 @@ import '@fastify/rate-limit';
47
47
  */
48
48
 
49
49
  /**
50
- * Extended repository type that includes optional preset methods
51
- * Used internally for type-safe access to preset-added methods
50
+ * Flexible repository interface that accepts any repository shape
51
+ * Core CRUD methods use flexible signatures to work with any implementation
52
+ * Custom methods can be added via the index signature
53
+ *
54
+ * @example
55
+ * // MongoKit repository with custom methods
56
+ * interface MyRepository extends FlexibleRepository {
57
+ * findByEmail(email: string): Promise<User>;
58
+ * customMethod(): Promise<void>;
59
+ * }
52
60
  */
53
- interface ExtendedRepository<TDoc> extends CrudRepository<TDoc> {
54
- getBySlug?(slug: string, options?: QueryOptions): Promise<TDoc | null>;
55
- getDeleted?(options?: QueryOptions): Promise<TDoc[]>;
56
- restore?(id: string, options?: QueryOptions): Promise<TDoc | null>;
57
- getTree?(options?: QueryOptions): Promise<TDoc[]>;
58
- getChildren?(parentId: string, options?: QueryOptions): Promise<TDoc[]>;
61
+ interface FlexibleRepository {
62
+ getAll(...args: any[]): Promise<any>;
63
+ getById(...args: any[]): Promise<any>;
64
+ create(...args: any[]): Promise<any>;
65
+ update(...args: any[]): Promise<any>;
66
+ delete(...args: any[]): Promise<any>;
67
+ [key: string]: any;
59
68
  }
60
69
  interface BaseControllerOptions {
61
70
  /** Schema options for field sanitization */
@@ -80,10 +89,34 @@ interface BaseControllerOptions {
80
89
  /**
81
90
  * Framework-agnostic base controller implementing MongoKit's IController
82
91
  *
92
+ * @template TDoc - The document type
93
+ * @template TRepository - The repository type (defaults to CrudRepository<TDoc>, preserves custom methods when specified)
94
+ *
83
95
  * Use with Fastify adapter for Fastify integration (see createFastifyAdapter in createCrudRouter)
96
+ *
97
+ * @example
98
+ * // Without custom repository type (backward compatible)
99
+ * class SimpleController extends BaseController<Product> {
100
+ * constructor(repository: CrudRepository<Product>) {
101
+ * super(repository);
102
+ * }
103
+ * }
104
+ *
105
+ * @example
106
+ * // With custom repository type (type-safe access to custom methods)
107
+ * class ProductController extends BaseController<Product, ProductRepository> {
108
+ * constructor(repository: ProductRepository) {
109
+ * super(repository);
110
+ * }
111
+ *
112
+ * async customMethod(context: IRequestContext) {
113
+ * // TypeScript knows about ProductRepository's custom methods
114
+ * return await this.repository.findByCategory(...);
115
+ * }
116
+ * }
84
117
  */
85
- declare class BaseController<TDoc = AnyRecord> implements IController<TDoc> {
86
- protected repository: ExtendedRepository<TDoc>;
118
+ declare class BaseController<TDoc = AnyRecord, TRepository extends FlexibleRepository = FlexibleRepository> implements IController<TDoc> {
119
+ protected repository: TRepository;
87
120
  protected schemaOptions: RouteSchemaOptions;
88
121
  protected queryParser: QueryParserInterface;
89
122
  protected maxLimit: number;
@@ -96,7 +129,7 @@ declare class BaseController<TDoc = AnyRecord> implements IController<TDoc> {
96
129
  slugField?: string;
97
130
  parentField?: string;
98
131
  };
99
- constructor(repository: CrudRepository<TDoc> | RepositoryLike, options?: BaseControllerOptions);
132
+ constructor(repository: TRepository, options?: BaseControllerOptions);
100
133
  /**
101
134
  * Inject resource options from defineResource
102
135
  */
@@ -112,20 +145,20 @@ declare class BaseController<TDoc = AnyRecord> implements IController<TDoc> {
112
145
  /**
113
146
  * Build service context from IRequestContext
114
147
  */
115
- protected _buildContext(context: IRequestContext): ServiceContext;
148
+ protected _buildContext(req: IRequestContext): ServiceContext;
116
149
  /**
117
150
  * Parse query into QueryOptions using queryParser
118
151
  */
119
- protected _parseQueryOptions(context: IRequestContext): ControllerQueryOptions;
152
+ protected _parseQueryOptions(req: IRequestContext): ControllerQueryOptions;
120
153
  /**
121
154
  * Apply org and policy filters
122
155
  */
123
- protected _applyFilters(options: ControllerQueryOptions, context: IRequestContext): ControllerQueryOptions;
156
+ protected _applyFilters(options: ControllerQueryOptions, req: IRequestContext): ControllerQueryOptions;
124
157
  /**
125
158
  * Build filter for single-item operations (get/update/delete)
126
159
  * Combines ID filter with policy/org filters for proper security enforcement
127
160
  */
128
- protected _buildIdFilter(id: string, context: IRequestContext): AnyRecord;
161
+ protected _buildIdFilter(id: string, req: IRequestContext): AnyRecord;
129
162
  /**
130
163
  * Check if a value matches a MongoDB query operator
131
164
  */
@@ -149,7 +182,7 @@ declare class BaseController<TDoc = AnyRecord> implements IController<TDoc> {
149
182
  * Validates that fetched item satisfies all policy constraints
150
183
  * Supports MongoDB query operators: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $regex, $and, $or
151
184
  */
152
- protected _checkPolicyFilters(item: AnyRecord, context: IRequestContext): boolean;
185
+ protected _checkPolicyFilters(item: AnyRecord, req: IRequestContext): boolean;
153
186
  /** Parse lean option (default: true for performance) */
154
187
  protected _parseLean(leanValue: unknown): boolean;
155
188
  /** Get blocked fields from schema options */
@@ -166,49 +199,49 @@ declare class BaseController<TDoc = AnyRecord> implements IController<TDoc> {
166
199
  /** Check org scope for a document */
167
200
  protected _checkOrgScope(item: AnyRecord | null, arcContext: RequestContext | undefined): boolean;
168
201
  /** Check ownership for update/delete (ownedByUser preset) */
169
- protected _checkOwnership(item: AnyRecord | null, context: IRequestContext): boolean;
202
+ protected _checkOwnership(item: AnyRecord | null, req: IRequestContext): boolean;
170
203
  /**
171
204
  * Get hook system from context (instance-scoped) or fall back to global singleton
172
205
  * This allows proper isolation when running multiple app instances (e.g., in tests)
173
206
  */
174
- protected _getHooks(context: IRequestContext): HookSystem;
207
+ protected _getHooks(req: IRequestContext): HookSystem;
175
208
  /**
176
209
  * List resources with filtering, pagination, sorting
177
210
  * Implements IController.list()
178
211
  */
179
- list(context: IRequestContext): Promise<IControllerResponse<PaginatedResult<TDoc>>>;
212
+ list(req: IRequestContext): Promise<IControllerResponse<PaginatedResult<TDoc>>>;
180
213
  /**
181
214
  * Get single resource by ID
182
215
  * Implements IController.get()
183
216
  */
184
- get(context: IRequestContext): Promise<IControllerResponse<TDoc>>;
217
+ get(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
185
218
  /**
186
219
  * Create new resource
187
220
  * Implements IController.create()
188
221
  */
189
- create(context: IRequestContext): Promise<IControllerResponse<TDoc>>;
222
+ create(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
190
223
  /**
191
224
  * Update existing resource
192
225
  * Implements IController.update()
193
226
  */
194
- update(context: IRequestContext): Promise<IControllerResponse<TDoc>>;
227
+ update(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
195
228
  /**
196
229
  * Delete resource
197
230
  * Implements IController.delete()
198
231
  */
199
- delete(context: IRequestContext): Promise<IControllerResponse<{
232
+ delete(req: IRequestContext): Promise<IControllerResponse<{
200
233
  message: string;
201
234
  }>>;
202
235
  /** Get resource by slug (slugLookup preset) */
203
- getBySlug(context: IRequestContext): Promise<IControllerResponse<TDoc>>;
236
+ getBySlug(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
204
237
  /** Get soft-deleted resources (softDelete preset) */
205
- getDeleted(context: IRequestContext): Promise<IControllerResponse<PaginatedResult<TDoc>>>;
238
+ getDeleted(req: IRequestContext): Promise<IControllerResponse<PaginatedResult<TDoc>>>;
206
239
  /** Restore soft-deleted resource (softDelete preset) */
207
- restore(context: IRequestContext): Promise<IControllerResponse<TDoc>>;
240
+ restore(req: IRequestContext): Promise<IControllerResponse<TDoc>>;
208
241
  /** Get hierarchical tree (tree preset) */
209
- getTree(context: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
242
+ getTree(req: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
210
243
  /** Get children of parent (tree preset) */
211
- getChildren(context: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
244
+ getChildren(req: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
212
245
  }
213
246
 
214
247
  /**
@@ -328,4 +361,4 @@ declare function assertValidConfig(config: ResourceConfig, options?: ValidateOpt
328
361
 
329
362
  declare const version = "1.0.0";
330
363
 
331
- export { AnyRecord, BaseController, type BaseControllerOptions, CrudRepository, HookSystem, IController, IControllerResponse, IRequestContext, PaginatedResult, QueryOptions, RepositoryLike, RequestContext, ResourceConfig, RouteSchemaOptions, ServiceContext, assertValidConfig, formatValidationErrors, validateResourceConfig, version };
364
+ export { AnyRecord, BaseController, type BaseControllerOptions, HookSystem, IController, IControllerResponse, IRequestContext, PaginatedResult, RequestContext, ResourceConfig, RouteSchemaOptions, ServiceContext, assertValidConfig, formatValidationErrors, validateResourceConfig, version };