@classytic/arc 1.0.0 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -35
- package/bin/arc.js +118 -103
- package/dist/BaseController-nNRS3vpA.d.ts +233 -0
- package/dist/adapters/index.d.ts +2 -2
- package/dist/{arcCorePlugin-DTPWXcZN.d.ts → arcCorePlugin-CAjBQtZB.d.ts} +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/cli/commands/generate.d.ts +16 -0
- package/dist/cli/commands/generate.js +334 -0
- package/dist/cli/commands/init.d.ts +24 -0
- package/dist/cli/commands/init.js +2425 -0
- package/dist/cli/index.d.ts +4 -43
- package/dist/cli/index.js +3160 -411
- package/dist/core/index.d.ts +220 -0
- package/dist/core/index.js +2764 -0
- package/dist/{createApp-pzUAkzbz.d.ts → createApp-CjN9zZSL.d.ts} +1 -1
- package/dist/docs/index.js +19 -11
- package/dist/factory/index.d.ts +4 -4
- package/dist/factory/index.js +6 -23
- package/dist/hooks/index.d.ts +1 -1
- package/dist/{index-DkAW8BXh.d.ts → index-D5QTob1X.d.ts} +32 -12
- package/dist/index.d.ts +7 -203
- package/dist/index.js +108 -113
- package/dist/org/index.d.ts +1 -1
- package/dist/permissions/index.js +5 -2
- package/dist/plugins/index.d.ts +2 -2
- package/dist/presets/index.d.ts +6 -6
- package/dist/presets/index.js +3 -1
- package/dist/presets/multiTenant.d.ts +1 -1
- package/dist/registry/index.d.ts +2 -2
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +6 -23
- package/dist/types/index.d.ts +1 -1
- package/dist/{types-0IPhH_NR.d.ts → types-zpN48n6B.d.ts} +1 -1
- package/dist/utils/index.d.ts +28 -4
- package/dist/utils/index.js +17 -8
- package/package.json +8 -14
package/dist/docs/index.js
CHANGED
|
@@ -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?.
|
|
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`
|
package/dist/factory/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export { A as ArcFactory, c as createApp } from '../createApp-
|
|
2
|
-
import { C as CreateAppOptions } from '../types-
|
|
3
|
-
export { M as MultipartOptions, R as RawBodyOptions, U as UnderPressureOptions } from '../types-
|
|
1
|
+
export { A as ArcFactory, c as createApp } from '../createApp-CjN9zZSL.js';
|
|
2
|
+
import { C as CreateAppOptions } from '../types-zpN48n6B.js';
|
|
3
|
+
export { M as MultipartOptions, R as RawBodyOptions, U as UnderPressureOptions } from '../types-zpN48n6B.js';
|
|
4
4
|
import 'fastify';
|
|
5
5
|
import '@fastify/cors';
|
|
6
6
|
import '@fastify/helmet';
|
|
7
7
|
import '@fastify/rate-limit';
|
|
8
|
-
import '../index-
|
|
8
|
+
import '../index-D5QTob1X.js';
|
|
9
9
|
import 'mongoose';
|
|
10
10
|
import '../types-B99TBmFV.js';
|
|
11
11
|
|
package/dist/factory/index.js
CHANGED
|
@@ -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
|
}
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -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-
|
|
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-D5QTob1X.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
|
|
409
|
-
|
|
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 (
|
|
437
|
-
* const product = await productRepo.create(
|
|
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> = (
|
|
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(
|
|
483
|
+
list(req: IRequestContext): Promise<IControllerResponse<{
|
|
484
484
|
docs: TDoc[];
|
|
485
485
|
total: number;
|
|
486
486
|
}>>;
|
|
487
|
-
get(
|
|
488
|
-
create(
|
|
489
|
-
update(
|
|
490
|
-
delete(
|
|
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
|
|
1322
|
+
export { type InferDocType as $, type AnyRecord as A, type CrudController as B, type ControllerQueryOptions as C, type DataAdapter as D, type FieldRule as E, type FieldMetadata as F, type CrudSchemas as G, HookSystem as H, type IController 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 PaginatedResult as P, type QueryParserInterface as Q, type RouteSchemaOptions 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 IRequestContext 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, type RequestContext as b, type IControllerResponse as c, type RequestWithExtras as d, type CrudRouteKey as e, type PresetResult as f, type AuthHelpers as g, type AuthPluginOptions as h, type IntrospectionPluginOptions as i, ResourceRegistry as j, type RegisterOptions 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,216 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { V as AdapterValidationResult, K as AdditionalRoute,
|
|
1
|
+
import { l as ResourceConfig } from './index-D5QTob1X.js';
|
|
2
|
+
export { V as AdapterValidationResult, K as AdditionalRoute, A as AnyRecord, s as ApiResponse, h as AuthPluginOptions, a4 as ConfigError, t as ControllerLike, B as CrudController, y as CrudRepository, e 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, H as HookSystem, I as IController, c as IControllerResponse, a as IRequestContext, $ as InferDocType, a0 as InferResourceDoc, Y as IntrospectionData, i as IntrospectionPluginOptions, J as JWTPayload, M as MiddlewareConfig, Z as OrgScopeOptions, O as OwnershipCheck, P as PaginatedResult, L as PresetFunction, f as PresetResult, x as QueryOptions, W as RegistryEntry, X as RegistryStats, n as RelationMetadata, o as RepositoryLike, b as RequestContext, aa as RequestIdOptions, d as RequestWithExtras, q as ResourceDefinition, T as ResourceMetadata, z as RouteHandler, R as RouteSchemaOptions, m as SchemaMetadata, S as ServiceContext, 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-D5QTob1X.js';
|
|
3
3
|
export { MongooseAdapter, MongooseAdapterOptions, PrismaAdapter, PrismaAdapterOptions, createMongooseAdapter, createPrismaAdapter } from './adapters/index.js';
|
|
4
|
+
export { B as BaseController, a as BaseControllerOptions } from './BaseController-nNRS3vpA.js';
|
|
4
5
|
export { RouteHandlerMethod } from 'fastify';
|
|
5
6
|
export { P as PermissionCheck, a as PermissionContext, b as PermissionResult, U as UserBase } from './types-B99TBmFV.js';
|
|
6
7
|
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-
|
|
8
|
+
export { e as gracefulShutdownPlugin, a as healthPlugin, _ as requestIdPlugin } from './arcCorePlugin-CAjBQtZB.js';
|
|
8
9
|
export { DomainEvent, EventHandler, eventPlugin } from './events/index.js';
|
|
9
10
|
export { allOf, allowPublic, anyOf, denyAll, requireAuth, requireOwnership, requireRoles, when } from './permissions/index.js';
|
|
10
|
-
export { A as ArcFactory, c as createApp } from './createApp-
|
|
11
|
-
export { C as CreateAppOptions } from './types-
|
|
11
|
+
export { A as ArcFactory, c as createApp } from './createApp-CjN9zZSL.js';
|
|
12
|
+
export { C as CreateAppOptions } from './types-zpN48n6B.js';
|
|
12
13
|
import 'mongoose';
|
|
13
14
|
import '@fastify/cors';
|
|
14
15
|
import '@fastify/helmet';
|
|
15
16
|
import '@fastify/rate-limit';
|
|
16
17
|
|
|
17
|
-
/**
|
|
18
|
-
* Base Controller - Framework-Agnostic CRUD Operations
|
|
19
|
-
*
|
|
20
|
-
* Implements IController interface for framework portability.
|
|
21
|
-
* Works with Fastify, Express, Next.js, or any framework via adapter pattern.
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* import { BaseController } from '@classytic/arc';
|
|
25
|
-
*
|
|
26
|
-
* // Use Arc's default query parser (works out of the box)
|
|
27
|
-
* class ProductController extends BaseController {
|
|
28
|
-
* constructor(repository: CrudRepository) {
|
|
29
|
-
* super(repository);
|
|
30
|
-
* }
|
|
31
|
-
* }
|
|
32
|
-
*
|
|
33
|
-
* // Or use MongoKit's parser for advanced MongoDB features ($lookup, aggregations)
|
|
34
|
-
* import { QueryParser } from '@classytic/mongokit';
|
|
35
|
-
* defineResource({
|
|
36
|
-
* name: 'product',
|
|
37
|
-
* queryParser: new QueryParser(),
|
|
38
|
-
* // ...
|
|
39
|
-
* });
|
|
40
|
-
*
|
|
41
|
-
* // Or use a custom parser for SQL databases
|
|
42
|
-
* defineResource({
|
|
43
|
-
* name: 'user',
|
|
44
|
-
* queryParser: new PgQueryParser(),
|
|
45
|
-
* // ...
|
|
46
|
-
* });
|
|
47
|
-
*/
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Extended repository type that includes optional preset methods
|
|
51
|
-
* Used internally for type-safe access to preset-added methods
|
|
52
|
-
*/
|
|
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[]>;
|
|
59
|
-
}
|
|
60
|
-
interface BaseControllerOptions {
|
|
61
|
-
/** Schema options for field sanitization */
|
|
62
|
-
schemaOptions?: RouteSchemaOptions;
|
|
63
|
-
/**
|
|
64
|
-
* Query parser instance
|
|
65
|
-
* Default: Arc built-in query parser (adapter-agnostic).
|
|
66
|
-
* You can swap in MongoKit QueryParser, pgkit parser, etc.
|
|
67
|
-
*/
|
|
68
|
-
queryParser?: QueryParserInterface;
|
|
69
|
-
/** Maximum limit for pagination (default: 100) */
|
|
70
|
-
maxLimit?: number;
|
|
71
|
-
/** Default limit for pagination (default: 20) */
|
|
72
|
-
defaultLimit?: number;
|
|
73
|
-
/** Default sort field (default: '-createdAt') */
|
|
74
|
-
defaultSort?: string;
|
|
75
|
-
/** Resource name for hook execution (e.g., 'product' → 'product.created') */
|
|
76
|
-
resourceName?: string;
|
|
77
|
-
/** Disable automatic event emission (default: false) */
|
|
78
|
-
disableEvents?: boolean;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Framework-agnostic base controller implementing MongoKit's IController
|
|
82
|
-
*
|
|
83
|
-
* Use with Fastify adapter for Fastify integration (see createFastifyAdapter in createCrudRouter)
|
|
84
|
-
*/
|
|
85
|
-
declare class BaseController<TDoc = AnyRecord> implements IController<TDoc> {
|
|
86
|
-
protected repository: ExtendedRepository<TDoc>;
|
|
87
|
-
protected schemaOptions: RouteSchemaOptions;
|
|
88
|
-
protected queryParser: QueryParserInterface;
|
|
89
|
-
protected maxLimit: number;
|
|
90
|
-
protected defaultLimit: number;
|
|
91
|
-
protected defaultSort: string;
|
|
92
|
-
protected resourceName?: string;
|
|
93
|
-
protected disableEvents: boolean;
|
|
94
|
-
/** Preset field names for dynamic param reading */
|
|
95
|
-
protected _presetFields: {
|
|
96
|
-
slugField?: string;
|
|
97
|
-
parentField?: string;
|
|
98
|
-
};
|
|
99
|
-
constructor(repository: CrudRepository<TDoc> | RepositoryLike, options?: BaseControllerOptions);
|
|
100
|
-
/**
|
|
101
|
-
* Inject resource options from defineResource
|
|
102
|
-
*/
|
|
103
|
-
_setResourceOptions(options: {
|
|
104
|
-
schemaOptions?: RouteSchemaOptions;
|
|
105
|
-
presetFields?: {
|
|
106
|
-
slugField?: string;
|
|
107
|
-
parentField?: string;
|
|
108
|
-
};
|
|
109
|
-
resourceName?: string;
|
|
110
|
-
queryParser?: QueryParserInterface;
|
|
111
|
-
}): void;
|
|
112
|
-
/**
|
|
113
|
-
* Build service context from IRequestContext
|
|
114
|
-
*/
|
|
115
|
-
protected _buildContext(context: IRequestContext): ServiceContext;
|
|
116
|
-
/**
|
|
117
|
-
* Parse query into QueryOptions using queryParser
|
|
118
|
-
*/
|
|
119
|
-
protected _parseQueryOptions(context: IRequestContext): ControllerQueryOptions;
|
|
120
|
-
/**
|
|
121
|
-
* Apply org and policy filters
|
|
122
|
-
*/
|
|
123
|
-
protected _applyFilters(options: ControllerQueryOptions, context: IRequestContext): ControllerQueryOptions;
|
|
124
|
-
/**
|
|
125
|
-
* Build filter for single-item operations (get/update/delete)
|
|
126
|
-
* Combines ID filter with policy/org filters for proper security enforcement
|
|
127
|
-
*/
|
|
128
|
-
protected _buildIdFilter(id: string, context: IRequestContext): AnyRecord;
|
|
129
|
-
/**
|
|
130
|
-
* Check if a value matches a MongoDB query operator
|
|
131
|
-
*/
|
|
132
|
-
protected _matchesOperator(itemValue: unknown, operator: string, filterValue: unknown): boolean;
|
|
133
|
-
/**
|
|
134
|
-
* Forbidden paths that could lead to prototype pollution
|
|
135
|
-
*/
|
|
136
|
-
private static readonly FORBIDDEN_PATHS;
|
|
137
|
-
/**
|
|
138
|
-
* Get nested value from object using dot notation (e.g., "owner.id")
|
|
139
|
-
* Security: Validates path against forbidden patterns to prevent prototype pollution
|
|
140
|
-
*/
|
|
141
|
-
protected _getNestedValue(obj: AnyRecord, path: string): unknown;
|
|
142
|
-
/**
|
|
143
|
-
* Check if item matches a single filter condition
|
|
144
|
-
* Supports nested paths (e.g., "owner.id", "metadata.status")
|
|
145
|
-
*/
|
|
146
|
-
protected _matchesFilter(item: AnyRecord, key: string, filterValue: unknown): boolean;
|
|
147
|
-
/**
|
|
148
|
-
* Check if item matches policy filters (for get/update/delete operations)
|
|
149
|
-
* Validates that fetched item satisfies all policy constraints
|
|
150
|
-
* Supports MongoDB query operators: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists, $regex, $and, $or
|
|
151
|
-
*/
|
|
152
|
-
protected _checkPolicyFilters(item: AnyRecord, context: IRequestContext): boolean;
|
|
153
|
-
/** Parse lean option (default: true for performance) */
|
|
154
|
-
protected _parseLean(leanValue: unknown): boolean;
|
|
155
|
-
/** Get blocked fields from schema options */
|
|
156
|
-
protected _getBlockedFields(schemaOptions: RouteSchemaOptions): string[];
|
|
157
|
-
/**
|
|
158
|
-
* Convert parsed select object to string format
|
|
159
|
-
* Converts { name: 1, email: 1, password: 0 } → 'name email -password'
|
|
160
|
-
*/
|
|
161
|
-
protected _selectToString(select: string | string[] | Record<string, 0 | 1> | undefined): string | undefined;
|
|
162
|
-
/** Sanitize select fields */
|
|
163
|
-
protected _sanitizeSelect(select: string | undefined, schemaOptions: RouteSchemaOptions): string | undefined;
|
|
164
|
-
/** Sanitize populate fields */
|
|
165
|
-
protected _sanitizePopulate(populate: unknown, schemaOptions: RouteSchemaOptions): string[] | undefined;
|
|
166
|
-
/** Check org scope for a document */
|
|
167
|
-
protected _checkOrgScope(item: AnyRecord | null, arcContext: RequestContext | undefined): boolean;
|
|
168
|
-
/** Check ownership for update/delete (ownedByUser preset) */
|
|
169
|
-
protected _checkOwnership(item: AnyRecord | null, context: IRequestContext): boolean;
|
|
170
|
-
/**
|
|
171
|
-
* Get hook system from context (instance-scoped) or fall back to global singleton
|
|
172
|
-
* This allows proper isolation when running multiple app instances (e.g., in tests)
|
|
173
|
-
*/
|
|
174
|
-
protected _getHooks(context: IRequestContext): HookSystem;
|
|
175
|
-
/**
|
|
176
|
-
* List resources with filtering, pagination, sorting
|
|
177
|
-
* Implements IController.list()
|
|
178
|
-
*/
|
|
179
|
-
list(context: IRequestContext): Promise<IControllerResponse<PaginatedResult<TDoc>>>;
|
|
180
|
-
/**
|
|
181
|
-
* Get single resource by ID
|
|
182
|
-
* Implements IController.get()
|
|
183
|
-
*/
|
|
184
|
-
get(context: IRequestContext): Promise<IControllerResponse<TDoc>>;
|
|
185
|
-
/**
|
|
186
|
-
* Create new resource
|
|
187
|
-
* Implements IController.create()
|
|
188
|
-
*/
|
|
189
|
-
create(context: IRequestContext): Promise<IControllerResponse<TDoc>>;
|
|
190
|
-
/**
|
|
191
|
-
* Update existing resource
|
|
192
|
-
* Implements IController.update()
|
|
193
|
-
*/
|
|
194
|
-
update(context: IRequestContext): Promise<IControllerResponse<TDoc>>;
|
|
195
|
-
/**
|
|
196
|
-
* Delete resource
|
|
197
|
-
* Implements IController.delete()
|
|
198
|
-
*/
|
|
199
|
-
delete(context: IRequestContext): Promise<IControllerResponse<{
|
|
200
|
-
message: string;
|
|
201
|
-
}>>;
|
|
202
|
-
/** Get resource by slug (slugLookup preset) */
|
|
203
|
-
getBySlug(context: IRequestContext): Promise<IControllerResponse<TDoc>>;
|
|
204
|
-
/** Get soft-deleted resources (softDelete preset) */
|
|
205
|
-
getDeleted(context: IRequestContext): Promise<IControllerResponse<PaginatedResult<TDoc>>>;
|
|
206
|
-
/** Restore soft-deleted resource (softDelete preset) */
|
|
207
|
-
restore(context: IRequestContext): Promise<IControllerResponse<TDoc>>;
|
|
208
|
-
/** Get hierarchical tree (tree preset) */
|
|
209
|
-
getTree(context: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
|
|
210
|
-
/** Get children of parent (tree preset) */
|
|
211
|
-
getChildren(context: IRequestContext): Promise<IControllerResponse<TDoc[]>>;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
18
|
/**
|
|
215
19
|
* Resource Configuration Validator
|
|
216
20
|
*
|
|
@@ -328,4 +132,4 @@ declare function assertValidConfig(config: ResourceConfig, options?: ValidateOpt
|
|
|
328
132
|
|
|
329
133
|
declare const version = "1.0.0";
|
|
330
134
|
|
|
331
|
-
export {
|
|
135
|
+
export { ResourceConfig, assertValidConfig, formatValidationErrors, validateResourceConfig, version };
|