@classytic/arc 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +900 -0
  3. package/bin/arc.js +344 -0
  4. package/dist/adapters/index.d.ts +237 -0
  5. package/dist/adapters/index.js +668 -0
  6. package/dist/arcCorePlugin-DTPWXcZN.d.ts +273 -0
  7. package/dist/audit/index.d.ts +195 -0
  8. package/dist/audit/index.js +319 -0
  9. package/dist/auth/index.d.ts +47 -0
  10. package/dist/auth/index.js +174 -0
  11. package/dist/cli/commands/docs.d.ts +11 -0
  12. package/dist/cli/commands/docs.js +474 -0
  13. package/dist/cli/commands/introspect.d.ts +8 -0
  14. package/dist/cli/commands/introspect.js +338 -0
  15. package/dist/cli/index.d.ts +43 -0
  16. package/dist/cli/index.js +520 -0
  17. package/dist/createApp-pzUAkzbz.d.ts +77 -0
  18. package/dist/docs/index.d.ts +166 -0
  19. package/dist/docs/index.js +650 -0
  20. package/dist/errors-8WIxGS_6.d.ts +122 -0
  21. package/dist/events/index.d.ts +117 -0
  22. package/dist/events/index.js +89 -0
  23. package/dist/factory/index.d.ts +38 -0
  24. package/dist/factory/index.js +1664 -0
  25. package/dist/hooks/index.d.ts +4 -0
  26. package/dist/hooks/index.js +199 -0
  27. package/dist/idempotency/index.d.ts +323 -0
  28. package/dist/idempotency/index.js +500 -0
  29. package/dist/index-DkAW8BXh.d.ts +1302 -0
  30. package/dist/index.d.ts +331 -0
  31. package/dist/index.js +4734 -0
  32. package/dist/migrations/index.d.ts +185 -0
  33. package/dist/migrations/index.js +274 -0
  34. package/dist/org/index.d.ts +129 -0
  35. package/dist/org/index.js +220 -0
  36. package/dist/permissions/index.d.ts +144 -0
  37. package/dist/permissions/index.js +100 -0
  38. package/dist/plugins/index.d.ts +46 -0
  39. package/dist/plugins/index.js +1069 -0
  40. package/dist/policies/index.d.ts +398 -0
  41. package/dist/policies/index.js +196 -0
  42. package/dist/presets/index.d.ts +336 -0
  43. package/dist/presets/index.js +382 -0
  44. package/dist/presets/multiTenant.d.ts +39 -0
  45. package/dist/presets/multiTenant.js +112 -0
  46. package/dist/registry/index.d.ts +16 -0
  47. package/dist/registry/index.js +253 -0
  48. package/dist/testing/index.d.ts +618 -0
  49. package/dist/testing/index.js +48032 -0
  50. package/dist/types/index.d.ts +4 -0
  51. package/dist/types/index.js +8 -0
  52. package/dist/types-0IPhH_NR.d.ts +143 -0
  53. package/dist/types-B99TBmFV.d.ts +76 -0
  54. package/dist/utils/index.d.ts +655 -0
  55. package/dist/utils/index.js +905 -0
  56. package/package.json +227 -0
@@ -0,0 +1,331 @@
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';
3
+ export { MongooseAdapter, MongooseAdapterOptions, PrismaAdapter, PrismaAdapterOptions, createMongooseAdapter, createPrismaAdapter } from './adapters/index.js';
4
+ export { RouteHandlerMethod } from 'fastify';
5
+ export { P as PermissionCheck, a as PermissionContext, b as PermissionResult, U as UserBase } from './types-B99TBmFV.js';
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';
8
+ export { DomainEvent, EventHandler, eventPlugin } from './events/index.js';
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';
12
+ import 'mongoose';
13
+ import '@fastify/cors';
14
+ import '@fastify/helmet';
15
+ import '@fastify/rate-limit';
16
+
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
+ /**
215
+ * Resource Configuration Validator
216
+ *
217
+ * Fail-fast validation at definition time.
218
+ * Invalid configs throw immediately with clear, actionable errors.
219
+ *
220
+ * @example
221
+ * const result = validateResourceConfig(config);
222
+ * if (!result.valid) {
223
+ * console.error(formatValidationErrors(result.errors));
224
+ * }
225
+ */
226
+
227
+ interface ConfigError {
228
+ field: string;
229
+ message: string;
230
+ suggestion?: string;
231
+ }
232
+ interface ValidationResult {
233
+ valid: boolean;
234
+ errors: ConfigError[];
235
+ warnings: ConfigError[];
236
+ }
237
+ interface ValidateOptions {
238
+ /** Skip controller method validation (for testing) */
239
+ skipControllerCheck?: boolean;
240
+ /** Allow unknown preset names */
241
+ allowUnknownPresets?: boolean;
242
+ /** Custom valid permission keys beyond CRUD */
243
+ additionalPermissionKeys?: string[];
244
+ }
245
+ /**
246
+ * Validate a resource configuration
247
+ */
248
+ declare function validateResourceConfig(config: ResourceConfig, options?: ValidateOptions): ValidationResult;
249
+ /**
250
+ * Format validation errors for display
251
+ */
252
+ declare function formatValidationErrors(resourceName: string, result: ValidationResult): string;
253
+ /**
254
+ * Validate and throw if invalid
255
+ */
256
+ declare function assertValidConfig(config: ResourceConfig, options?: ValidateOptions): void;
257
+
258
+ /**
259
+ * @classytic/arc
260
+ *
261
+ * Resource-oriented backend framework for Fastify.
262
+ * Supports MongoDB (Mongoose) and PostgreSQL/MySQL/SQLite (Prisma).
263
+ *
264
+ * ## Import Strategy (Tree-Shaking)
265
+ *
266
+ * This main entry exports commonly-used items. For better tree-shaking,
267
+ * import from specific subpaths when needed:
268
+ *
269
+ * ```typescript
270
+ * // Main entry - common items
271
+ * import { defineResource, createMongooseAdapter, allowPublic } from '@classytic/arc';
272
+ *
273
+ * // Subpath imports - specialized modules
274
+ * import { createTestApp } from '@classytic/arc/testing';
275
+ * import { createApp } from '@classytic/arc/factory';
276
+ * import { PrismaQueryParser } from '@classytic/arc/adapters';
277
+ * import { beforeCreate, afterUpdate } from '@classytic/arc/hooks';
278
+ * import { MemoryEventTransport } from '@classytic/arc/events';
279
+ * import { createStateMachine } from '@classytic/arc/utils';
280
+ * ```
281
+ *
282
+ * ## Subpath Exports
283
+ *
284
+ * | Subpath | Purpose |
285
+ * |---------|---------|
286
+ * | `@classytic/arc/testing` | Test utilities, mocks, TestHarness |
287
+ * | `@classytic/arc/factory` | App creation (createApp, ArcFactory) |
288
+ * | `@classytic/arc/adapters` | Database adapters + PrismaQueryParser |
289
+ * | `@classytic/arc/permissions` | Permission functions |
290
+ * | `@classytic/arc/presets` | Preset functions |
291
+ * | `@classytic/arc/hooks` | Hook helpers (beforeCreate, etc.) |
292
+ * | `@classytic/arc/events` | Event transports |
293
+ * | `@classytic/arc/plugins` | Fastify plugins |
294
+ * | `@classytic/arc/utils` | Utilities (state machine, etc.) |
295
+ * | `@classytic/arc/org` | Organization utilities |
296
+ * | `@classytic/arc/audit` | Audit trail |
297
+ * | `@classytic/arc/idempotency` | Idempotency stores |
298
+ * | `@classytic/arc/types` | TypeScript types |
299
+ *
300
+ * @example Basic Resource
301
+ * ```typescript
302
+ * import { defineResource, createMongooseAdapter, allowPublic, requireRoles } from '@classytic/arc';
303
+ *
304
+ * const productResource = defineResource({
305
+ * name: 'product',
306
+ * adapter: createMongooseAdapter({ model: ProductModel, repository: productRepo }),
307
+ * permissions: {
308
+ * list: allowPublic(),
309
+ * create: requireRoles(['admin']),
310
+ * },
311
+ * });
312
+ * ```
313
+ *
314
+ * @example Full Application
315
+ * ```typescript
316
+ * import { createApp } from '@classytic/arc/factory';
317
+ * import { productResource } from './modules/product.resource.js';
318
+ *
319
+ * const app = await createApp({
320
+ * preset: 'production',
321
+ * auth: { jwt: { secret: process.env.JWT_SECRET } },
322
+ * plugins: async (fastify) => {
323
+ * await fastify.register(productResource.toPlugin());
324
+ * },
325
+ * });
326
+ * ```
327
+ */
328
+
329
+ declare const version = "1.0.0";
330
+
331
+ export { AnyRecord, BaseController, type BaseControllerOptions, CrudRepository, HookSystem, IController, IControllerResponse, IRequestContext, PaginatedResult, QueryOptions, RepositoryLike, RequestContext, ResourceConfig, RouteSchemaOptions, ServiceContext, assertValidConfig, formatValidationErrors, validateResourceConfig, version };