@classytic/arc 1.1.0 → 2.1.2
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 +247 -794
- package/bin/arc.js +91 -52
- package/dist/EventTransport-BD2U0BTc.d.mts +100 -0
- package/dist/EventTransport-BD2U0BTc.d.mts.map +1 -0
- package/dist/HookSystem-BsGV-j2l.mjs +405 -0
- package/dist/HookSystem-BsGV-j2l.mjs.map +1 -0
- package/dist/ResourceRegistry-DsN4KJjV.mjs +250 -0
- package/dist/ResourceRegistry-DsN4KJjV.mjs.map +1 -0
- package/dist/adapters/index.d.mts +5 -0
- package/dist/adapters/index.mjs +3 -0
- package/dist/audit/index.d.mts +82 -0
- package/dist/audit/index.d.mts.map +1 -0
- package/dist/audit/index.mjs +276 -0
- package/dist/audit/index.mjs.map +1 -0
- package/dist/audit/mongodb.d.mts +5 -0
- package/dist/audit/mongodb.mjs +3 -0
- package/dist/audited-C3T5DTUx.mjs +141 -0
- package/dist/audited-C3T5DTUx.mjs.map +1 -0
- package/dist/auth/index.d.mts +189 -0
- package/dist/auth/index.d.mts.map +1 -0
- package/dist/auth/index.mjs +1102 -0
- package/dist/auth/index.mjs.map +1 -0
- package/dist/auth/redis-session.d.mts +44 -0
- package/dist/auth/redis-session.d.mts.map +1 -0
- package/dist/auth/redis-session.mjs +76 -0
- package/dist/auth/redis-session.mjs.map +1 -0
- package/dist/betterAuthOpenApi-BrHKeSAx.mjs +250 -0
- package/dist/betterAuthOpenApi-BrHKeSAx.mjs.map +1 -0
- package/dist/cache/index.d.mts +146 -0
- package/dist/cache/index.d.mts.map +1 -0
- package/dist/cache/index.mjs +92 -0
- package/dist/cache/index.mjs.map +1 -0
- package/dist/caching-Bl28lYsR.mjs +94 -0
- package/dist/caching-Bl28lYsR.mjs.map +1 -0
- package/dist/chunk-C7Uep-_p.mjs +20 -0
- package/dist/circuitBreaker-DeY4FCjs.mjs +1097 -0
- package/dist/circuitBreaker-DeY4FCjs.mjs.map +1 -0
- package/dist/cli/commands/describe.d.mts +19 -0
- package/dist/cli/commands/describe.d.mts.map +1 -0
- package/dist/cli/commands/describe.mjs +239 -0
- package/dist/cli/commands/describe.mjs.map +1 -0
- package/dist/cli/commands/docs.d.mts +14 -0
- package/dist/cli/commands/docs.d.mts.map +1 -0
- package/dist/cli/commands/docs.mjs +53 -0
- package/dist/cli/commands/docs.mjs.map +1 -0
- package/dist/cli/commands/{generate.d.ts → generate.d.mts} +3 -1
- package/dist/cli/commands/generate.d.mts.map +1 -0
- package/dist/cli/commands/generate.mjs +358 -0
- package/dist/cli/commands/generate.mjs.map +1 -0
- package/dist/cli/commands/{init.d.ts → init.d.mts} +12 -8
- package/dist/cli/commands/init.d.mts.map +1 -0
- package/dist/cli/commands/{init.js → init.mjs} +807 -616
- package/dist/cli/commands/init.mjs.map +1 -0
- package/dist/cli/commands/introspect.d.mts +11 -0
- package/dist/cli/commands/introspect.d.mts.map +1 -0
- package/dist/cli/commands/introspect.mjs +76 -0
- package/dist/cli/commands/introspect.mjs.map +1 -0
- package/dist/cli/index.d.mts +17 -0
- package/dist/cli/index.d.mts.map +1 -0
- package/dist/cli/index.mjs +157 -0
- package/dist/cli/index.mjs.map +1 -0
- package/dist/constants-DdXFXQtN.mjs +85 -0
- package/dist/constants-DdXFXQtN.mjs.map +1 -0
- package/dist/core/index.d.mts +5 -0
- package/dist/core/index.mjs +4 -0
- package/dist/createApp-CUgNqegw.mjs +560 -0
- package/dist/createApp-CUgNqegw.mjs.map +1 -0
- package/dist/defineResource-k0_BDn8v.mjs +2197 -0
- package/dist/defineResource-k0_BDn8v.mjs.map +1 -0
- package/dist/discovery/index.d.mts +47 -0
- package/dist/discovery/index.d.mts.map +1 -0
- package/dist/discovery/index.mjs +110 -0
- package/dist/discovery/index.mjs.map +1 -0
- package/dist/docs/index.d.mts +163 -0
- package/dist/docs/index.d.mts.map +1 -0
- package/dist/docs/index.mjs +73 -0
- package/dist/docs/index.mjs.map +1 -0
- package/dist/elevation-BRy3yFWT.mjs +113 -0
- package/dist/elevation-BRy3yFWT.mjs.map +1 -0
- package/dist/elevation-B_2dRLVP.d.mts +88 -0
- package/dist/elevation-B_2dRLVP.d.mts.map +1 -0
- package/dist/errorHandler-BbcgBmIH.d.mts +73 -0
- package/dist/errorHandler-BbcgBmIH.d.mts.map +1 -0
- package/dist/errorHandler-C1okiriz.mjs +109 -0
- package/dist/errorHandler-C1okiriz.mjs.map +1 -0
- package/dist/errors-B9bZok84.mjs +212 -0
- package/dist/errors-B9bZok84.mjs.map +1 -0
- package/dist/errors-ChKiFz62.d.mts +125 -0
- package/dist/errors-ChKiFz62.d.mts.map +1 -0
- package/dist/eventPlugin-CTrLH3mt.d.mts +125 -0
- package/dist/eventPlugin-CTrLH3mt.d.mts.map +1 -0
- package/dist/eventPlugin-DGR_B2on.mjs +230 -0
- package/dist/eventPlugin-DGR_B2on.mjs.map +1 -0
- package/dist/events/index.d.mts +54 -0
- package/dist/events/index.d.mts.map +1 -0
- package/dist/events/index.mjs +52 -0
- package/dist/events/index.mjs.map +1 -0
- package/dist/events/transports/redis-stream-entry.d.mts +2 -0
- package/dist/events/transports/redis-stream-entry.mjs +178 -0
- package/dist/events/transports/redis-stream-entry.mjs.map +1 -0
- package/dist/events/transports/redis.d.mts +77 -0
- package/dist/events/transports/redis.d.mts.map +1 -0
- package/dist/events/transports/redis.mjs +125 -0
- package/dist/events/transports/redis.mjs.map +1 -0
- package/dist/externalPaths-DlINfKbP.d.mts +51 -0
- package/dist/externalPaths-DlINfKbP.d.mts.map +1 -0
- package/dist/factory/index.d.mts +64 -0
- package/dist/factory/index.d.mts.map +1 -0
- package/dist/factory/index.mjs +3 -0
- package/dist/fastifyAdapter-BkrGrlFi.d.mts +217 -0
- package/dist/fastifyAdapter-BkrGrlFi.d.mts.map +1 -0
- package/dist/fields-DyaDVX4J.d.mts +110 -0
- package/dist/fields-DyaDVX4J.d.mts.map +1 -0
- package/dist/fields-iagOozy0.mjs +115 -0
- package/dist/fields-iagOozy0.mjs.map +1 -0
- package/dist/hooks/index.d.mts +4 -0
- package/dist/hooks/index.mjs +3 -0
- package/dist/idempotency/index.d.mts +97 -0
- package/dist/idempotency/index.d.mts.map +1 -0
- package/dist/idempotency/index.mjs +320 -0
- package/dist/idempotency/index.mjs.map +1 -0
- package/dist/idempotency/mongodb.d.mts +2 -0
- package/dist/idempotency/mongodb.mjs +115 -0
- package/dist/idempotency/mongodb.mjs.map +1 -0
- package/dist/idempotency/redis.d.mts +2 -0
- package/dist/idempotency/redis.mjs +104 -0
- package/dist/idempotency/redis.mjs.map +1 -0
- package/dist/index.d.mts +261 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +105 -0
- package/dist/index.mjs.map +1 -0
- package/dist/integrations/event-gateway.d.mts +47 -0
- package/dist/integrations/event-gateway.d.mts.map +1 -0
- package/dist/integrations/event-gateway.mjs +44 -0
- package/dist/integrations/event-gateway.mjs.map +1 -0
- package/dist/integrations/index.d.mts +5 -0
- package/dist/integrations/index.mjs +1 -0
- package/dist/integrations/jobs.d.mts +104 -0
- package/dist/integrations/jobs.d.mts.map +1 -0
- package/dist/integrations/jobs.mjs +124 -0
- package/dist/integrations/jobs.mjs.map +1 -0
- package/dist/integrations/streamline.d.mts +61 -0
- package/dist/integrations/streamline.d.mts.map +1 -0
- package/dist/integrations/streamline.mjs +126 -0
- package/dist/integrations/streamline.mjs.map +1 -0
- package/dist/integrations/websocket.d.mts +83 -0
- package/dist/integrations/websocket.d.mts.map +1 -0
- package/dist/integrations/websocket.mjs +289 -0
- package/dist/integrations/websocket.mjs.map +1 -0
- package/dist/interface-B01JvPVc.d.mts +78 -0
- package/dist/interface-B01JvPVc.d.mts.map +1 -0
- package/dist/interface-CZe8IkMf.d.mts +55 -0
- package/dist/interface-CZe8IkMf.d.mts.map +1 -0
- package/dist/interface-Ch8HU9uM.d.mts +1098 -0
- package/dist/interface-Ch8HU9uM.d.mts.map +1 -0
- package/dist/introspectionPlugin-rFdO8ZUa.mjs +54 -0
- package/dist/introspectionPlugin-rFdO8ZUa.mjs.map +1 -0
- package/dist/keys-BqNejWup.mjs +43 -0
- package/dist/keys-BqNejWup.mjs.map +1 -0
- package/dist/logger-Df2O2WsW.mjs +79 -0
- package/dist/logger-Df2O2WsW.mjs.map +1 -0
- package/dist/memory-cQgelFOj.mjs +144 -0
- package/dist/memory-cQgelFOj.mjs.map +1 -0
- package/dist/migrations/index.d.mts +157 -0
- package/dist/migrations/index.d.mts.map +1 -0
- package/dist/migrations/index.mjs +261 -0
- package/dist/migrations/index.mjs.map +1 -0
- package/dist/mongodb-BfJVlUJH.mjs +94 -0
- package/dist/mongodb-BfJVlUJH.mjs.map +1 -0
- package/dist/mongodb-CGzRbfAK.d.mts +119 -0
- package/dist/mongodb-CGzRbfAK.d.mts.map +1 -0
- package/dist/mongodb-JN-9JA7K.d.mts +72 -0
- package/dist/mongodb-JN-9JA7K.d.mts.map +1 -0
- package/dist/openapi-G3Cw7XuM.mjs +524 -0
- package/dist/openapi-G3Cw7XuM.mjs.map +1 -0
- package/dist/org/index.d.mts +69 -0
- package/dist/org/index.d.mts.map +1 -0
- package/dist/org/index.mjs +514 -0
- package/dist/org/index.mjs.map +1 -0
- package/dist/org/types.d.mts +83 -0
- package/dist/org/types.d.mts.map +1 -0
- package/dist/org/types.mjs +1 -0
- package/dist/permissions/index.d.mts +279 -0
- package/dist/permissions/index.d.mts.map +1 -0
- package/dist/permissions/index.mjs +579 -0
- package/dist/permissions/index.mjs.map +1 -0
- package/dist/plugins/index.d.mts +173 -0
- package/dist/plugins/index.d.mts.map +1 -0
- package/dist/plugins/index.mjs +523 -0
- package/dist/plugins/index.mjs.map +1 -0
- package/dist/plugins/response-cache.d.mts +88 -0
- package/dist/plugins/response-cache.d.mts.map +1 -0
- package/dist/plugins/response-cache.mjs +284 -0
- package/dist/plugins/response-cache.mjs.map +1 -0
- package/dist/plugins/tracing-entry.d.mts +2 -0
- package/dist/plugins/tracing-entry.mjs +186 -0
- package/dist/plugins/tracing-entry.mjs.map +1 -0
- package/dist/pluralize-CEweyOEm.mjs +87 -0
- package/dist/pluralize-CEweyOEm.mjs.map +1 -0
- package/dist/policies/{index.d.ts → index.d.mts} +204 -169
- package/dist/policies/index.d.mts.map +1 -0
- package/dist/policies/index.mjs +322 -0
- package/dist/policies/index.mjs.map +1 -0
- package/dist/presets/{index.d.ts → index.d.mts} +63 -131
- package/dist/presets/index.d.mts.map +1 -0
- package/dist/presets/index.mjs +144 -0
- package/dist/presets/index.mjs.map +1 -0
- package/dist/presets/multiTenant.d.mts +25 -0
- package/dist/presets/multiTenant.d.mts.map +1 -0
- package/dist/presets/multiTenant.mjs +114 -0
- package/dist/presets/multiTenant.mjs.map +1 -0
- package/dist/presets-BITljm96.mjs +120 -0
- package/dist/presets-BITljm96.mjs.map +1 -0
- package/dist/presets-DzSMwlKj.d.mts +58 -0
- package/dist/presets-DzSMwlKj.d.mts.map +1 -0
- package/dist/prisma-DJbMt3yf.mjs +628 -0
- package/dist/prisma-DJbMt3yf.mjs.map +1 -0
- package/dist/prisma-Dg9GoVdj.d.mts +275 -0
- package/dist/prisma-Dg9GoVdj.d.mts.map +1 -0
- package/dist/queryCachePlugin-7THaI5mt.d.mts +72 -0
- package/dist/queryCachePlugin-7THaI5mt.d.mts.map +1 -0
- package/dist/queryCachePlugin-DMBnp2Q0.mjs +139 -0
- package/dist/queryCachePlugin-DMBnp2Q0.mjs.map +1 -0
- package/dist/redis-D-JAeLtm.d.mts +50 -0
- package/dist/redis-D-JAeLtm.d.mts.map +1 -0
- package/dist/redis-stream-Bdh_vUU8.d.mts +104 -0
- package/dist/redis-stream-Bdh_vUU8.d.mts.map +1 -0
- package/dist/registry/index.d.mts +12 -0
- package/dist/registry/index.d.mts.map +1 -0
- package/dist/registry/index.mjs +4 -0
- package/dist/requestContext-QQD6ROJc.mjs +56 -0
- package/dist/requestContext-QQD6ROJc.mjs.map +1 -0
- package/dist/schemaConverter-BwrmWroW.mjs +99 -0
- package/dist/schemaConverter-BwrmWroW.mjs.map +1 -0
- package/dist/schemas/index.d.mts +64 -0
- package/dist/schemas/index.d.mts.map +1 -0
- package/dist/schemas/index.mjs +83 -0
- package/dist/schemas/index.mjs.map +1 -0
- package/dist/scope/index.d.mts +22 -0
- package/dist/scope/index.d.mts.map +1 -0
- package/dist/scope/index.mjs +66 -0
- package/dist/scope/index.mjs.map +1 -0
- package/dist/sessionManager-jPKLbHE0.d.mts +187 -0
- package/dist/sessionManager-jPKLbHE0.d.mts.map +1 -0
- package/dist/sse-B3c3_yZp.mjs +124 -0
- package/dist/sse-B3c3_yZp.mjs.map +1 -0
- package/dist/testing/index.d.mts +908 -0
- package/dist/testing/index.d.mts.map +1 -0
- package/dist/testing/index.mjs +1977 -0
- package/dist/testing/index.mjs.map +1 -0
- package/dist/tracing-Cc7vVQPp.d.mts +71 -0
- package/dist/tracing-Cc7vVQPp.d.mts.map +1 -0
- package/dist/typeGuards-DhMNLuvU.mjs +10 -0
- package/dist/typeGuards-DhMNLuvU.mjs.map +1 -0
- package/dist/types/index.d.mts +947 -0
- package/dist/types/index.d.mts.map +1 -0
- package/dist/types/index.mjs +15 -0
- package/dist/types/index.mjs.map +1 -0
- package/dist/types-Beqn1Un7.mjs +39 -0
- package/dist/types-Beqn1Un7.mjs.map +1 -0
- package/dist/types-CIgB7UUl.d.mts +446 -0
- package/dist/types-CIgB7UUl.d.mts.map +1 -0
- package/dist/types-aYB4V7uN.d.mts +87 -0
- package/dist/types-aYB4V7uN.d.mts.map +1 -0
- package/dist/utils/index.d.mts +748 -0
- package/dist/utils/index.d.mts.map +1 -0
- package/dist/utils/index.mjs +6 -0
- package/package.json +194 -68
- package/dist/BaseController-DVAiHxEQ.d.ts +0 -233
- package/dist/adapters/index.d.ts +0 -237
- package/dist/adapters/index.js +0 -668
- package/dist/arcCorePlugin-CsShQdyP.d.ts +0 -273
- package/dist/audit/index.d.ts +0 -195
- package/dist/audit/index.js +0 -319
- package/dist/auth/index.d.ts +0 -47
- package/dist/auth/index.js +0 -174
- package/dist/cli/commands/docs.d.ts +0 -11
- package/dist/cli/commands/docs.js +0 -474
- package/dist/cli/commands/generate.js +0 -334
- package/dist/cli/commands/introspect.d.ts +0 -8
- package/dist/cli/commands/introspect.js +0 -338
- package/dist/cli/index.d.ts +0 -4
- package/dist/cli/index.js +0 -3269
- package/dist/core/index.d.ts +0 -220
- package/dist/core/index.js +0 -2786
- package/dist/createApp-Ce9wl8W9.d.ts +0 -77
- package/dist/docs/index.d.ts +0 -166
- package/dist/docs/index.js +0 -658
- package/dist/errors-8WIxGS_6.d.ts +0 -122
- package/dist/events/index.d.ts +0 -117
- package/dist/events/index.js +0 -89
- package/dist/factory/index.d.ts +0 -38
- package/dist/factory/index.js +0 -1652
- package/dist/hooks/index.d.ts +0 -4
- package/dist/hooks/index.js +0 -199
- package/dist/idempotency/index.d.ts +0 -323
- package/dist/idempotency/index.js +0 -500
- package/dist/index-B4t03KQ0.d.ts +0 -1366
- package/dist/index.d.ts +0 -135
- package/dist/index.js +0 -4756
- package/dist/migrations/index.d.ts +0 -185
- package/dist/migrations/index.js +0 -274
- package/dist/org/index.d.ts +0 -129
- package/dist/org/index.js +0 -220
- package/dist/permissions/index.d.ts +0 -144
- package/dist/permissions/index.js +0 -103
- package/dist/plugins/index.d.ts +0 -46
- package/dist/plugins/index.js +0 -1069
- package/dist/policies/index.js +0 -196
- package/dist/presets/index.js +0 -384
- package/dist/presets/multiTenant.d.ts +0 -39
- package/dist/presets/multiTenant.js +0 -112
- package/dist/registry/index.d.ts +0 -16
- package/dist/registry/index.js +0 -253
- package/dist/testing/index.d.ts +0 -618
- package/dist/testing/index.js +0 -48020
- package/dist/types/index.d.ts +0 -4
- package/dist/types/index.js +0 -8
- package/dist/types-B99TBmFV.d.ts +0 -76
- package/dist/types-BvckRbs2.d.ts +0 -143
- package/dist/utils/index.d.ts +0 -679
- package/dist/utils/index.js +0 -931
package/dist/index-B4t03KQ0.d.ts
DELETED
|
@@ -1,1366 +0,0 @@
|
|
|
1
|
-
import { ClientSession, Model, Document, Types } from 'mongoose';
|
|
2
|
-
import { FastifyPluginAsync, FastifyRequest, FastifyReply, RouteHandlerMethod, FastifyInstance } from 'fastify';
|
|
3
|
-
import { U as UserBase, P as PermissionCheck } from './types-B99TBmFV.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Repository Interface - Database-Agnostic CRUD Operations
|
|
7
|
-
*
|
|
8
|
-
* This is the standard interface that all repositories must implement.
|
|
9
|
-
* MongoKit Repository already implements this interface.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```typescript
|
|
13
|
-
* import type { CrudRepository } from '@classytic/arc';
|
|
14
|
-
*
|
|
15
|
-
* // Your repository automatically satisfies this interface
|
|
16
|
-
* const userRepo: CrudRepository<UserDocument> = new Repository(UserModel);
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Query options for read operations
|
|
22
|
-
*/
|
|
23
|
-
interface QueryOptions {
|
|
24
|
-
/** MongoDB session for transactions */
|
|
25
|
-
session?: ClientSession;
|
|
26
|
-
/** Field selection - include or exclude fields */
|
|
27
|
-
select?: string | string[] | Record<string, 0 | 1>;
|
|
28
|
-
/** Relations to populate - string, array, or Mongoose populate options */
|
|
29
|
-
populate?: string | string[] | Record<string, unknown>;
|
|
30
|
-
/** Return plain JS objects instead of Mongoose documents */
|
|
31
|
-
lean?: boolean;
|
|
32
|
-
/** Allow additional adapter-specific options */
|
|
33
|
-
[key: string]: unknown;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Pagination parameters for list operations
|
|
37
|
-
*/
|
|
38
|
-
interface PaginationParams<TDoc = unknown> {
|
|
39
|
-
/** Filter criteria */
|
|
40
|
-
filters?: Partial<TDoc> & Record<string, unknown>;
|
|
41
|
-
/** Sort specification - string ("-createdAt") or object ({ createdAt: -1 }) */
|
|
42
|
-
sort?: string | Record<string, 1 | -1>;
|
|
43
|
-
/** Page number (1-indexed) */
|
|
44
|
-
page?: number;
|
|
45
|
-
/** Items per page */
|
|
46
|
-
limit?: number;
|
|
47
|
-
/** Allow additional options (select, populate, etc.) */
|
|
48
|
-
[key: string]: unknown;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Paginated result from list operations
|
|
52
|
-
*/
|
|
53
|
-
interface PaginatedResult<TDoc> {
|
|
54
|
-
/** Documents for current page */
|
|
55
|
-
docs: TDoc[];
|
|
56
|
-
/** Current page number */
|
|
57
|
-
page: number;
|
|
58
|
-
/** Items per page */
|
|
59
|
-
limit: number;
|
|
60
|
-
/** Total document count */
|
|
61
|
-
total: number;
|
|
62
|
-
/** Total page count */
|
|
63
|
-
pages: number;
|
|
64
|
-
/** Has next page */
|
|
65
|
-
hasNext: boolean;
|
|
66
|
-
/** Has previous page */
|
|
67
|
-
hasPrev: boolean;
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Standard CRUD Repository Interface
|
|
71
|
-
*
|
|
72
|
-
* Defines the contract for data access operations.
|
|
73
|
-
* All database adapters (MongoKit, Prisma, etc.) implement this interface.
|
|
74
|
-
*
|
|
75
|
-
* @typeParam TDoc - The document/entity type
|
|
76
|
-
*/
|
|
77
|
-
interface CrudRepository<TDoc> {
|
|
78
|
-
/**
|
|
79
|
-
* Get paginated list of documents
|
|
80
|
-
*/
|
|
81
|
-
getAll(params?: PaginationParams<TDoc>, options?: QueryOptions): Promise<PaginatedResult<TDoc>>;
|
|
82
|
-
/**
|
|
83
|
-
* Get single document by ID
|
|
84
|
-
*/
|
|
85
|
-
getById(id: string, options?: QueryOptions): Promise<TDoc | null>;
|
|
86
|
-
/**
|
|
87
|
-
* Create new document
|
|
88
|
-
*/
|
|
89
|
-
create(data: Partial<TDoc>, options?: {
|
|
90
|
-
session?: ClientSession;
|
|
91
|
-
[key: string]: unknown;
|
|
92
|
-
}): Promise<TDoc>;
|
|
93
|
-
/**
|
|
94
|
-
* Update document by ID
|
|
95
|
-
*/
|
|
96
|
-
update(id: string, data: Partial<TDoc>, options?: QueryOptions): Promise<TDoc | null>;
|
|
97
|
-
/**
|
|
98
|
-
* Delete document by ID
|
|
99
|
-
*/
|
|
100
|
-
delete(id: string, options?: {
|
|
101
|
-
session?: ClientSession;
|
|
102
|
-
[key: string]: unknown;
|
|
103
|
-
}): Promise<{
|
|
104
|
-
success: boolean;
|
|
105
|
-
message: string;
|
|
106
|
-
}>;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Extract document type from a repository
|
|
110
|
-
*
|
|
111
|
-
* @example
|
|
112
|
-
* ```typescript
|
|
113
|
-
* type UserDoc = InferDoc<typeof userRepository>;
|
|
114
|
-
* // UserDoc is now the document type of userRepository
|
|
115
|
-
* ```
|
|
116
|
-
*/
|
|
117
|
-
type InferDoc<R> = R extends CrudRepository<infer T> ? T : never;
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Define a resource with database adapter
|
|
121
|
-
*
|
|
122
|
-
* This is the MAIN entry point for creating Arc resources.
|
|
123
|
-
* The adapter provides both repository and schema metadata.
|
|
124
|
-
*/
|
|
125
|
-
declare function defineResource<TDoc = AnyRecord>(config: ResourceConfig<TDoc>): ResourceDefinition<TDoc>;
|
|
126
|
-
interface ResolvedResourceConfig<TDoc = AnyRecord> extends ResourceConfig<TDoc> {
|
|
127
|
-
_appliedPresets?: string[];
|
|
128
|
-
_controllerOptions?: {
|
|
129
|
-
slugField?: string;
|
|
130
|
-
parentField?: string;
|
|
131
|
-
[key: string]: unknown;
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
declare class ResourceDefinition<TDoc = AnyRecord> {
|
|
135
|
-
readonly name: string;
|
|
136
|
-
readonly displayName: string;
|
|
137
|
-
readonly tag: string;
|
|
138
|
-
readonly prefix: string;
|
|
139
|
-
readonly adapter?: DataAdapter<TDoc>;
|
|
140
|
-
readonly controller?: IController<TDoc>;
|
|
141
|
-
readonly schemaOptions: RouteSchemaOptions;
|
|
142
|
-
readonly customSchemas: CrudSchemas;
|
|
143
|
-
readonly permissions: ResourcePermissions;
|
|
144
|
-
readonly additionalRoutes: AdditionalRoute[];
|
|
145
|
-
readonly middlewares: MiddlewareConfig;
|
|
146
|
-
readonly disableDefaultRoutes: boolean;
|
|
147
|
-
readonly disabledRoutes: CrudRouteKey[];
|
|
148
|
-
readonly organizationScoped: boolean;
|
|
149
|
-
readonly events: Record<string, EventDefinition>;
|
|
150
|
-
readonly _appliedPresets: string[];
|
|
151
|
-
constructor(config: ResolvedResourceConfig<TDoc>);
|
|
152
|
-
/** Get repository from adapter (if available) */
|
|
153
|
-
get repository(): RepositoryLike | CrudRepository<TDoc> | undefined;
|
|
154
|
-
/** Get model from adapter (if available) */
|
|
155
|
-
get model(): Model<Document> | unknown | undefined;
|
|
156
|
-
_validateControllerMethods(): void;
|
|
157
|
-
toPlugin(): FastifyPluginAsync;
|
|
158
|
-
/**
|
|
159
|
-
* Get event definitions for registry
|
|
160
|
-
*/
|
|
161
|
-
getEvents(): Array<{
|
|
162
|
-
name: string;
|
|
163
|
-
module: string;
|
|
164
|
-
schema?: AnyRecord;
|
|
165
|
-
description?: string;
|
|
166
|
-
}>;
|
|
167
|
-
/**
|
|
168
|
-
* Get resource metadata
|
|
169
|
-
*/
|
|
170
|
-
getMetadata(): ResourceMetadata;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Resource Registry
|
|
175
|
-
*
|
|
176
|
-
* Singleton that tracks all registered resources for introspection.
|
|
177
|
-
*/
|
|
178
|
-
|
|
179
|
-
interface RegisterOptions {
|
|
180
|
-
module?: string;
|
|
181
|
-
/** Pre-generated OpenAPI schemas */
|
|
182
|
-
openApiSchemas?: OpenApiSchemas;
|
|
183
|
-
}
|
|
184
|
-
declare class ResourceRegistry {
|
|
185
|
-
private _resources;
|
|
186
|
-
private _frozen;
|
|
187
|
-
constructor();
|
|
188
|
-
/**
|
|
189
|
-
* Register a resource
|
|
190
|
-
*/
|
|
191
|
-
register(resource: ResourceDefinition<unknown>, options?: RegisterOptions): this;
|
|
192
|
-
/**
|
|
193
|
-
* Get resource by name
|
|
194
|
-
*/
|
|
195
|
-
get(name: string): RegistryEntry | undefined;
|
|
196
|
-
/**
|
|
197
|
-
* Get all resources
|
|
198
|
-
*/
|
|
199
|
-
getAll(): RegistryEntry[];
|
|
200
|
-
/**
|
|
201
|
-
* Get resources by module
|
|
202
|
-
*/
|
|
203
|
-
getByModule(moduleName: string): RegistryEntry[];
|
|
204
|
-
/**
|
|
205
|
-
* Get resources by preset
|
|
206
|
-
*/
|
|
207
|
-
getByPreset(presetName: string): RegistryEntry[];
|
|
208
|
-
/**
|
|
209
|
-
* Check if resource exists
|
|
210
|
-
*/
|
|
211
|
-
has(name: string): boolean;
|
|
212
|
-
/**
|
|
213
|
-
* Get registry statistics
|
|
214
|
-
*/
|
|
215
|
-
getStats(): RegistryStats;
|
|
216
|
-
/**
|
|
217
|
-
* Get full introspection data
|
|
218
|
-
*/
|
|
219
|
-
getIntrospection(): IntrospectionData;
|
|
220
|
-
/**
|
|
221
|
-
* Freeze registry (prevent further registrations)
|
|
222
|
-
*/
|
|
223
|
-
freeze(): void;
|
|
224
|
-
/**
|
|
225
|
-
* Check if frozen
|
|
226
|
-
*/
|
|
227
|
-
isFrozen(): boolean;
|
|
228
|
-
/**
|
|
229
|
-
* Unfreeze registry (for testing)
|
|
230
|
-
*/
|
|
231
|
-
_unfreeze(): void;
|
|
232
|
-
/**
|
|
233
|
-
* Clear all resources (for testing)
|
|
234
|
-
*/
|
|
235
|
-
_clear(): void;
|
|
236
|
-
/**
|
|
237
|
-
* Group by key
|
|
238
|
-
*/
|
|
239
|
-
private _groupBy;
|
|
240
|
-
}
|
|
241
|
-
declare const resourceRegistry: ResourceRegistry;
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Hook System
|
|
245
|
-
*
|
|
246
|
-
* Lifecycle hooks for resource operations.
|
|
247
|
-
* Allows intercepting and modifying data at various points.
|
|
248
|
-
*/
|
|
249
|
-
|
|
250
|
-
type HookPhase = 'before' | 'after';
|
|
251
|
-
type HookOperation = 'create' | 'update' | 'delete' | 'read' | 'list';
|
|
252
|
-
interface HookContext<T = AnyRecord> {
|
|
253
|
-
resource: string;
|
|
254
|
-
operation: HookOperation;
|
|
255
|
-
phase: HookPhase;
|
|
256
|
-
data?: T;
|
|
257
|
-
result?: T | T[];
|
|
258
|
-
user?: UserBase;
|
|
259
|
-
context?: RequestContext;
|
|
260
|
-
meta?: AnyRecord;
|
|
261
|
-
}
|
|
262
|
-
type HookHandler<T = AnyRecord> = (ctx: HookContext<T>) => void | Promise<void> | T | Promise<T>;
|
|
263
|
-
interface HookRegistration {
|
|
264
|
-
resource: string;
|
|
265
|
-
operation: HookOperation;
|
|
266
|
-
phase: HookPhase;
|
|
267
|
-
handler: HookHandler;
|
|
268
|
-
priority: number;
|
|
269
|
-
}
|
|
270
|
-
interface HookSystemOptions {
|
|
271
|
-
/** Custom logger for error reporting. Defaults to console.error */
|
|
272
|
-
logger?: {
|
|
273
|
-
error: (message: string, ...args: unknown[]) => void;
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
declare class HookSystem {
|
|
277
|
-
private hooks;
|
|
278
|
-
private logger;
|
|
279
|
-
constructor(options?: HookSystemOptions);
|
|
280
|
-
/**
|
|
281
|
-
* Generate hook key
|
|
282
|
-
*/
|
|
283
|
-
private getKey;
|
|
284
|
-
/**
|
|
285
|
-
* Register a hook
|
|
286
|
-
* Supports both object parameter and positional arguments
|
|
287
|
-
*/
|
|
288
|
-
register<T = AnyRecord>(resourceOrOptions: string | {
|
|
289
|
-
resource: string;
|
|
290
|
-
operation: HookOperation;
|
|
291
|
-
phase: HookPhase;
|
|
292
|
-
handler: HookHandler<T>;
|
|
293
|
-
priority?: number;
|
|
294
|
-
}, operation?: HookOperation, phase?: HookPhase, handler?: HookHandler<T>, priority?: number): () => void;
|
|
295
|
-
/**
|
|
296
|
-
* Register before hook
|
|
297
|
-
*/
|
|
298
|
-
before<T = AnyRecord>(resource: string, operation: HookOperation, handler: HookHandler<T>, priority?: number): () => void;
|
|
299
|
-
/**
|
|
300
|
-
* Register after hook
|
|
301
|
-
*/
|
|
302
|
-
after<T = AnyRecord>(resource: string, operation: HookOperation, handler: HookHandler<T>, priority?: number): () => void;
|
|
303
|
-
/**
|
|
304
|
-
* Execute hooks for a given context
|
|
305
|
-
*/
|
|
306
|
-
execute<T = AnyRecord>(ctx: HookContext<T>): Promise<T | undefined>;
|
|
307
|
-
/**
|
|
308
|
-
* Execute before hooks
|
|
309
|
-
*/
|
|
310
|
-
executeBefore<T = AnyRecord>(resource: string, operation: HookOperation, data: T, options?: {
|
|
311
|
-
user?: UserBase;
|
|
312
|
-
context?: RequestContext;
|
|
313
|
-
meta?: AnyRecord;
|
|
314
|
-
}): Promise<T>;
|
|
315
|
-
/**
|
|
316
|
-
* Execute after hooks
|
|
317
|
-
* Errors in after hooks are logged but don't fail the request
|
|
318
|
-
*/
|
|
319
|
-
executeAfter<T = AnyRecord>(resource: string, operation: HookOperation, result: T | T[], options?: {
|
|
320
|
-
user?: UserBase;
|
|
321
|
-
context?: RequestContext;
|
|
322
|
-
meta?: AnyRecord;
|
|
323
|
-
}): Promise<void>;
|
|
324
|
-
/**
|
|
325
|
-
* Get all registered hooks
|
|
326
|
-
*/
|
|
327
|
-
getAll(): HookRegistration[];
|
|
328
|
-
/**
|
|
329
|
-
* Get hooks for a specific resource
|
|
330
|
-
*/
|
|
331
|
-
getForResource(resource: string): HookRegistration[];
|
|
332
|
-
/**
|
|
333
|
-
* Clear all hooks
|
|
334
|
-
*/
|
|
335
|
-
clear(): void;
|
|
336
|
-
/**
|
|
337
|
-
* Clear hooks for a specific resource
|
|
338
|
-
*/
|
|
339
|
-
clearResource(resource: string): void;
|
|
340
|
-
}
|
|
341
|
-
/**
|
|
342
|
-
* Create a new isolated HookSystem instance
|
|
343
|
-
*
|
|
344
|
-
* Use this for:
|
|
345
|
-
* - Test isolation (parallel test suites)
|
|
346
|
-
* - Multiple app instances with independent hooks
|
|
347
|
-
*
|
|
348
|
-
* @example
|
|
349
|
-
* const hooks = createHookSystem();
|
|
350
|
-
* await app.register(arcCorePlugin, { hookSystem: hooks });
|
|
351
|
-
*
|
|
352
|
-
* @example With custom logger
|
|
353
|
-
* const hooks = createHookSystem({ logger: fastify.log });
|
|
354
|
-
*/
|
|
355
|
-
declare function createHookSystem(options?: HookSystemOptions): HookSystem;
|
|
356
|
-
declare const hookSystem: HookSystem;
|
|
357
|
-
/**
|
|
358
|
-
* Register a before create hook
|
|
359
|
-
*/
|
|
360
|
-
declare function beforeCreate<T = AnyRecord>(resource: string, handler: HookHandler<T>, priority?: number): () => void;
|
|
361
|
-
/**
|
|
362
|
-
* Register an after create hook
|
|
363
|
-
*/
|
|
364
|
-
declare function afterCreate<T = AnyRecord>(resource: string, handler: HookHandler<T>, priority?: number): () => void;
|
|
365
|
-
/**
|
|
366
|
-
* Register a before update hook
|
|
367
|
-
*/
|
|
368
|
-
declare function beforeUpdate<T = AnyRecord>(resource: string, handler: HookHandler<T>, priority?: number): () => void;
|
|
369
|
-
/**
|
|
370
|
-
* Register an after update hook
|
|
371
|
-
*/
|
|
372
|
-
declare function afterUpdate<T = AnyRecord>(resource: string, handler: HookHandler<T>, priority?: number): () => void;
|
|
373
|
-
/**
|
|
374
|
-
* Register a before delete hook
|
|
375
|
-
*/
|
|
376
|
-
declare function beforeDelete<T = AnyRecord>(resource: string, handler: HookHandler<T>, priority?: number): () => void;
|
|
377
|
-
/**
|
|
378
|
-
* Register an after delete hook
|
|
379
|
-
*/
|
|
380
|
-
declare function afterDelete<T = AnyRecord>(resource: string, handler: HookHandler<T>, priority?: number): () => void;
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Handler Types - Controller and Route Handler Definitions
|
|
384
|
-
*
|
|
385
|
-
* Two handler patterns supported:
|
|
386
|
-
* 1. ControllerHandler - Arc's standard pattern (receives context object)
|
|
387
|
-
* 2. FastifyHandler - Fastify native pattern (receives request, reply)
|
|
388
|
-
*
|
|
389
|
-
* Use `wrapHandler: true` for ControllerHandler, `wrapHandler: false` for FastifyHandler.
|
|
390
|
-
*/
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* Request context passed to controller handlers
|
|
394
|
-
*/
|
|
395
|
-
interface IRequestContext {
|
|
396
|
-
/** Route parameters (e.g., { id: '123' }) */
|
|
397
|
-
params: Record<string, string>;
|
|
398
|
-
/** Query string parameters */
|
|
399
|
-
query: Record<string, unknown>;
|
|
400
|
-
/** Request body */
|
|
401
|
-
body: unknown;
|
|
402
|
-
/** Authenticated user or null */
|
|
403
|
-
user: UserBase | null;
|
|
404
|
-
/** Request headers */
|
|
405
|
-
headers: Record<string, string | undefined>;
|
|
406
|
-
/** Organization ID (for multi-tenant apps) */
|
|
407
|
-
organizationId?: string;
|
|
408
|
-
/** Additional metadata and custom fields */
|
|
409
|
-
metadata?: Record<string, unknown>;
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* Standard response from controller handlers
|
|
413
|
-
*/
|
|
414
|
-
interface IControllerResponse<T = unknown> {
|
|
415
|
-
/** Operation success status */
|
|
416
|
-
success: boolean;
|
|
417
|
-
/** Response data */
|
|
418
|
-
data?: T;
|
|
419
|
-
/** Error message (when success is false) */
|
|
420
|
-
error?: string;
|
|
421
|
-
/** HTTP status code (default: 200 for success, 400 for error) */
|
|
422
|
-
status?: number;
|
|
423
|
-
/** Additional metadata */
|
|
424
|
-
meta?: Record<string, unknown>;
|
|
425
|
-
/** Error details (for debugging) */
|
|
426
|
-
details?: Record<string, unknown>;
|
|
427
|
-
}
|
|
428
|
-
/**
|
|
429
|
-
* Controller handler - Arc's standard pattern
|
|
430
|
-
*
|
|
431
|
-
* Receives a request context object, returns IControllerResponse.
|
|
432
|
-
* Use with `wrapHandler: true` in additionalRoutes.
|
|
433
|
-
*
|
|
434
|
-
* @example
|
|
435
|
-
* ```typescript
|
|
436
|
-
* const createProduct: ControllerHandler<Product> = async (req) => {
|
|
437
|
-
* const product = await productRepo.create(req.body);
|
|
438
|
-
* return { success: true, data: product, status: 201 };
|
|
439
|
-
* };
|
|
440
|
-
*
|
|
441
|
-
* additionalRoutes: [{
|
|
442
|
-
* method: 'POST',
|
|
443
|
-
* path: '/products',
|
|
444
|
-
* handler: createProduct,
|
|
445
|
-
* permissions: requireAuth(),
|
|
446
|
-
* wrapHandler: true, // Arc wraps this into Fastify handler
|
|
447
|
-
* }]
|
|
448
|
-
* ```
|
|
449
|
-
*/
|
|
450
|
-
type ControllerHandler<T = unknown> = (req: IRequestContext) => Promise<IControllerResponse<T>>;
|
|
451
|
-
/**
|
|
452
|
-
* Fastify native handler
|
|
453
|
-
*
|
|
454
|
-
* Standard Fastify request/reply pattern.
|
|
455
|
-
* Use with `wrapHandler: false` in additionalRoutes.
|
|
456
|
-
*
|
|
457
|
-
* @example
|
|
458
|
-
* ```typescript
|
|
459
|
-
* const downloadFile: FastifyHandler = async (request, reply) => {
|
|
460
|
-
* const file = await getFile(request.params.id);
|
|
461
|
-
* reply.header('Content-Type', file.mimeType);
|
|
462
|
-
* return reply.send(file.buffer);
|
|
463
|
-
* };
|
|
464
|
-
*
|
|
465
|
-
* additionalRoutes: [{
|
|
466
|
-
* method: 'GET',
|
|
467
|
-
* path: '/files/:id/download',
|
|
468
|
-
* handler: downloadFile,
|
|
469
|
-
* permissions: requireAuth(),
|
|
470
|
-
* wrapHandler: false, // Use as-is, no wrapping
|
|
471
|
-
* }]
|
|
472
|
-
* ```
|
|
473
|
-
*/
|
|
474
|
-
type FastifyHandler = (request: FastifyRequest, reply: FastifyReply) => Promise<void> | void;
|
|
475
|
-
/**
|
|
476
|
-
* Union type for route handlers
|
|
477
|
-
*/
|
|
478
|
-
type RouteHandler = ControllerHandler | FastifyHandler;
|
|
479
|
-
/**
|
|
480
|
-
* Controller interface for CRUD operations (strict)
|
|
481
|
-
*/
|
|
482
|
-
interface IController<TDoc = unknown> {
|
|
483
|
-
list(req: IRequestContext): Promise<IControllerResponse<{
|
|
484
|
-
docs: TDoc[];
|
|
485
|
-
total: number;
|
|
486
|
-
}>>;
|
|
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
|
-
message: string;
|
|
492
|
-
}>>;
|
|
493
|
-
}
|
|
494
|
-
/**
|
|
495
|
-
* Flexible controller interface - accepts controllers with any handler style
|
|
496
|
-
* Use this when your controller uses Fastify native handlers
|
|
497
|
-
*/
|
|
498
|
-
interface ControllerLike {
|
|
499
|
-
list?: unknown;
|
|
500
|
-
get?: unknown;
|
|
501
|
-
create?: unknown;
|
|
502
|
-
update?: unknown;
|
|
503
|
-
delete?: unknown;
|
|
504
|
-
[key: string]: unknown;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
type AnyRecord = Record<string, unknown>;
|
|
508
|
-
type ObjectId = Types.ObjectId | string;
|
|
509
|
-
/**
|
|
510
|
-
* Flexible user type that accepts any object with id/ID properties.
|
|
511
|
-
* Use this instead of `any` when dealing with user objects.
|
|
512
|
-
* Re-exports UserBase from permissions module for convenience.
|
|
513
|
-
* The actual user structure is defined by your app's auth system.
|
|
514
|
-
*/
|
|
515
|
-
type UserLike = UserBase & {
|
|
516
|
-
/** User email (optional) */
|
|
517
|
-
email?: string;
|
|
518
|
-
};
|
|
519
|
-
/**
|
|
520
|
-
* Extract user ID from a user object (supports both id and _id)
|
|
521
|
-
*/
|
|
522
|
-
declare function getUserId(user: UserLike | null | undefined): string | undefined;
|
|
523
|
-
|
|
524
|
-
type CrudController<TDoc> = IController<TDoc>;
|
|
525
|
-
interface ApiResponse<T = unknown> {
|
|
526
|
-
success: boolean;
|
|
527
|
-
data?: T;
|
|
528
|
-
error?: string;
|
|
529
|
-
message?: string;
|
|
530
|
-
meta?: Record<string, unknown>;
|
|
531
|
-
}
|
|
532
|
-
interface UserOrganization {
|
|
533
|
-
userId: string;
|
|
534
|
-
organizationId: string;
|
|
535
|
-
[key: string]: unknown;
|
|
536
|
-
}
|
|
537
|
-
interface JWTPayload {
|
|
538
|
-
sub: string;
|
|
539
|
-
[key: string]: unknown;
|
|
540
|
-
}
|
|
541
|
-
interface RequestContext {
|
|
542
|
-
operation?: string;
|
|
543
|
-
user?: unknown;
|
|
544
|
-
organizationId?: string;
|
|
545
|
-
filters?: Record<string, unknown>;
|
|
546
|
-
[key: string]: unknown;
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
* Controller-level query options - parsed from request query string
|
|
550
|
-
* Includes pagination, filtering, and context data
|
|
551
|
-
*/
|
|
552
|
-
interface ControllerQueryOptions {
|
|
553
|
-
page?: number;
|
|
554
|
-
limit?: number;
|
|
555
|
-
sort?: string | Record<string, 1 | -1>;
|
|
556
|
-
/** Simple populate (comma-separated string or array) */
|
|
557
|
-
populate?: string | string[] | Record<string, unknown>;
|
|
558
|
-
/**
|
|
559
|
-
* Advanced populate options (Mongoose-compatible)
|
|
560
|
-
* When set, takes precedence over simple `populate`
|
|
561
|
-
*/
|
|
562
|
-
populateOptions?: PopulateOption[];
|
|
563
|
-
select?: string | string[] | Record<string, 0 | 1>;
|
|
564
|
-
filters?: Record<string, unknown>;
|
|
565
|
-
search?: string;
|
|
566
|
-
lean?: boolean;
|
|
567
|
-
after?: string;
|
|
568
|
-
user?: unknown;
|
|
569
|
-
organizationId?: string;
|
|
570
|
-
context?: Record<string, unknown>;
|
|
571
|
-
/** Allow additional options */
|
|
572
|
-
[key: string]: unknown;
|
|
573
|
-
}
|
|
574
|
-
/**
|
|
575
|
-
* Mongoose-compatible populate option for advanced field selection
|
|
576
|
-
* Used when you need to select specific fields from populated documents
|
|
577
|
-
*
|
|
578
|
-
* @example
|
|
579
|
-
* ```typescript
|
|
580
|
-
* // URL: ?populate[author][select]=name,email
|
|
581
|
-
* // Generates: { path: 'author', select: 'name email' }
|
|
582
|
-
* ```
|
|
583
|
-
*/
|
|
584
|
-
interface PopulateOption {
|
|
585
|
-
/** Field path to populate */
|
|
586
|
-
path: string;
|
|
587
|
-
/** Fields to select (space-separated) */
|
|
588
|
-
select?: string;
|
|
589
|
-
/** Filter conditions for populated documents */
|
|
590
|
-
match?: Record<string, unknown>;
|
|
591
|
-
/** Query options (limit, sort, skip) */
|
|
592
|
-
options?: {
|
|
593
|
-
limit?: number;
|
|
594
|
-
sort?: Record<string, 1 | -1>;
|
|
595
|
-
skip?: number;
|
|
596
|
-
};
|
|
597
|
-
/** Nested populate configuration */
|
|
598
|
-
populate?: PopulateOption;
|
|
599
|
-
}
|
|
600
|
-
/**
|
|
601
|
-
* Parsed query result from QueryParser
|
|
602
|
-
* Includes pagination, sorting, filtering, etc.
|
|
603
|
-
*
|
|
604
|
-
* The index signature allows custom query parsers (like MongoKit's QueryParser)
|
|
605
|
-
* to add additional fields without breaking Arc's type system.
|
|
606
|
-
*/
|
|
607
|
-
interface ParsedQuery {
|
|
608
|
-
filters?: Record<string, unknown>;
|
|
609
|
-
limit?: number;
|
|
610
|
-
sort?: string | Record<string, 1 | -1>;
|
|
611
|
-
/** Simple populate (comma-separated string or array) */
|
|
612
|
-
populate?: string | string[] | Record<string, unknown>;
|
|
613
|
-
/**
|
|
614
|
-
* Advanced populate options (Mongoose-compatible)
|
|
615
|
-
* When set, takes precedence over simple `populate`
|
|
616
|
-
* @example [{ path: 'author', select: 'name email' }]
|
|
617
|
-
*/
|
|
618
|
-
populateOptions?: PopulateOption[];
|
|
619
|
-
search?: string;
|
|
620
|
-
page?: number;
|
|
621
|
-
after?: string;
|
|
622
|
-
select?: string | string[] | Record<string, 0 | 1>;
|
|
623
|
-
/** Allow additional fields from custom query parsers */
|
|
624
|
-
[key: string]: unknown;
|
|
625
|
-
}
|
|
626
|
-
/**
|
|
627
|
-
* Query Parser Interface
|
|
628
|
-
* Implement this to create custom query parsers
|
|
629
|
-
*
|
|
630
|
-
* @example MongoKit QueryParser
|
|
631
|
-
* ```typescript
|
|
632
|
-
* import { QueryParser } from '@classytic/mongokit';
|
|
633
|
-
* const queryParser = new QueryParser();
|
|
634
|
-
* ```
|
|
635
|
-
*/
|
|
636
|
-
interface QueryParserInterface {
|
|
637
|
-
parse(query: Record<string, unknown> | null | undefined): ParsedQuery;
|
|
638
|
-
/**
|
|
639
|
-
* Optional: Export OpenAPI schema for query parameters
|
|
640
|
-
* Use this to document query parameters in OpenAPI/Swagger
|
|
641
|
-
*/
|
|
642
|
-
getQuerySchema?(): {
|
|
643
|
-
type: 'object';
|
|
644
|
-
properties: Record<string, unknown>;
|
|
645
|
-
required?: string[];
|
|
646
|
-
};
|
|
647
|
-
}
|
|
648
|
-
interface FastifyRequestExtras {
|
|
649
|
-
user?: unknown;
|
|
650
|
-
organizationId?: string;
|
|
651
|
-
}
|
|
652
|
-
interface RequestWithExtras extends Omit<FastifyRequest, 'user'> {
|
|
653
|
-
/**
|
|
654
|
-
* Arc metadata - set by createCrudRouter
|
|
655
|
-
* Contains resource configuration and schema options
|
|
656
|
-
*/
|
|
657
|
-
arc?: {
|
|
658
|
-
resourceName?: string;
|
|
659
|
-
schemaOptions?: RouteSchemaOptions;
|
|
660
|
-
permissions?: ResourcePermissions;
|
|
661
|
-
};
|
|
662
|
-
user?: unknown;
|
|
663
|
-
organizationId?: string;
|
|
664
|
-
context?: Record<string, unknown>;
|
|
665
|
-
_policyFilters?: Record<string, unknown>;
|
|
666
|
-
fieldMask?: string[];
|
|
667
|
-
_ownershipCheck?: Record<string, unknown>;
|
|
668
|
-
}
|
|
669
|
-
type FastifyWithAuth = FastifyInstance & {
|
|
670
|
-
authenticate: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
|
|
671
|
-
};
|
|
672
|
-
/**
|
|
673
|
-
* Arc core decorator interface
|
|
674
|
-
* Added by arcCorePlugin to provide instance-scoped hooks and registry
|
|
675
|
-
*/
|
|
676
|
-
interface ArcDecorator {
|
|
677
|
-
/** Instance-scoped hook system */
|
|
678
|
-
hooks: HookSystem;
|
|
679
|
-
/** Instance-scoped resource registry */
|
|
680
|
-
registry: ResourceRegistry;
|
|
681
|
-
/** Whether event emission is enabled */
|
|
682
|
-
emitEvents: boolean;
|
|
683
|
-
}
|
|
684
|
-
/**
|
|
685
|
-
* Events decorator interface
|
|
686
|
-
* Added by eventPlugin to provide event pub/sub
|
|
687
|
-
*/
|
|
688
|
-
interface EventsDecorator {
|
|
689
|
-
/** Publish an event */
|
|
690
|
-
publish: <T>(type: string, payload: T, meta?: Partial<{
|
|
691
|
-
id: string;
|
|
692
|
-
timestamp: Date;
|
|
693
|
-
}>) => Promise<void>;
|
|
694
|
-
/** Subscribe to events */
|
|
695
|
-
subscribe: (pattern: string, handler: (event: unknown) => void | Promise<void>) => Promise<() => void>;
|
|
696
|
-
/** Get transport name */
|
|
697
|
-
transportName: string;
|
|
698
|
-
}
|
|
699
|
-
/**
|
|
700
|
-
* Fastify instance with Arc decorators
|
|
701
|
-
* Arc adds these decorators via plugins/presets
|
|
702
|
-
*/
|
|
703
|
-
type FastifyWithDecorators = FastifyInstance & {
|
|
704
|
-
arc?: ArcDecorator;
|
|
705
|
-
events?: EventsDecorator;
|
|
706
|
-
authenticate?: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
|
|
707
|
-
organizationScoped?: (options?: {
|
|
708
|
-
required?: boolean;
|
|
709
|
-
}) => RouteHandlerMethod;
|
|
710
|
-
[key: string]: unknown;
|
|
711
|
-
};
|
|
712
|
-
interface OwnershipCheck {
|
|
713
|
-
field: string;
|
|
714
|
-
userField?: string;
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
interface ResourceConfig<TDoc = AnyRecord> {
|
|
718
|
-
name: string;
|
|
719
|
-
displayName?: string;
|
|
720
|
-
tag?: string;
|
|
721
|
-
prefix?: string;
|
|
722
|
-
adapter?: DataAdapter<TDoc>;
|
|
723
|
-
/** Controller instance - accepts any object with CRUD methods */
|
|
724
|
-
controller?: IController<TDoc> | ControllerLike | Record<string, any> | object;
|
|
725
|
-
queryParser?: unknown;
|
|
726
|
-
permissions?: ResourcePermissions;
|
|
727
|
-
schemaOptions?: RouteSchemaOptions;
|
|
728
|
-
openApiSchemas?: OpenApiSchemas;
|
|
729
|
-
customSchemas?: Partial<CrudSchemas>;
|
|
730
|
-
presets?: Array<string | PresetResult | {
|
|
731
|
-
name: string;
|
|
732
|
-
[key: string]: unknown;
|
|
733
|
-
}>;
|
|
734
|
-
hooks?: ResourceHooks;
|
|
735
|
-
middlewares?: MiddlewareConfig;
|
|
736
|
-
additionalRoutes?: AdditionalRoute[];
|
|
737
|
-
disableCrud?: boolean;
|
|
738
|
-
disableDefaultRoutes?: boolean;
|
|
739
|
-
disabledRoutes?: CrudRouteKey[];
|
|
740
|
-
organizationScoped?: boolean;
|
|
741
|
-
module?: string;
|
|
742
|
-
events?: Record<string, EventDefinition>;
|
|
743
|
-
skipValidation?: boolean;
|
|
744
|
-
skipRegistry?: boolean;
|
|
745
|
-
_appliedPresets?: string[];
|
|
746
|
-
}
|
|
747
|
-
/**
|
|
748
|
-
* Resource-level permissions
|
|
749
|
-
* ONLY PermissionCheck functions allowed - no string arrays
|
|
750
|
-
*/
|
|
751
|
-
interface ResourcePermissions {
|
|
752
|
-
list?: PermissionCheck;
|
|
753
|
-
get?: PermissionCheck;
|
|
754
|
-
create?: PermissionCheck;
|
|
755
|
-
update?: PermissionCheck;
|
|
756
|
-
delete?: PermissionCheck;
|
|
757
|
-
}
|
|
758
|
-
interface ResourceHooks {
|
|
759
|
-
beforeCreate?: (data: AnyRecord) => Promise<AnyRecord> | AnyRecord;
|
|
760
|
-
afterCreate?: (doc: AnyRecord) => Promise<void> | void;
|
|
761
|
-
beforeUpdate?: (id: string, data: AnyRecord) => Promise<AnyRecord> | AnyRecord;
|
|
762
|
-
afterUpdate?: (doc: AnyRecord) => Promise<void> | void;
|
|
763
|
-
beforeDelete?: (id: string) => Promise<void> | void;
|
|
764
|
-
afterDelete?: (id: string) => Promise<void> | void;
|
|
765
|
-
}
|
|
766
|
-
/**
|
|
767
|
-
* Additional route definition for custom endpoints
|
|
768
|
-
*/
|
|
769
|
-
interface AdditionalRoute {
|
|
770
|
-
/** HTTP method */
|
|
771
|
-
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
772
|
-
/** Route path (relative to resource prefix) */
|
|
773
|
-
path: string;
|
|
774
|
-
/**
|
|
775
|
-
* Handler - string (controller method name) or function
|
|
776
|
-
* Function can be Fastify handler or any (request, reply) => Promise<any>
|
|
777
|
-
*/
|
|
778
|
-
handler: string | RouteHandlerMethod | ((request: any, reply: any) => any);
|
|
779
|
-
/** Permission check - REQUIRED */
|
|
780
|
-
permissions: PermissionCheck;
|
|
781
|
-
/**
|
|
782
|
-
* Handler type - REQUIRED, no auto-detection
|
|
783
|
-
* true = ControllerHandler (receives context object)
|
|
784
|
-
* false = FastifyHandler (receives request, reply)
|
|
785
|
-
*/
|
|
786
|
-
wrapHandler: boolean;
|
|
787
|
-
/** OpenAPI summary */
|
|
788
|
-
summary?: string;
|
|
789
|
-
/** OpenAPI description */
|
|
790
|
-
description?: string;
|
|
791
|
-
/** OpenAPI tags */
|
|
792
|
-
tags?: string[];
|
|
793
|
-
/**
|
|
794
|
-
* Custom route-level middleware
|
|
795
|
-
* Can be an array of handlers or a function that receives fastify and returns handlers
|
|
796
|
-
* @example
|
|
797
|
-
* // Direct array
|
|
798
|
-
* preHandler: [myMiddleware]
|
|
799
|
-
* // Function that receives fastify (for accessing decorators)
|
|
800
|
-
* preHandler: (fastify) => [fastify.customerContext({ required: true })]
|
|
801
|
-
*/
|
|
802
|
-
preHandler?: RouteHandlerMethod[] | ((fastify: any) => RouteHandlerMethod[]);
|
|
803
|
-
/** Fastify route schema */
|
|
804
|
-
schema?: Record<string, unknown>;
|
|
805
|
-
}
|
|
806
|
-
interface RouteSchemaOptions {
|
|
807
|
-
hiddenFields?: string[];
|
|
808
|
-
readonlyFields?: string[];
|
|
809
|
-
requiredFields?: string[];
|
|
810
|
-
optionalFields?: string[];
|
|
811
|
-
excludeFields?: string[];
|
|
812
|
-
fieldRules?: Record<string, {
|
|
813
|
-
systemManaged?: boolean;
|
|
814
|
-
[key: string]: unknown;
|
|
815
|
-
}>;
|
|
816
|
-
query?: Record<string, unknown>;
|
|
817
|
-
}
|
|
818
|
-
interface FieldRule {
|
|
819
|
-
field: string;
|
|
820
|
-
required?: boolean;
|
|
821
|
-
readonly?: boolean;
|
|
822
|
-
hidden?: boolean;
|
|
823
|
-
}
|
|
824
|
-
/**
|
|
825
|
-
* CRUD Route Schemas (Fastify Native Format)
|
|
826
|
-
*
|
|
827
|
-
* @example
|
|
828
|
-
* {
|
|
829
|
-
* list: {
|
|
830
|
-
* querystring: { type: 'object', properties: { page: { type: 'number' } } },
|
|
831
|
-
* response: { 200: { type: 'object', properties: { docs: { type: 'array' } } } }
|
|
832
|
-
* },
|
|
833
|
-
* create: {
|
|
834
|
-
* body: { type: 'object', properties: { name: { type: 'string' } } },
|
|
835
|
-
* response: { 201: { type: 'object' } }
|
|
836
|
-
* }
|
|
837
|
-
* }
|
|
838
|
-
*/
|
|
839
|
-
interface CrudSchemas {
|
|
840
|
-
/** GET / - List all resources */
|
|
841
|
-
list?: {
|
|
842
|
-
querystring?: Record<string, unknown>;
|
|
843
|
-
response?: Record<number, unknown>;
|
|
844
|
-
[key: string]: unknown;
|
|
845
|
-
};
|
|
846
|
-
/** GET /:id - Get single resource */
|
|
847
|
-
get?: {
|
|
848
|
-
params?: Record<string, unknown>;
|
|
849
|
-
response?: Record<number, unknown>;
|
|
850
|
-
[key: string]: unknown;
|
|
851
|
-
};
|
|
852
|
-
/** POST / - Create resource */
|
|
853
|
-
create?: {
|
|
854
|
-
body?: Record<string, unknown>;
|
|
855
|
-
response?: Record<number, unknown>;
|
|
856
|
-
[key: string]: unknown;
|
|
857
|
-
};
|
|
858
|
-
/** PATCH /:id - Update resource */
|
|
859
|
-
update?: {
|
|
860
|
-
params?: Record<string, unknown>;
|
|
861
|
-
body?: Record<string, unknown>;
|
|
862
|
-
response?: Record<number, unknown>;
|
|
863
|
-
[key: string]: unknown;
|
|
864
|
-
};
|
|
865
|
-
/** DELETE /:id - Delete resource */
|
|
866
|
-
delete?: {
|
|
867
|
-
params?: Record<string, unknown>;
|
|
868
|
-
response?: Record<number, unknown>;
|
|
869
|
-
[key: string]: unknown;
|
|
870
|
-
};
|
|
871
|
-
[key: string]: unknown;
|
|
872
|
-
}
|
|
873
|
-
interface OpenApiSchemas {
|
|
874
|
-
entity?: unknown;
|
|
875
|
-
createBody?: unknown;
|
|
876
|
-
updateBody?: unknown;
|
|
877
|
-
params?: unknown;
|
|
878
|
-
listQuery?: unknown;
|
|
879
|
-
/**
|
|
880
|
-
* Explicit response schema for OpenAPI documentation.
|
|
881
|
-
* If provided, this will be used as-is for the response schema.
|
|
882
|
-
* If not provided, response schema is auto-generated from createBody.
|
|
883
|
-
*
|
|
884
|
-
* Note: This is for OpenAPI docs only - does NOT affect Fastify serialization.
|
|
885
|
-
*
|
|
886
|
-
* @example
|
|
887
|
-
* response: {
|
|
888
|
-
* type: 'object',
|
|
889
|
-
* properties: {
|
|
890
|
-
* _id: { type: 'string' },
|
|
891
|
-
* name: { type: 'string' },
|
|
892
|
-
* email: { type: 'string' },
|
|
893
|
-
* // Exclude password, include virtuals
|
|
894
|
-
* fullName: { type: 'string' },
|
|
895
|
-
* }
|
|
896
|
-
* }
|
|
897
|
-
*/
|
|
898
|
-
response?: unknown;
|
|
899
|
-
[key: string]: unknown;
|
|
900
|
-
}
|
|
901
|
-
/** Handler for middleware functions */
|
|
902
|
-
type MiddlewareHandler = (request: RequestWithExtras, reply: FastifyReply) => Promise<unknown>;
|
|
903
|
-
type CrudRouteKey = 'list' | 'get' | 'create' | 'update' | 'delete';
|
|
904
|
-
interface MiddlewareConfig {
|
|
905
|
-
list?: MiddlewareHandler[];
|
|
906
|
-
get?: MiddlewareHandler[];
|
|
907
|
-
create?: MiddlewareHandler[];
|
|
908
|
-
update?: MiddlewareHandler[];
|
|
909
|
-
delete?: MiddlewareHandler[];
|
|
910
|
-
[key: string]: MiddlewareHandler[] | undefined;
|
|
911
|
-
}
|
|
912
|
-
/**
|
|
913
|
-
* JWT utilities provided to authenticator
|
|
914
|
-
* Arc provides these helpers, app uses them as needed
|
|
915
|
-
*/
|
|
916
|
-
interface JwtContext {
|
|
917
|
-
/** Verify a JWT token and return decoded payload */
|
|
918
|
-
verify: <T = Record<string, unknown>>(token: string) => T;
|
|
919
|
-
/** Sign a payload and return JWT token */
|
|
920
|
-
sign: (payload: Record<string, unknown>, options?: {
|
|
921
|
-
expiresIn?: string;
|
|
922
|
-
}) => string;
|
|
923
|
-
/** Decode without verification (for inspection) */
|
|
924
|
-
decode: <T = Record<string, unknown>>(token: string) => T | null;
|
|
925
|
-
}
|
|
926
|
-
/**
|
|
927
|
-
* Context passed to app's authenticator function
|
|
928
|
-
*/
|
|
929
|
-
interface AuthenticatorContext {
|
|
930
|
-
/** JWT utilities (available if jwt.secret provided) */
|
|
931
|
-
jwt: JwtContext | null;
|
|
932
|
-
/** Fastify instance for advanced use cases */
|
|
933
|
-
fastify: FastifyInstance;
|
|
934
|
-
}
|
|
935
|
-
/**
|
|
936
|
-
* App-provided authenticator function
|
|
937
|
-
*
|
|
938
|
-
* Arc calls this for every non-public route.
|
|
939
|
-
* App has FULL control over authentication logic.
|
|
940
|
-
*
|
|
941
|
-
* @example
|
|
942
|
-
* ```typescript
|
|
943
|
-
* // Simple JWT auth
|
|
944
|
-
* authenticate: async (request, { jwt }) => {
|
|
945
|
-
* const token = request.headers.authorization?.split(' ')[1];
|
|
946
|
-
* if (!token || !jwt) return null;
|
|
947
|
-
* const decoded = jwt.verify(token);
|
|
948
|
-
* return userRepo.findById(decoded.id);
|
|
949
|
-
* }
|
|
950
|
-
*
|
|
951
|
-
* // Multi-strategy (JWT + API Key)
|
|
952
|
-
* authenticate: async (request, { jwt }) => {
|
|
953
|
-
* const apiKey = request.headers['x-api-key'];
|
|
954
|
-
* if (apiKey) {
|
|
955
|
-
* const result = await apiKeyService.verify(apiKey);
|
|
956
|
-
* if (result) return { _id: result.userId, isApiKey: true };
|
|
957
|
-
* }
|
|
958
|
-
* const token = request.headers.authorization?.split(' ')[1];
|
|
959
|
-
* if (token && jwt) {
|
|
960
|
-
* const decoded = jwt.verify(token);
|
|
961
|
-
* return userRepo.findById(decoded.id);
|
|
962
|
-
* }
|
|
963
|
-
* return null;
|
|
964
|
-
* }
|
|
965
|
-
* ```
|
|
966
|
-
*/
|
|
967
|
-
type Authenticator = (request: FastifyRequest, context: AuthenticatorContext) => Promise<any | null> | any | null;
|
|
968
|
-
/**
|
|
969
|
-
* Token pair returned by issueTokens helper
|
|
970
|
-
*/
|
|
971
|
-
interface TokenPair {
|
|
972
|
-
/** Access token (JWT) */
|
|
973
|
-
accessToken: string;
|
|
974
|
-
/** Refresh token (JWT with longer expiry) */
|
|
975
|
-
refreshToken?: string;
|
|
976
|
-
/** Access token expiry in seconds */
|
|
977
|
-
expiresIn: number;
|
|
978
|
-
/** Refresh token expiry in seconds */
|
|
979
|
-
refreshExpiresIn?: number;
|
|
980
|
-
/** Token type (always 'Bearer') */
|
|
981
|
-
tokenType: 'Bearer';
|
|
982
|
-
}
|
|
983
|
-
/**
|
|
984
|
-
* Auth helpers available on fastify.auth
|
|
985
|
-
*
|
|
986
|
-
* @example
|
|
987
|
-
* ```typescript
|
|
988
|
-
* // In login handler
|
|
989
|
-
* const user = await userRepo.findByEmail(email);
|
|
990
|
-
* if (!user || !await bcrypt.compare(password, user.password)) {
|
|
991
|
-
* return reply.code(401).send({ error: 'Invalid credentials' });
|
|
992
|
-
* }
|
|
993
|
-
*
|
|
994
|
-
* const tokens = fastify.auth.issueTokens({
|
|
995
|
-
* id: user._id,
|
|
996
|
-
* email: user.email,
|
|
997
|
-
* roles: user.roles,
|
|
998
|
-
* });
|
|
999
|
-
*
|
|
1000
|
-
* return { success: true, ...tokens, user };
|
|
1001
|
-
* ```
|
|
1002
|
-
*/
|
|
1003
|
-
interface AuthHelpers {
|
|
1004
|
-
/** JWT utilities (if configured) */
|
|
1005
|
-
jwt: JwtContext | null;
|
|
1006
|
-
/**
|
|
1007
|
-
* Issue access + refresh tokens for a user
|
|
1008
|
-
* App calls this after validating credentials
|
|
1009
|
-
*/
|
|
1010
|
-
issueTokens: (payload: Record<string, unknown>, options?: {
|
|
1011
|
-
expiresIn?: string;
|
|
1012
|
-
refreshExpiresIn?: string;
|
|
1013
|
-
}) => TokenPair;
|
|
1014
|
-
/**
|
|
1015
|
-
* Verify a refresh token and return decoded payload
|
|
1016
|
-
*/
|
|
1017
|
-
verifyRefreshToken: <T = Record<string, unknown>>(token: string) => T;
|
|
1018
|
-
}
|
|
1019
|
-
interface ServiceContext {
|
|
1020
|
-
user?: unknown;
|
|
1021
|
-
organizationId?: string;
|
|
1022
|
-
requestId?: string;
|
|
1023
|
-
select?: string[] | Record<string, 0 | 1>;
|
|
1024
|
-
populate?: string | string[];
|
|
1025
|
-
lean?: boolean;
|
|
1026
|
-
}
|
|
1027
|
-
interface PresetHook {
|
|
1028
|
-
operation: 'create' | 'update' | 'delete' | 'read' | 'list';
|
|
1029
|
-
phase: 'before' | 'after';
|
|
1030
|
-
handler: (ctx: any) => void | Promise<void> | AnyRecord | Promise<AnyRecord>;
|
|
1031
|
-
priority?: number;
|
|
1032
|
-
}
|
|
1033
|
-
interface PresetResult {
|
|
1034
|
-
name: string;
|
|
1035
|
-
additionalRoutes?: AdditionalRoute[] | ((permissions: ResourcePermissions) => AdditionalRoute[]);
|
|
1036
|
-
middlewares?: MiddlewareConfig;
|
|
1037
|
-
schemaOptions?: RouteSchemaOptions;
|
|
1038
|
-
controllerOptions?: Record<string, unknown>;
|
|
1039
|
-
hooks?: PresetHook[];
|
|
1040
|
-
}
|
|
1041
|
-
type PresetFunction = (config: ResourceConfig) => PresetResult;
|
|
1042
|
-
interface GracefulShutdownOptions {
|
|
1043
|
-
timeout?: number;
|
|
1044
|
-
onShutdown?: () => Promise<void> | void;
|
|
1045
|
-
signals?: NodeJS.Signals[];
|
|
1046
|
-
logEvents?: boolean;
|
|
1047
|
-
}
|
|
1048
|
-
interface RequestIdOptions {
|
|
1049
|
-
headerName?: string;
|
|
1050
|
-
generator?: () => string;
|
|
1051
|
-
}
|
|
1052
|
-
interface HealthOptions {
|
|
1053
|
-
path?: string;
|
|
1054
|
-
check?: () => Promise<any>;
|
|
1055
|
-
}
|
|
1056
|
-
interface HealthCheck {
|
|
1057
|
-
healthy: boolean;
|
|
1058
|
-
timestamp: string;
|
|
1059
|
-
[key: string]: unknown;
|
|
1060
|
-
}
|
|
1061
|
-
/**
|
|
1062
|
-
* Auth Plugin Options - Clean, Minimal Configuration
|
|
1063
|
-
*
|
|
1064
|
-
* Arc provides JWT infrastructure and calls your authenticator.
|
|
1065
|
-
* You control ALL authentication logic.
|
|
1066
|
-
*
|
|
1067
|
-
* @example
|
|
1068
|
-
* ```typescript
|
|
1069
|
-
* // Minimal: just JWT (uses default jwtVerify)
|
|
1070
|
-
* auth: {
|
|
1071
|
-
* jwt: { secret: process.env.JWT_SECRET },
|
|
1072
|
-
* }
|
|
1073
|
-
*
|
|
1074
|
-
* // With custom authenticator (recommended)
|
|
1075
|
-
* auth: {
|
|
1076
|
-
* jwt: { secret: process.env.JWT_SECRET },
|
|
1077
|
-
* authenticate: async (request, { jwt }) => {
|
|
1078
|
-
* const token = request.headers.authorization?.split(' ')[1];
|
|
1079
|
-
* if (!token) return null;
|
|
1080
|
-
* const decoded = jwt.verify(token);
|
|
1081
|
-
* return userRepo.findById(decoded.id);
|
|
1082
|
-
* },
|
|
1083
|
-
* }
|
|
1084
|
-
*
|
|
1085
|
-
* // Multi-strategy (JWT + API Key)
|
|
1086
|
-
* auth: {
|
|
1087
|
-
* jwt: { secret: process.env.JWT_SECRET },
|
|
1088
|
-
* authenticate: async (request, { jwt }) => {
|
|
1089
|
-
* // Try API key first (faster)
|
|
1090
|
-
* const apiKey = request.headers['x-api-key'];
|
|
1091
|
-
* if (apiKey) {
|
|
1092
|
-
* const result = await apiKeyService.verify(apiKey);
|
|
1093
|
-
* if (result) return { _id: result.userId, isApiKey: true };
|
|
1094
|
-
* }
|
|
1095
|
-
* // Try JWT
|
|
1096
|
-
* const token = request.headers.authorization?.split(' ')[1];
|
|
1097
|
-
* if (token) {
|
|
1098
|
-
* const decoded = jwt.verify(token);
|
|
1099
|
-
* return userRepo.findById(decoded.id);
|
|
1100
|
-
* }
|
|
1101
|
-
* return null;
|
|
1102
|
-
* },
|
|
1103
|
-
* onFailure: (request, reply) => {
|
|
1104
|
-
* reply.code(401).send({
|
|
1105
|
-
* success: false,
|
|
1106
|
-
* error: 'Authentication required',
|
|
1107
|
-
* message: 'Use Bearer token or X-API-Key header',
|
|
1108
|
-
* });
|
|
1109
|
-
* },
|
|
1110
|
-
* }
|
|
1111
|
-
* ```
|
|
1112
|
-
*/
|
|
1113
|
-
interface AuthPluginOptions {
|
|
1114
|
-
/**
|
|
1115
|
-
* JWT configuration (optional but recommended)
|
|
1116
|
-
* If provided, jwt utilities are available in authenticator context
|
|
1117
|
-
*/
|
|
1118
|
-
jwt?: {
|
|
1119
|
-
/** JWT secret (required for JWT features) */
|
|
1120
|
-
secret: string;
|
|
1121
|
-
/** Access token expiry (default: '15m') */
|
|
1122
|
-
expiresIn?: string;
|
|
1123
|
-
/** Refresh token secret (defaults to main secret) */
|
|
1124
|
-
refreshSecret?: string;
|
|
1125
|
-
/** Refresh token expiry (default: '7d') */
|
|
1126
|
-
refreshExpiresIn?: string;
|
|
1127
|
-
/** Additional @fastify/jwt sign options */
|
|
1128
|
-
sign?: Record<string, unknown>;
|
|
1129
|
-
/** Additional @fastify/jwt verify options */
|
|
1130
|
-
verify?: Record<string, unknown>;
|
|
1131
|
-
};
|
|
1132
|
-
/**
|
|
1133
|
-
* Custom authenticator function (recommended)
|
|
1134
|
-
*
|
|
1135
|
-
* Arc calls this for non-public routes.
|
|
1136
|
-
* Return user object to authenticate, null/undefined to reject.
|
|
1137
|
-
*
|
|
1138
|
-
* If not provided and jwt.secret is set, uses default jwtVerify.
|
|
1139
|
-
*/
|
|
1140
|
-
authenticate?: Authenticator;
|
|
1141
|
-
/**
|
|
1142
|
-
* Custom auth failure handler
|
|
1143
|
-
* Customize the 401 response when authentication fails
|
|
1144
|
-
*/
|
|
1145
|
-
onFailure?: (request: FastifyRequest, reply: FastifyReply, error?: Error) => void | Promise<void>;
|
|
1146
|
-
/**
|
|
1147
|
-
* Property name to store user on request (default: 'user')
|
|
1148
|
-
*/
|
|
1149
|
-
userProperty?: string;
|
|
1150
|
-
}
|
|
1151
|
-
interface OrgScopeOptions {
|
|
1152
|
-
enabled?: boolean;
|
|
1153
|
-
header?: string;
|
|
1154
|
-
headerName?: string;
|
|
1155
|
-
queryParam?: string;
|
|
1156
|
-
bypassRoles?: string[];
|
|
1157
|
-
userOrgsPath?: string;
|
|
1158
|
-
validateMembership?: (user: unknown, orgId: string) => Promise<boolean> | boolean;
|
|
1159
|
-
}
|
|
1160
|
-
interface IntrospectionPluginOptions {
|
|
1161
|
-
path?: string;
|
|
1162
|
-
prefix?: string;
|
|
1163
|
-
enabled?: boolean;
|
|
1164
|
-
authRoles?: string[];
|
|
1165
|
-
}
|
|
1166
|
-
interface CrudRouterOptions {
|
|
1167
|
-
/** Route prefix */
|
|
1168
|
-
prefix?: string;
|
|
1169
|
-
/** Permission checks for CRUD operations */
|
|
1170
|
-
permissions?: ResourcePermissions;
|
|
1171
|
-
/** OpenAPI tag for grouping routes */
|
|
1172
|
-
tag?: string;
|
|
1173
|
-
/** JSON schemas for CRUD operations */
|
|
1174
|
-
schemas?: Partial<CrudSchemas>;
|
|
1175
|
-
/** Middlewares for each CRUD operation */
|
|
1176
|
-
middlewares?: MiddlewareConfig;
|
|
1177
|
-
/** Additional custom routes (from presets or user-defined) */
|
|
1178
|
-
additionalRoutes?: AdditionalRoute[];
|
|
1179
|
-
/** Disable all default CRUD routes */
|
|
1180
|
-
disableDefaultRoutes?: boolean;
|
|
1181
|
-
/** Disable specific CRUD routes */
|
|
1182
|
-
disabledRoutes?: CrudRouteKey[];
|
|
1183
|
-
/** Enable organization-scoped filtering */
|
|
1184
|
-
organizationScoped?: boolean;
|
|
1185
|
-
/** Resource name for lifecycle hooks */
|
|
1186
|
-
resourceName?: string;
|
|
1187
|
-
/** Schema generation options */
|
|
1188
|
-
schemaOptions?: RouteSchemaOptions;
|
|
1189
|
-
}
|
|
1190
|
-
interface ResourceMetadata {
|
|
1191
|
-
name: string;
|
|
1192
|
-
displayName?: string;
|
|
1193
|
-
tag?: string;
|
|
1194
|
-
prefix: string;
|
|
1195
|
-
module?: string;
|
|
1196
|
-
permissions?: ResourcePermissions;
|
|
1197
|
-
presets: string[];
|
|
1198
|
-
additionalRoutes?: AdditionalRoute[];
|
|
1199
|
-
routes: Array<{
|
|
1200
|
-
method: string;
|
|
1201
|
-
path: string;
|
|
1202
|
-
handler?: string;
|
|
1203
|
-
operation?: string;
|
|
1204
|
-
summary?: string;
|
|
1205
|
-
}>;
|
|
1206
|
-
events?: string[];
|
|
1207
|
-
}
|
|
1208
|
-
interface RegistryEntry extends ResourceMetadata {
|
|
1209
|
-
plugin: unknown;
|
|
1210
|
-
adapter?: {
|
|
1211
|
-
type: string;
|
|
1212
|
-
name: string;
|
|
1213
|
-
} | null;
|
|
1214
|
-
events?: string[];
|
|
1215
|
-
disableDefaultRoutes?: boolean;
|
|
1216
|
-
openApiSchemas?: OpenApiSchemas;
|
|
1217
|
-
registeredAt?: string;
|
|
1218
|
-
}
|
|
1219
|
-
interface RegistryStats {
|
|
1220
|
-
total?: number;
|
|
1221
|
-
totalResources: number;
|
|
1222
|
-
byTag?: Record<string, number>;
|
|
1223
|
-
byModule?: Record<string, number>;
|
|
1224
|
-
presetUsage?: Record<string, number>;
|
|
1225
|
-
totalRoutes?: number;
|
|
1226
|
-
totalEvents?: number;
|
|
1227
|
-
}
|
|
1228
|
-
interface IntrospectionData {
|
|
1229
|
-
resources: ResourceMetadata[];
|
|
1230
|
-
stats: RegistryStats;
|
|
1231
|
-
generatedAt?: string;
|
|
1232
|
-
}
|
|
1233
|
-
interface EventDefinition {
|
|
1234
|
-
name: string;
|
|
1235
|
-
handler: (data: unknown) => Promise<void> | void;
|
|
1236
|
-
schema?: Record<string, unknown>;
|
|
1237
|
-
description?: string;
|
|
1238
|
-
}
|
|
1239
|
-
interface ConfigError {
|
|
1240
|
-
field: string;
|
|
1241
|
-
message: string;
|
|
1242
|
-
code?: string;
|
|
1243
|
-
}
|
|
1244
|
-
interface ValidationResult$1 {
|
|
1245
|
-
valid: boolean;
|
|
1246
|
-
errors: ConfigError[];
|
|
1247
|
-
}
|
|
1248
|
-
interface ValidateOptions {
|
|
1249
|
-
strict?: boolean;
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
/**
|
|
1253
|
-
* Infer document type from DataAdapter or ResourceConfig
|
|
1254
|
-
*/
|
|
1255
|
-
type InferDocType<T> = T extends DataAdapter<infer D> ? D : T extends ResourceConfig<infer D> ? D : never;
|
|
1256
|
-
type InferResourceDoc<T> = T extends ResourceConfig<infer D> ? D : never;
|
|
1257
|
-
type TypedResourceConfig<TDoc> = ResourceConfig<TDoc>;
|
|
1258
|
-
type TypedController<TDoc> = IController<TDoc>;
|
|
1259
|
-
type TypedRepository<TDoc> = CrudRepository<TDoc>;
|
|
1260
|
-
interface BaseControllerOptions {
|
|
1261
|
-
/** Query parser instance */
|
|
1262
|
-
queryParser: QueryParserInterface;
|
|
1263
|
-
/** Schema generation options */
|
|
1264
|
-
schemaOptions?: RouteSchemaOptions;
|
|
1265
|
-
/** Maximum items per page */
|
|
1266
|
-
maxLimit?: number;
|
|
1267
|
-
/** Default items per page */
|
|
1268
|
-
defaultLimit?: number;
|
|
1269
|
-
/** Default sort field */
|
|
1270
|
-
defaultSort?: string;
|
|
1271
|
-
/** Resource name for hooks */
|
|
1272
|
-
resourceName?: string;
|
|
1273
|
-
/** Disable event emission */
|
|
1274
|
-
disableEvents?: boolean;
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
/**
|
|
1278
|
-
* Data Adapter Interface - Database Abstraction Layer
|
|
1279
|
-
*
|
|
1280
|
-
* Core abstraction that allows Arc to work with any database.
|
|
1281
|
-
* This is the ONLY contract between Arc and data persistence.
|
|
1282
|
-
*/
|
|
1283
|
-
|
|
1284
|
-
/**
|
|
1285
|
-
* Minimal repository interface for flexible adapter compatibility
|
|
1286
|
-
* Accepts any object with CRUD method names
|
|
1287
|
-
*/
|
|
1288
|
-
interface RepositoryLike {
|
|
1289
|
-
getAll: unknown;
|
|
1290
|
-
getById: unknown;
|
|
1291
|
-
create: unknown;
|
|
1292
|
-
update: unknown;
|
|
1293
|
-
delete: unknown;
|
|
1294
|
-
[key: string]: unknown;
|
|
1295
|
-
}
|
|
1296
|
-
interface DataAdapter<TDoc = unknown> {
|
|
1297
|
-
/**
|
|
1298
|
-
* Repository implementing CRUD operations
|
|
1299
|
-
* Accepts CrudRepository, MongoKit Repository, or any compatible object
|
|
1300
|
-
*/
|
|
1301
|
-
repository: CrudRepository<TDoc> | RepositoryLike;
|
|
1302
|
-
/** Adapter identifier for introspection */
|
|
1303
|
-
readonly type: 'mongoose' | 'prisma' | 'drizzle' | 'typeorm' | 'custom';
|
|
1304
|
-
/** Human-readable name */
|
|
1305
|
-
readonly name: string;
|
|
1306
|
-
/**
|
|
1307
|
-
* Generate OpenAPI schemas for CRUD operations
|
|
1308
|
-
*
|
|
1309
|
-
* This method allows each adapter to generate schemas specific to its ORM/database.
|
|
1310
|
-
* For example, Mongoose adapter can use mongokit to generate schemas from Mongoose models.
|
|
1311
|
-
*
|
|
1312
|
-
* @param options - Schema generation options (field rules, populate settings, etc.)
|
|
1313
|
-
* @returns OpenAPI schemas for CRUD operations or null if not supported
|
|
1314
|
-
*/
|
|
1315
|
-
generateSchemas?(options?: RouteSchemaOptions): OpenApiSchemas | null;
|
|
1316
|
-
/** Extract schema metadata for OpenAPI/introspection */
|
|
1317
|
-
getSchemaMetadata?(): SchemaMetadata | null;
|
|
1318
|
-
/** Validate data against schema before persistence */
|
|
1319
|
-
validate?(data: unknown): Promise<ValidationResult> | ValidationResult;
|
|
1320
|
-
/** Health check for database connection */
|
|
1321
|
-
healthCheck?(): Promise<boolean>;
|
|
1322
|
-
/** Close/cleanup resources */
|
|
1323
|
-
close?(): Promise<void>;
|
|
1324
|
-
}
|
|
1325
|
-
interface SchemaMetadata {
|
|
1326
|
-
name: string;
|
|
1327
|
-
fields: Record<string, FieldMetadata>;
|
|
1328
|
-
indexes?: Array<{
|
|
1329
|
-
fields: string[];
|
|
1330
|
-
unique?: boolean;
|
|
1331
|
-
sparse?: boolean;
|
|
1332
|
-
}>;
|
|
1333
|
-
relations?: Record<string, RelationMetadata>;
|
|
1334
|
-
}
|
|
1335
|
-
interface FieldMetadata {
|
|
1336
|
-
type: 'string' | 'number' | 'boolean' | 'date' | 'object' | 'array' | 'objectId' | 'enum';
|
|
1337
|
-
required?: boolean;
|
|
1338
|
-
unique?: boolean;
|
|
1339
|
-
default?: unknown;
|
|
1340
|
-
enum?: Array<string | number>;
|
|
1341
|
-
min?: number;
|
|
1342
|
-
max?: number;
|
|
1343
|
-
minLength?: number;
|
|
1344
|
-
maxLength?: number;
|
|
1345
|
-
pattern?: string;
|
|
1346
|
-
description?: string;
|
|
1347
|
-
ref?: string;
|
|
1348
|
-
array?: boolean;
|
|
1349
|
-
}
|
|
1350
|
-
interface RelationMetadata {
|
|
1351
|
-
type: 'one-to-one' | 'one-to-many' | 'many-to-many';
|
|
1352
|
-
target: string;
|
|
1353
|
-
foreignKey?: string;
|
|
1354
|
-
through?: string;
|
|
1355
|
-
}
|
|
1356
|
-
interface ValidationResult {
|
|
1357
|
-
valid: boolean;
|
|
1358
|
-
errors?: Array<{
|
|
1359
|
-
field: string;
|
|
1360
|
-
message: string;
|
|
1361
|
-
code?: string;
|
|
1362
|
-
}>;
|
|
1363
|
-
}
|
|
1364
|
-
type AdapterFactory<TDoc> = (config: unknown) => DataAdapter<TDoc>;
|
|
1365
|
-
|
|
1366
|
-
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, createHookSystem as aA, beforeCreate as aB, afterCreate as aC, beforeUpdate as aD, afterUpdate as aE, beforeDelete as aF, afterDelete as aG, type HookPhase as aH, type HookOperation as aI, type HookRegistration as aJ, type HookSystemOptions as aK, 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 PopulateOption as ak, type ArcDecorator as al, type EventsDecorator as am, type ResourcePermissions as an, type ResourceHooks as ao, type MiddlewareHandler as ap, type JwtContext as aq, type AuthenticatorContext as ar, type Authenticator as as, type TokenPair as at, type PresetHook as au, type BaseControllerOptions as av, type PaginationParams as aw, type InferDoc as ax, type ControllerHandler as ay, type FastifyHandler 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 };
|