@classytic/arc 1.0.8 → 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.
Files changed (322) hide show
  1. package/README.md +247 -794
  2. package/bin/arc.js +91 -52
  3. package/dist/EventTransport-BD2U0BTc.d.mts +100 -0
  4. package/dist/EventTransport-BD2U0BTc.d.mts.map +1 -0
  5. package/dist/HookSystem-BsGV-j2l.mjs +405 -0
  6. package/dist/HookSystem-BsGV-j2l.mjs.map +1 -0
  7. package/dist/ResourceRegistry-DsN4KJjV.mjs +250 -0
  8. package/dist/ResourceRegistry-DsN4KJjV.mjs.map +1 -0
  9. package/dist/adapters/index.d.mts +5 -0
  10. package/dist/adapters/index.mjs +3 -0
  11. package/dist/audit/index.d.mts +82 -0
  12. package/dist/audit/index.d.mts.map +1 -0
  13. package/dist/audit/index.mjs +276 -0
  14. package/dist/audit/index.mjs.map +1 -0
  15. package/dist/audit/mongodb.d.mts +5 -0
  16. package/dist/audit/mongodb.mjs +3 -0
  17. package/dist/audited-C3T5DTUx.mjs +141 -0
  18. package/dist/audited-C3T5DTUx.mjs.map +1 -0
  19. package/dist/auth/index.d.mts +189 -0
  20. package/dist/auth/index.d.mts.map +1 -0
  21. package/dist/auth/index.mjs +1102 -0
  22. package/dist/auth/index.mjs.map +1 -0
  23. package/dist/auth/redis-session.d.mts +44 -0
  24. package/dist/auth/redis-session.d.mts.map +1 -0
  25. package/dist/auth/redis-session.mjs +76 -0
  26. package/dist/auth/redis-session.mjs.map +1 -0
  27. package/dist/betterAuthOpenApi-BrHKeSAx.mjs +250 -0
  28. package/dist/betterAuthOpenApi-BrHKeSAx.mjs.map +1 -0
  29. package/dist/cache/index.d.mts +146 -0
  30. package/dist/cache/index.d.mts.map +1 -0
  31. package/dist/cache/index.mjs +92 -0
  32. package/dist/cache/index.mjs.map +1 -0
  33. package/dist/caching-Bl28lYsR.mjs +94 -0
  34. package/dist/caching-Bl28lYsR.mjs.map +1 -0
  35. package/dist/chunk-C7Uep-_p.mjs +20 -0
  36. package/dist/circuitBreaker-DeY4FCjs.mjs +1097 -0
  37. package/dist/circuitBreaker-DeY4FCjs.mjs.map +1 -0
  38. package/dist/cli/commands/describe.d.mts +19 -0
  39. package/dist/cli/commands/describe.d.mts.map +1 -0
  40. package/dist/cli/commands/describe.mjs +239 -0
  41. package/dist/cli/commands/describe.mjs.map +1 -0
  42. package/dist/cli/commands/docs.d.mts +14 -0
  43. package/dist/cli/commands/docs.d.mts.map +1 -0
  44. package/dist/cli/commands/docs.mjs +53 -0
  45. package/dist/cli/commands/docs.mjs.map +1 -0
  46. package/dist/cli/commands/{generate.d.ts → generate.d.mts} +3 -1
  47. package/dist/cli/commands/generate.d.mts.map +1 -0
  48. package/dist/cli/commands/generate.mjs +358 -0
  49. package/dist/cli/commands/generate.mjs.map +1 -0
  50. package/dist/cli/commands/{init.d.ts → init.d.mts} +12 -8
  51. package/dist/cli/commands/init.d.mts.map +1 -0
  52. package/dist/cli/commands/{init.js → init.mjs} +807 -616
  53. package/dist/cli/commands/init.mjs.map +1 -0
  54. package/dist/cli/commands/introspect.d.mts +11 -0
  55. package/dist/cli/commands/introspect.d.mts.map +1 -0
  56. package/dist/cli/commands/introspect.mjs +76 -0
  57. package/dist/cli/commands/introspect.mjs.map +1 -0
  58. package/dist/cli/index.d.mts +17 -0
  59. package/dist/cli/index.d.mts.map +1 -0
  60. package/dist/cli/index.mjs +157 -0
  61. package/dist/cli/index.mjs.map +1 -0
  62. package/dist/constants-DdXFXQtN.mjs +85 -0
  63. package/dist/constants-DdXFXQtN.mjs.map +1 -0
  64. package/dist/core/index.d.mts +5 -0
  65. package/dist/core/index.mjs +4 -0
  66. package/dist/createApp-CUgNqegw.mjs +560 -0
  67. package/dist/createApp-CUgNqegw.mjs.map +1 -0
  68. package/dist/defineResource-k0_BDn8v.mjs +2197 -0
  69. package/dist/defineResource-k0_BDn8v.mjs.map +1 -0
  70. package/dist/discovery/index.d.mts +47 -0
  71. package/dist/discovery/index.d.mts.map +1 -0
  72. package/dist/discovery/index.mjs +110 -0
  73. package/dist/discovery/index.mjs.map +1 -0
  74. package/dist/docs/index.d.mts +163 -0
  75. package/dist/docs/index.d.mts.map +1 -0
  76. package/dist/docs/index.mjs +73 -0
  77. package/dist/docs/index.mjs.map +1 -0
  78. package/dist/elevation-BRy3yFWT.mjs +113 -0
  79. package/dist/elevation-BRy3yFWT.mjs.map +1 -0
  80. package/dist/elevation-B_2dRLVP.d.mts +88 -0
  81. package/dist/elevation-B_2dRLVP.d.mts.map +1 -0
  82. package/dist/errorHandler-BbcgBmIH.d.mts +73 -0
  83. package/dist/errorHandler-BbcgBmIH.d.mts.map +1 -0
  84. package/dist/errorHandler-C1okiriz.mjs +109 -0
  85. package/dist/errorHandler-C1okiriz.mjs.map +1 -0
  86. package/dist/errors-B9bZok84.mjs +212 -0
  87. package/dist/errors-B9bZok84.mjs.map +1 -0
  88. package/dist/errors-ChKiFz62.d.mts +125 -0
  89. package/dist/errors-ChKiFz62.d.mts.map +1 -0
  90. package/dist/eventPlugin-CTrLH3mt.d.mts +125 -0
  91. package/dist/eventPlugin-CTrLH3mt.d.mts.map +1 -0
  92. package/dist/eventPlugin-DGR_B2on.mjs +230 -0
  93. package/dist/eventPlugin-DGR_B2on.mjs.map +1 -0
  94. package/dist/events/index.d.mts +54 -0
  95. package/dist/events/index.d.mts.map +1 -0
  96. package/dist/events/index.mjs +52 -0
  97. package/dist/events/index.mjs.map +1 -0
  98. package/dist/events/transports/redis-stream-entry.d.mts +2 -0
  99. package/dist/events/transports/redis-stream-entry.mjs +178 -0
  100. package/dist/events/transports/redis-stream-entry.mjs.map +1 -0
  101. package/dist/events/transports/redis.d.mts +77 -0
  102. package/dist/events/transports/redis.d.mts.map +1 -0
  103. package/dist/events/transports/redis.mjs +125 -0
  104. package/dist/events/transports/redis.mjs.map +1 -0
  105. package/dist/externalPaths-DlINfKbP.d.mts +51 -0
  106. package/dist/externalPaths-DlINfKbP.d.mts.map +1 -0
  107. package/dist/factory/index.d.mts +64 -0
  108. package/dist/factory/index.d.mts.map +1 -0
  109. package/dist/factory/index.mjs +3 -0
  110. package/dist/fastifyAdapter-BkrGrlFi.d.mts +217 -0
  111. package/dist/fastifyAdapter-BkrGrlFi.d.mts.map +1 -0
  112. package/dist/fields-DyaDVX4J.d.mts +110 -0
  113. package/dist/fields-DyaDVX4J.d.mts.map +1 -0
  114. package/dist/fields-iagOozy0.mjs +115 -0
  115. package/dist/fields-iagOozy0.mjs.map +1 -0
  116. package/dist/hooks/index.d.mts +4 -0
  117. package/dist/hooks/index.mjs +3 -0
  118. package/dist/idempotency/index.d.mts +97 -0
  119. package/dist/idempotency/index.d.mts.map +1 -0
  120. package/dist/idempotency/index.mjs +320 -0
  121. package/dist/idempotency/index.mjs.map +1 -0
  122. package/dist/idempotency/mongodb.d.mts +2 -0
  123. package/dist/idempotency/mongodb.mjs +115 -0
  124. package/dist/idempotency/mongodb.mjs.map +1 -0
  125. package/dist/idempotency/redis.d.mts +2 -0
  126. package/dist/idempotency/redis.mjs +104 -0
  127. package/dist/idempotency/redis.mjs.map +1 -0
  128. package/dist/index.d.mts +261 -0
  129. package/dist/index.d.mts.map +1 -0
  130. package/dist/index.mjs +105 -0
  131. package/dist/index.mjs.map +1 -0
  132. package/dist/integrations/event-gateway.d.mts +47 -0
  133. package/dist/integrations/event-gateway.d.mts.map +1 -0
  134. package/dist/integrations/event-gateway.mjs +44 -0
  135. package/dist/integrations/event-gateway.mjs.map +1 -0
  136. package/dist/integrations/index.d.mts +5 -0
  137. package/dist/integrations/index.mjs +1 -0
  138. package/dist/integrations/jobs.d.mts +104 -0
  139. package/dist/integrations/jobs.d.mts.map +1 -0
  140. package/dist/integrations/jobs.mjs +124 -0
  141. package/dist/integrations/jobs.mjs.map +1 -0
  142. package/dist/integrations/streamline.d.mts +61 -0
  143. package/dist/integrations/streamline.d.mts.map +1 -0
  144. package/dist/integrations/streamline.mjs +126 -0
  145. package/dist/integrations/streamline.mjs.map +1 -0
  146. package/dist/integrations/websocket.d.mts +83 -0
  147. package/dist/integrations/websocket.d.mts.map +1 -0
  148. package/dist/integrations/websocket.mjs +289 -0
  149. package/dist/integrations/websocket.mjs.map +1 -0
  150. package/dist/interface-B01JvPVc.d.mts +78 -0
  151. package/dist/interface-B01JvPVc.d.mts.map +1 -0
  152. package/dist/interface-CZe8IkMf.d.mts +55 -0
  153. package/dist/interface-CZe8IkMf.d.mts.map +1 -0
  154. package/dist/interface-Ch8HU9uM.d.mts +1098 -0
  155. package/dist/interface-Ch8HU9uM.d.mts.map +1 -0
  156. package/dist/introspectionPlugin-rFdO8ZUa.mjs +54 -0
  157. package/dist/introspectionPlugin-rFdO8ZUa.mjs.map +1 -0
  158. package/dist/keys-BqNejWup.mjs +43 -0
  159. package/dist/keys-BqNejWup.mjs.map +1 -0
  160. package/dist/logger-Df2O2WsW.mjs +79 -0
  161. package/dist/logger-Df2O2WsW.mjs.map +1 -0
  162. package/dist/memory-cQgelFOj.mjs +144 -0
  163. package/dist/memory-cQgelFOj.mjs.map +1 -0
  164. package/dist/migrations/index.d.mts +157 -0
  165. package/dist/migrations/index.d.mts.map +1 -0
  166. package/dist/migrations/index.mjs +261 -0
  167. package/dist/migrations/index.mjs.map +1 -0
  168. package/dist/mongodb-BfJVlUJH.mjs +94 -0
  169. package/dist/mongodb-BfJVlUJH.mjs.map +1 -0
  170. package/dist/mongodb-CGzRbfAK.d.mts +119 -0
  171. package/dist/mongodb-CGzRbfAK.d.mts.map +1 -0
  172. package/dist/mongodb-JN-9JA7K.d.mts +72 -0
  173. package/dist/mongodb-JN-9JA7K.d.mts.map +1 -0
  174. package/dist/openapi-G3Cw7XuM.mjs +524 -0
  175. package/dist/openapi-G3Cw7XuM.mjs.map +1 -0
  176. package/dist/org/index.d.mts +69 -0
  177. package/dist/org/index.d.mts.map +1 -0
  178. package/dist/org/index.mjs +514 -0
  179. package/dist/org/index.mjs.map +1 -0
  180. package/dist/org/types.d.mts +83 -0
  181. package/dist/org/types.d.mts.map +1 -0
  182. package/dist/org/types.mjs +1 -0
  183. package/dist/permissions/index.d.mts +279 -0
  184. package/dist/permissions/index.d.mts.map +1 -0
  185. package/dist/permissions/index.mjs +579 -0
  186. package/dist/permissions/index.mjs.map +1 -0
  187. package/dist/plugins/index.d.mts +173 -0
  188. package/dist/plugins/index.d.mts.map +1 -0
  189. package/dist/plugins/index.mjs +523 -0
  190. package/dist/plugins/index.mjs.map +1 -0
  191. package/dist/plugins/response-cache.d.mts +88 -0
  192. package/dist/plugins/response-cache.d.mts.map +1 -0
  193. package/dist/plugins/response-cache.mjs +284 -0
  194. package/dist/plugins/response-cache.mjs.map +1 -0
  195. package/dist/plugins/tracing-entry.d.mts +2 -0
  196. package/dist/plugins/tracing-entry.mjs +186 -0
  197. package/dist/plugins/tracing-entry.mjs.map +1 -0
  198. package/dist/pluralize-CEweyOEm.mjs +87 -0
  199. package/dist/pluralize-CEweyOEm.mjs.map +1 -0
  200. package/dist/policies/{index.d.ts → index.d.mts} +204 -169
  201. package/dist/policies/index.d.mts.map +1 -0
  202. package/dist/policies/index.mjs +322 -0
  203. package/dist/policies/index.mjs.map +1 -0
  204. package/dist/presets/{index.d.ts → index.d.mts} +63 -131
  205. package/dist/presets/index.d.mts.map +1 -0
  206. package/dist/presets/index.mjs +144 -0
  207. package/dist/presets/index.mjs.map +1 -0
  208. package/dist/presets/multiTenant.d.mts +25 -0
  209. package/dist/presets/multiTenant.d.mts.map +1 -0
  210. package/dist/presets/multiTenant.mjs +114 -0
  211. package/dist/presets/multiTenant.mjs.map +1 -0
  212. package/dist/presets-BITljm96.mjs +120 -0
  213. package/dist/presets-BITljm96.mjs.map +1 -0
  214. package/dist/presets-DzSMwlKj.d.mts +58 -0
  215. package/dist/presets-DzSMwlKj.d.mts.map +1 -0
  216. package/dist/prisma-DJbMt3yf.mjs +628 -0
  217. package/dist/prisma-DJbMt3yf.mjs.map +1 -0
  218. package/dist/prisma-Dg9GoVdj.d.mts +275 -0
  219. package/dist/prisma-Dg9GoVdj.d.mts.map +1 -0
  220. package/dist/queryCachePlugin-7THaI5mt.d.mts +72 -0
  221. package/dist/queryCachePlugin-7THaI5mt.d.mts.map +1 -0
  222. package/dist/queryCachePlugin-DMBnp2Q0.mjs +139 -0
  223. package/dist/queryCachePlugin-DMBnp2Q0.mjs.map +1 -0
  224. package/dist/redis-D-JAeLtm.d.mts +50 -0
  225. package/dist/redis-D-JAeLtm.d.mts.map +1 -0
  226. package/dist/redis-stream-Bdh_vUU8.d.mts +104 -0
  227. package/dist/redis-stream-Bdh_vUU8.d.mts.map +1 -0
  228. package/dist/registry/index.d.mts +12 -0
  229. package/dist/registry/index.d.mts.map +1 -0
  230. package/dist/registry/index.mjs +4 -0
  231. package/dist/requestContext-QQD6ROJc.mjs +56 -0
  232. package/dist/requestContext-QQD6ROJc.mjs.map +1 -0
  233. package/dist/schemaConverter-BwrmWroW.mjs +99 -0
  234. package/dist/schemaConverter-BwrmWroW.mjs.map +1 -0
  235. package/dist/schemas/index.d.mts +64 -0
  236. package/dist/schemas/index.d.mts.map +1 -0
  237. package/dist/schemas/index.mjs +83 -0
  238. package/dist/schemas/index.mjs.map +1 -0
  239. package/dist/scope/index.d.mts +22 -0
  240. package/dist/scope/index.d.mts.map +1 -0
  241. package/dist/scope/index.mjs +66 -0
  242. package/dist/scope/index.mjs.map +1 -0
  243. package/dist/sessionManager-jPKLbHE0.d.mts +187 -0
  244. package/dist/sessionManager-jPKLbHE0.d.mts.map +1 -0
  245. package/dist/sse-B3c3_yZp.mjs +124 -0
  246. package/dist/sse-B3c3_yZp.mjs.map +1 -0
  247. package/dist/testing/index.d.mts +908 -0
  248. package/dist/testing/index.d.mts.map +1 -0
  249. package/dist/testing/index.mjs +1977 -0
  250. package/dist/testing/index.mjs.map +1 -0
  251. package/dist/tracing-Cc7vVQPp.d.mts +71 -0
  252. package/dist/tracing-Cc7vVQPp.d.mts.map +1 -0
  253. package/dist/typeGuards-DhMNLuvU.mjs +10 -0
  254. package/dist/typeGuards-DhMNLuvU.mjs.map +1 -0
  255. package/dist/types/index.d.mts +947 -0
  256. package/dist/types/index.d.mts.map +1 -0
  257. package/dist/types/index.mjs +15 -0
  258. package/dist/types/index.mjs.map +1 -0
  259. package/dist/types-Beqn1Un7.mjs +39 -0
  260. package/dist/types-Beqn1Un7.mjs.map +1 -0
  261. package/dist/types-CIgB7UUl.d.mts +446 -0
  262. package/dist/types-CIgB7UUl.d.mts.map +1 -0
  263. package/dist/types-aYB4V7uN.d.mts +87 -0
  264. package/dist/types-aYB4V7uN.d.mts.map +1 -0
  265. package/dist/utils/index.d.mts +748 -0
  266. package/dist/utils/index.d.mts.map +1 -0
  267. package/dist/utils/index.mjs +6 -0
  268. package/package.json +198 -70
  269. package/dist/BaseController-nNRS3vpA.d.ts +0 -233
  270. package/dist/adapters/index.d.ts +0 -237
  271. package/dist/adapters/index.js +0 -668
  272. package/dist/arcCorePlugin-CAjBQtZB.d.ts +0 -273
  273. package/dist/audit/index.d.ts +0 -195
  274. package/dist/audit/index.js +0 -319
  275. package/dist/auth/index.d.ts +0 -47
  276. package/dist/auth/index.js +0 -174
  277. package/dist/cli/commands/docs.d.ts +0 -11
  278. package/dist/cli/commands/docs.js +0 -474
  279. package/dist/cli/commands/generate.js +0 -334
  280. package/dist/cli/commands/introspect.d.ts +0 -8
  281. package/dist/cli/commands/introspect.js +0 -338
  282. package/dist/cli/index.d.ts +0 -4
  283. package/dist/cli/index.js +0 -3269
  284. package/dist/core/index.d.ts +0 -220
  285. package/dist/core/index.js +0 -2764
  286. package/dist/createApp-CjN9zZSL.d.ts +0 -77
  287. package/dist/docs/index.d.ts +0 -166
  288. package/dist/docs/index.js +0 -658
  289. package/dist/errors-8WIxGS_6.d.ts +0 -122
  290. package/dist/events/index.d.ts +0 -117
  291. package/dist/events/index.js +0 -89
  292. package/dist/factory/index.d.ts +0 -38
  293. package/dist/factory/index.js +0 -1647
  294. package/dist/hooks/index.d.ts +0 -4
  295. package/dist/hooks/index.js +0 -199
  296. package/dist/idempotency/index.d.ts +0 -323
  297. package/dist/idempotency/index.js +0 -500
  298. package/dist/index-D5QTob1X.d.ts +0 -1322
  299. package/dist/index.d.ts +0 -135
  300. package/dist/index.js +0 -4729
  301. package/dist/migrations/index.d.ts +0 -185
  302. package/dist/migrations/index.js +0 -274
  303. package/dist/org/index.d.ts +0 -129
  304. package/dist/org/index.js +0 -220
  305. package/dist/permissions/index.d.ts +0 -144
  306. package/dist/permissions/index.js +0 -103
  307. package/dist/plugins/index.d.ts +0 -46
  308. package/dist/plugins/index.js +0 -1069
  309. package/dist/policies/index.js +0 -196
  310. package/dist/presets/index.js +0 -384
  311. package/dist/presets/multiTenant.d.ts +0 -39
  312. package/dist/presets/multiTenant.js +0 -112
  313. package/dist/registry/index.d.ts +0 -16
  314. package/dist/registry/index.js +0 -253
  315. package/dist/testing/index.d.ts +0 -618
  316. package/dist/testing/index.js +0 -48015
  317. package/dist/types/index.d.ts +0 -4
  318. package/dist/types/index.js +0 -8
  319. package/dist/types-B99TBmFV.d.ts +0 -76
  320. package/dist/types-zpN48n6B.d.ts +0 -143
  321. package/dist/utils/index.d.ts +0 -679
  322. package/dist/utils/index.js +0 -914
@@ -1,1322 +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
- populate?: string | string[] | Record<string, unknown>;
557
- select?: string | string[] | Record<string, 0 | 1>;
558
- filters?: Record<string, unknown>;
559
- search?: string;
560
- lean?: boolean;
561
- after?: string;
562
- user?: unknown;
563
- organizationId?: string;
564
- context?: Record<string, unknown>;
565
- /** Allow additional options */
566
- [key: string]: unknown;
567
- }
568
- /**
569
- * Parsed query result from QueryParser
570
- * Includes pagination, sorting, filtering, etc.
571
- */
572
- interface ParsedQuery {
573
- filters?: Record<string, unknown>;
574
- limit?: number;
575
- sort?: string | Record<string, 1 | -1>;
576
- populate?: string | string[] | Record<string, unknown>;
577
- search?: string;
578
- page?: number;
579
- after?: string;
580
- select?: string | string[] | Record<string, 0 | 1>;
581
- }
582
- /**
583
- * Query Parser Interface
584
- * Implement this to create custom query parsers
585
- *
586
- * @example MongoKit QueryParser
587
- * ```typescript
588
- * import { QueryParser } from '@classytic/mongokit';
589
- * const queryParser = new QueryParser();
590
- * ```
591
- */
592
- interface QueryParserInterface {
593
- parse(query: Record<string, unknown> | null | undefined): ParsedQuery;
594
- /**
595
- * Optional: Export OpenAPI schema for query parameters
596
- * Use this to document query parameters in OpenAPI/Swagger
597
- */
598
- getQuerySchema?(): {
599
- type: 'object';
600
- properties: Record<string, unknown>;
601
- required?: string[];
602
- };
603
- }
604
- interface FastifyRequestExtras {
605
- user?: unknown;
606
- organizationId?: string;
607
- }
608
- interface RequestWithExtras extends Omit<FastifyRequest, 'user'> {
609
- /**
610
- * Arc metadata - set by createCrudRouter
611
- * Contains resource configuration and schema options
612
- */
613
- arc?: {
614
- resourceName?: string;
615
- schemaOptions?: RouteSchemaOptions;
616
- permissions?: ResourcePermissions;
617
- };
618
- user?: unknown;
619
- organizationId?: string;
620
- context?: Record<string, unknown>;
621
- _policyFilters?: Record<string, unknown>;
622
- fieldMask?: string[];
623
- _ownershipCheck?: Record<string, unknown>;
624
- }
625
- type FastifyWithAuth = FastifyInstance & {
626
- authenticate: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
627
- };
628
- /**
629
- * Arc core decorator interface
630
- * Added by arcCorePlugin to provide instance-scoped hooks and registry
631
- */
632
- interface ArcDecorator {
633
- /** Instance-scoped hook system */
634
- hooks: HookSystem;
635
- /** Instance-scoped resource registry */
636
- registry: ResourceRegistry;
637
- /** Whether event emission is enabled */
638
- emitEvents: boolean;
639
- }
640
- /**
641
- * Events decorator interface
642
- * Added by eventPlugin to provide event pub/sub
643
- */
644
- interface EventsDecorator {
645
- /** Publish an event */
646
- publish: <T>(type: string, payload: T, meta?: Partial<{
647
- id: string;
648
- timestamp: Date;
649
- }>) => Promise<void>;
650
- /** Subscribe to events */
651
- subscribe: (pattern: string, handler: (event: unknown) => void | Promise<void>) => Promise<() => void>;
652
- /** Get transport name */
653
- transportName: string;
654
- }
655
- /**
656
- * Fastify instance with Arc decorators
657
- * Arc adds these decorators via plugins/presets
658
- */
659
- type FastifyWithDecorators = FastifyInstance & {
660
- arc?: ArcDecorator;
661
- events?: EventsDecorator;
662
- authenticate?: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
663
- organizationScoped?: (options?: {
664
- required?: boolean;
665
- }) => RouteHandlerMethod;
666
- [key: string]: unknown;
667
- };
668
- interface OwnershipCheck {
669
- field: string;
670
- userField?: string;
671
- }
672
-
673
- interface ResourceConfig<TDoc = AnyRecord> {
674
- name: string;
675
- displayName?: string;
676
- tag?: string;
677
- prefix?: string;
678
- adapter?: DataAdapter<TDoc>;
679
- /** Controller instance - accepts any object with CRUD methods */
680
- controller?: IController<TDoc> | ControllerLike | Record<string, any> | object;
681
- queryParser?: unknown;
682
- permissions?: ResourcePermissions;
683
- schemaOptions?: RouteSchemaOptions;
684
- openApiSchemas?: OpenApiSchemas;
685
- customSchemas?: Partial<CrudSchemas>;
686
- presets?: Array<string | PresetResult | {
687
- name: string;
688
- [key: string]: unknown;
689
- }>;
690
- hooks?: ResourceHooks;
691
- middlewares?: MiddlewareConfig;
692
- additionalRoutes?: AdditionalRoute[];
693
- disableCrud?: boolean;
694
- disableDefaultRoutes?: boolean;
695
- disabledRoutes?: CrudRouteKey[];
696
- organizationScoped?: boolean;
697
- module?: string;
698
- events?: Record<string, EventDefinition>;
699
- skipValidation?: boolean;
700
- skipRegistry?: boolean;
701
- _appliedPresets?: string[];
702
- }
703
- /**
704
- * Resource-level permissions
705
- * ONLY PermissionCheck functions allowed - no string arrays
706
- */
707
- interface ResourcePermissions {
708
- list?: PermissionCheck;
709
- get?: PermissionCheck;
710
- create?: PermissionCheck;
711
- update?: PermissionCheck;
712
- delete?: PermissionCheck;
713
- }
714
- interface ResourceHooks {
715
- beforeCreate?: (data: AnyRecord) => Promise<AnyRecord> | AnyRecord;
716
- afterCreate?: (doc: AnyRecord) => Promise<void> | void;
717
- beforeUpdate?: (id: string, data: AnyRecord) => Promise<AnyRecord> | AnyRecord;
718
- afterUpdate?: (doc: AnyRecord) => Promise<void> | void;
719
- beforeDelete?: (id: string) => Promise<void> | void;
720
- afterDelete?: (id: string) => Promise<void> | void;
721
- }
722
- /**
723
- * Additional route definition for custom endpoints
724
- */
725
- interface AdditionalRoute {
726
- /** HTTP method */
727
- method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
728
- /** Route path (relative to resource prefix) */
729
- path: string;
730
- /**
731
- * Handler - string (controller method name) or function
732
- * Function can be Fastify handler or any (request, reply) => Promise<any>
733
- */
734
- handler: string | RouteHandlerMethod | ((request: any, reply: any) => any);
735
- /** Permission check - REQUIRED */
736
- permissions: PermissionCheck;
737
- /**
738
- * Handler type - REQUIRED, no auto-detection
739
- * true = ControllerHandler (receives context object)
740
- * false = FastifyHandler (receives request, reply)
741
- */
742
- wrapHandler: boolean;
743
- /** OpenAPI summary */
744
- summary?: string;
745
- /** OpenAPI description */
746
- description?: string;
747
- /** OpenAPI tags */
748
- tags?: string[];
749
- /**
750
- * Custom route-level middleware
751
- * Can be an array of handlers or a function that receives fastify and returns handlers
752
- * @example
753
- * // Direct array
754
- * preHandler: [myMiddleware]
755
- * // Function that receives fastify (for accessing decorators)
756
- * preHandler: (fastify) => [fastify.customerContext({ required: true })]
757
- */
758
- preHandler?: RouteHandlerMethod[] | ((fastify: any) => RouteHandlerMethod[]);
759
- /** Fastify route schema */
760
- schema?: Record<string, unknown>;
761
- }
762
- interface RouteSchemaOptions {
763
- hiddenFields?: string[];
764
- readonlyFields?: string[];
765
- requiredFields?: string[];
766
- optionalFields?: string[];
767
- excludeFields?: string[];
768
- fieldRules?: Record<string, {
769
- systemManaged?: boolean;
770
- [key: string]: unknown;
771
- }>;
772
- query?: Record<string, unknown>;
773
- }
774
- interface FieldRule {
775
- field: string;
776
- required?: boolean;
777
- readonly?: boolean;
778
- hidden?: boolean;
779
- }
780
- /**
781
- * CRUD Route Schemas (Fastify Native Format)
782
- *
783
- * @example
784
- * {
785
- * list: {
786
- * querystring: { type: 'object', properties: { page: { type: 'number' } } },
787
- * response: { 200: { type: 'object', properties: { docs: { type: 'array' } } } }
788
- * },
789
- * create: {
790
- * body: { type: 'object', properties: { name: { type: 'string' } } },
791
- * response: { 201: { type: 'object' } }
792
- * }
793
- * }
794
- */
795
- interface CrudSchemas {
796
- /** GET / - List all resources */
797
- list?: {
798
- querystring?: Record<string, unknown>;
799
- response?: Record<number, unknown>;
800
- [key: string]: unknown;
801
- };
802
- /** GET /:id - Get single resource */
803
- get?: {
804
- params?: Record<string, unknown>;
805
- response?: Record<number, unknown>;
806
- [key: string]: unknown;
807
- };
808
- /** POST / - Create resource */
809
- create?: {
810
- body?: Record<string, unknown>;
811
- response?: Record<number, unknown>;
812
- [key: string]: unknown;
813
- };
814
- /** PATCH /:id - Update resource */
815
- update?: {
816
- params?: Record<string, unknown>;
817
- body?: Record<string, unknown>;
818
- response?: Record<number, unknown>;
819
- [key: string]: unknown;
820
- };
821
- /** DELETE /:id - Delete resource */
822
- delete?: {
823
- params?: Record<string, unknown>;
824
- response?: Record<number, unknown>;
825
- [key: string]: unknown;
826
- };
827
- [key: string]: unknown;
828
- }
829
- interface OpenApiSchemas {
830
- entity?: unknown;
831
- createBody?: unknown;
832
- updateBody?: unknown;
833
- params?: unknown;
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;
855
- [key: string]: unknown;
856
- }
857
- /** Handler for middleware functions */
858
- type MiddlewareHandler = (request: RequestWithExtras, reply: FastifyReply) => Promise<unknown>;
859
- type CrudRouteKey = 'list' | 'get' | 'create' | 'update' | 'delete';
860
- interface MiddlewareConfig {
861
- list?: MiddlewareHandler[];
862
- get?: MiddlewareHandler[];
863
- create?: MiddlewareHandler[];
864
- update?: MiddlewareHandler[];
865
- delete?: MiddlewareHandler[];
866
- [key: string]: MiddlewareHandler[] | undefined;
867
- }
868
- /**
869
- * JWT utilities provided to authenticator
870
- * Arc provides these helpers, app uses them as needed
871
- */
872
- interface JwtContext {
873
- /** Verify a JWT token and return decoded payload */
874
- verify: <T = Record<string, unknown>>(token: string) => T;
875
- /** Sign a payload and return JWT token */
876
- sign: (payload: Record<string, unknown>, options?: {
877
- expiresIn?: string;
878
- }) => string;
879
- /** Decode without verification (for inspection) */
880
- decode: <T = Record<string, unknown>>(token: string) => T | null;
881
- }
882
- /**
883
- * Context passed to app's authenticator function
884
- */
885
- interface AuthenticatorContext {
886
- /** JWT utilities (available if jwt.secret provided) */
887
- jwt: JwtContext | null;
888
- /** Fastify instance for advanced use cases */
889
- fastify: FastifyInstance;
890
- }
891
- /**
892
- * App-provided authenticator function
893
- *
894
- * Arc calls this for every non-public route.
895
- * App has FULL control over authentication logic.
896
- *
897
- * @example
898
- * ```typescript
899
- * // Simple JWT auth
900
- * authenticate: async (request, { jwt }) => {
901
- * const token = request.headers.authorization?.split(' ')[1];
902
- * if (!token || !jwt) return null;
903
- * const decoded = jwt.verify(token);
904
- * return userRepo.findById(decoded.id);
905
- * }
906
- *
907
- * // Multi-strategy (JWT + API Key)
908
- * authenticate: async (request, { jwt }) => {
909
- * const apiKey = request.headers['x-api-key'];
910
- * if (apiKey) {
911
- * const result = await apiKeyService.verify(apiKey);
912
- * if (result) return { _id: result.userId, isApiKey: true };
913
- * }
914
- * const token = request.headers.authorization?.split(' ')[1];
915
- * if (token && jwt) {
916
- * const decoded = jwt.verify(token);
917
- * return userRepo.findById(decoded.id);
918
- * }
919
- * return null;
920
- * }
921
- * ```
922
- */
923
- type Authenticator = (request: FastifyRequest, context: AuthenticatorContext) => Promise<any | null> | any | null;
924
- /**
925
- * Token pair returned by issueTokens helper
926
- */
927
- interface TokenPair {
928
- /** Access token (JWT) */
929
- accessToken: string;
930
- /** Refresh token (JWT with longer expiry) */
931
- refreshToken?: string;
932
- /** Access token expiry in seconds */
933
- expiresIn: number;
934
- /** Refresh token expiry in seconds */
935
- refreshExpiresIn?: number;
936
- /** Token type (always 'Bearer') */
937
- tokenType: 'Bearer';
938
- }
939
- /**
940
- * Auth helpers available on fastify.auth
941
- *
942
- * @example
943
- * ```typescript
944
- * // In login handler
945
- * const user = await userRepo.findByEmail(email);
946
- * if (!user || !await bcrypt.compare(password, user.password)) {
947
- * return reply.code(401).send({ error: 'Invalid credentials' });
948
- * }
949
- *
950
- * const tokens = fastify.auth.issueTokens({
951
- * id: user._id,
952
- * email: user.email,
953
- * roles: user.roles,
954
- * });
955
- *
956
- * return { success: true, ...tokens, user };
957
- * ```
958
- */
959
- interface AuthHelpers {
960
- /** JWT utilities (if configured) */
961
- jwt: JwtContext | null;
962
- /**
963
- * Issue access + refresh tokens for a user
964
- * App calls this after validating credentials
965
- */
966
- issueTokens: (payload: Record<string, unknown>, options?: {
967
- expiresIn?: string;
968
- refreshExpiresIn?: string;
969
- }) => TokenPair;
970
- /**
971
- * Verify a refresh token and return decoded payload
972
- */
973
- verifyRefreshToken: <T = Record<string, unknown>>(token: string) => T;
974
- }
975
- interface ServiceContext {
976
- user?: unknown;
977
- organizationId?: string;
978
- requestId?: string;
979
- select?: string[] | Record<string, 0 | 1>;
980
- populate?: string | string[];
981
- lean?: boolean;
982
- }
983
- interface PresetHook {
984
- operation: 'create' | 'update' | 'delete' | 'read' | 'list';
985
- phase: 'before' | 'after';
986
- handler: (ctx: any) => void | Promise<void> | AnyRecord | Promise<AnyRecord>;
987
- priority?: number;
988
- }
989
- interface PresetResult {
990
- name: string;
991
- additionalRoutes?: AdditionalRoute[] | ((permissions: ResourcePermissions) => AdditionalRoute[]);
992
- middlewares?: MiddlewareConfig;
993
- schemaOptions?: RouteSchemaOptions;
994
- controllerOptions?: Record<string, unknown>;
995
- hooks?: PresetHook[];
996
- }
997
- type PresetFunction = (config: ResourceConfig) => PresetResult;
998
- interface GracefulShutdownOptions {
999
- timeout?: number;
1000
- onShutdown?: () => Promise<void> | void;
1001
- signals?: NodeJS.Signals[];
1002
- logEvents?: boolean;
1003
- }
1004
- interface RequestIdOptions {
1005
- headerName?: string;
1006
- generator?: () => string;
1007
- }
1008
- interface HealthOptions {
1009
- path?: string;
1010
- check?: () => Promise<any>;
1011
- }
1012
- interface HealthCheck {
1013
- healthy: boolean;
1014
- timestamp: string;
1015
- [key: string]: unknown;
1016
- }
1017
- /**
1018
- * Auth Plugin Options - Clean, Minimal Configuration
1019
- *
1020
- * Arc provides JWT infrastructure and calls your authenticator.
1021
- * You control ALL authentication logic.
1022
- *
1023
- * @example
1024
- * ```typescript
1025
- * // Minimal: just JWT (uses default jwtVerify)
1026
- * auth: {
1027
- * jwt: { secret: process.env.JWT_SECRET },
1028
- * }
1029
- *
1030
- * // With custom authenticator (recommended)
1031
- * auth: {
1032
- * jwt: { secret: process.env.JWT_SECRET },
1033
- * authenticate: async (request, { jwt }) => {
1034
- * const token = request.headers.authorization?.split(' ')[1];
1035
- * if (!token) return null;
1036
- * const decoded = jwt.verify(token);
1037
- * return userRepo.findById(decoded.id);
1038
- * },
1039
- * }
1040
- *
1041
- * // Multi-strategy (JWT + API Key)
1042
- * auth: {
1043
- * jwt: { secret: process.env.JWT_SECRET },
1044
- * authenticate: async (request, { jwt }) => {
1045
- * // Try API key first (faster)
1046
- * const apiKey = request.headers['x-api-key'];
1047
- * if (apiKey) {
1048
- * const result = await apiKeyService.verify(apiKey);
1049
- * if (result) return { _id: result.userId, isApiKey: true };
1050
- * }
1051
- * // Try JWT
1052
- * const token = request.headers.authorization?.split(' ')[1];
1053
- * if (token) {
1054
- * const decoded = jwt.verify(token);
1055
- * return userRepo.findById(decoded.id);
1056
- * }
1057
- * return null;
1058
- * },
1059
- * onFailure: (request, reply) => {
1060
- * reply.code(401).send({
1061
- * success: false,
1062
- * error: 'Authentication required',
1063
- * message: 'Use Bearer token or X-API-Key header',
1064
- * });
1065
- * },
1066
- * }
1067
- * ```
1068
- */
1069
- interface AuthPluginOptions {
1070
- /**
1071
- * JWT configuration (optional but recommended)
1072
- * If provided, jwt utilities are available in authenticator context
1073
- */
1074
- jwt?: {
1075
- /** JWT secret (required for JWT features) */
1076
- secret: string;
1077
- /** Access token expiry (default: '15m') */
1078
- expiresIn?: string;
1079
- /** Refresh token secret (defaults to main secret) */
1080
- refreshSecret?: string;
1081
- /** Refresh token expiry (default: '7d') */
1082
- refreshExpiresIn?: string;
1083
- /** Additional @fastify/jwt sign options */
1084
- sign?: Record<string, unknown>;
1085
- /** Additional @fastify/jwt verify options */
1086
- verify?: Record<string, unknown>;
1087
- };
1088
- /**
1089
- * Custom authenticator function (recommended)
1090
- *
1091
- * Arc calls this for non-public routes.
1092
- * Return user object to authenticate, null/undefined to reject.
1093
- *
1094
- * If not provided and jwt.secret is set, uses default jwtVerify.
1095
- */
1096
- authenticate?: Authenticator;
1097
- /**
1098
- * Custom auth failure handler
1099
- * Customize the 401 response when authentication fails
1100
- */
1101
- onFailure?: (request: FastifyRequest, reply: FastifyReply, error?: Error) => void | Promise<void>;
1102
- /**
1103
- * Property name to store user on request (default: 'user')
1104
- */
1105
- userProperty?: string;
1106
- }
1107
- interface OrgScopeOptions {
1108
- enabled?: boolean;
1109
- header?: string;
1110
- headerName?: string;
1111
- queryParam?: string;
1112
- bypassRoles?: string[];
1113
- userOrgsPath?: string;
1114
- validateMembership?: (user: unknown, orgId: string) => Promise<boolean> | boolean;
1115
- }
1116
- interface IntrospectionPluginOptions {
1117
- path?: string;
1118
- prefix?: string;
1119
- enabled?: boolean;
1120
- authRoles?: string[];
1121
- }
1122
- interface CrudRouterOptions {
1123
- /** Route prefix */
1124
- prefix?: string;
1125
- /** Permission checks for CRUD operations */
1126
- permissions?: ResourcePermissions;
1127
- /** OpenAPI tag for grouping routes */
1128
- tag?: string;
1129
- /** JSON schemas for CRUD operations */
1130
- schemas?: Partial<CrudSchemas>;
1131
- /** Middlewares for each CRUD operation */
1132
- middlewares?: MiddlewareConfig;
1133
- /** Additional custom routes (from presets or user-defined) */
1134
- additionalRoutes?: AdditionalRoute[];
1135
- /** Disable all default CRUD routes */
1136
- disableDefaultRoutes?: boolean;
1137
- /** Disable specific CRUD routes */
1138
- disabledRoutes?: CrudRouteKey[];
1139
- /** Enable organization-scoped filtering */
1140
- organizationScoped?: boolean;
1141
- /** Resource name for lifecycle hooks */
1142
- resourceName?: string;
1143
- /** Schema generation options */
1144
- schemaOptions?: RouteSchemaOptions;
1145
- }
1146
- interface ResourceMetadata {
1147
- name: string;
1148
- displayName?: string;
1149
- tag?: string;
1150
- prefix: string;
1151
- module?: string;
1152
- permissions?: ResourcePermissions;
1153
- presets: string[];
1154
- additionalRoutes?: AdditionalRoute[];
1155
- routes: Array<{
1156
- method: string;
1157
- path: string;
1158
- handler?: string;
1159
- operation?: string;
1160
- summary?: string;
1161
- }>;
1162
- events?: string[];
1163
- }
1164
- interface RegistryEntry extends ResourceMetadata {
1165
- plugin: unknown;
1166
- adapter?: {
1167
- type: string;
1168
- name: string;
1169
- } | null;
1170
- events?: string[];
1171
- disableDefaultRoutes?: boolean;
1172
- openApiSchemas?: OpenApiSchemas;
1173
- registeredAt?: string;
1174
- }
1175
- interface RegistryStats {
1176
- total?: number;
1177
- totalResources: number;
1178
- byTag?: Record<string, number>;
1179
- byModule?: Record<string, number>;
1180
- presetUsage?: Record<string, number>;
1181
- totalRoutes?: number;
1182
- totalEvents?: number;
1183
- }
1184
- interface IntrospectionData {
1185
- resources: ResourceMetadata[];
1186
- stats: RegistryStats;
1187
- generatedAt?: string;
1188
- }
1189
- interface EventDefinition {
1190
- name: string;
1191
- handler: (data: unknown) => Promise<void> | void;
1192
- schema?: Record<string, unknown>;
1193
- description?: string;
1194
- }
1195
- interface ConfigError {
1196
- field: string;
1197
- message: string;
1198
- code?: string;
1199
- }
1200
- interface ValidationResult$1 {
1201
- valid: boolean;
1202
- errors: ConfigError[];
1203
- }
1204
- interface ValidateOptions {
1205
- strict?: boolean;
1206
- }
1207
-
1208
- /**
1209
- * Infer document type from DataAdapter or ResourceConfig
1210
- */
1211
- type InferDocType<T> = T extends DataAdapter<infer D> ? D : T extends ResourceConfig<infer D> ? D : never;
1212
- type InferResourceDoc<T> = T extends ResourceConfig<infer D> ? D : never;
1213
- type TypedResourceConfig<TDoc> = ResourceConfig<TDoc>;
1214
- type TypedController<TDoc> = IController<TDoc>;
1215
- type TypedRepository<TDoc> = CrudRepository<TDoc>;
1216
- interface BaseControllerOptions {
1217
- /** Query parser instance */
1218
- queryParser: QueryParserInterface;
1219
- /** Schema generation options */
1220
- schemaOptions?: RouteSchemaOptions;
1221
- /** Maximum items per page */
1222
- maxLimit?: number;
1223
- /** Default items per page */
1224
- defaultLimit?: number;
1225
- /** Default sort field */
1226
- defaultSort?: string;
1227
- /** Resource name for hooks */
1228
- resourceName?: string;
1229
- /** Disable event emission */
1230
- disableEvents?: boolean;
1231
- }
1232
-
1233
- /**
1234
- * Data Adapter Interface - Database Abstraction Layer
1235
- *
1236
- * Core abstraction that allows Arc to work with any database.
1237
- * This is the ONLY contract between Arc and data persistence.
1238
- */
1239
-
1240
- /**
1241
- * Minimal repository interface for flexible adapter compatibility
1242
- * Accepts any object with CRUD method names
1243
- */
1244
- interface RepositoryLike {
1245
- getAll: unknown;
1246
- getById: unknown;
1247
- create: unknown;
1248
- update: unknown;
1249
- delete: unknown;
1250
- [key: string]: unknown;
1251
- }
1252
- interface DataAdapter<TDoc = unknown> {
1253
- /**
1254
- * Repository implementing CRUD operations
1255
- * Accepts CrudRepository, MongoKit Repository, or any compatible object
1256
- */
1257
- repository: CrudRepository<TDoc> | RepositoryLike;
1258
- /** Adapter identifier for introspection */
1259
- readonly type: 'mongoose' | 'prisma' | 'drizzle' | 'typeorm' | 'custom';
1260
- /** Human-readable name */
1261
- readonly name: string;
1262
- /**
1263
- * Generate OpenAPI schemas for CRUD operations
1264
- *
1265
- * This method allows each adapter to generate schemas specific to its ORM/database.
1266
- * For example, Mongoose adapter can use mongokit to generate schemas from Mongoose models.
1267
- *
1268
- * @param options - Schema generation options (field rules, populate settings, etc.)
1269
- * @returns OpenAPI schemas for CRUD operations or null if not supported
1270
- */
1271
- generateSchemas?(options?: RouteSchemaOptions): OpenApiSchemas | null;
1272
- /** Extract schema metadata for OpenAPI/introspection */
1273
- getSchemaMetadata?(): SchemaMetadata | null;
1274
- /** Validate data against schema before persistence */
1275
- validate?(data: unknown): Promise<ValidationResult> | ValidationResult;
1276
- /** Health check for database connection */
1277
- healthCheck?(): Promise<boolean>;
1278
- /** Close/cleanup resources */
1279
- close?(): Promise<void>;
1280
- }
1281
- interface SchemaMetadata {
1282
- name: string;
1283
- fields: Record<string, FieldMetadata>;
1284
- indexes?: Array<{
1285
- fields: string[];
1286
- unique?: boolean;
1287
- sparse?: boolean;
1288
- }>;
1289
- relations?: Record<string, RelationMetadata>;
1290
- }
1291
- interface FieldMetadata {
1292
- type: 'string' | 'number' | 'boolean' | 'date' | 'object' | 'array' | 'objectId' | 'enum';
1293
- required?: boolean;
1294
- unique?: boolean;
1295
- default?: unknown;
1296
- enum?: Array<string | number>;
1297
- min?: number;
1298
- max?: number;
1299
- minLength?: number;
1300
- maxLength?: number;
1301
- pattern?: string;
1302
- description?: string;
1303
- ref?: string;
1304
- array?: boolean;
1305
- }
1306
- interface RelationMetadata {
1307
- type: 'one-to-one' | 'one-to-many' | 'many-to-many';
1308
- target: string;
1309
- foreignKey?: string;
1310
- through?: string;
1311
- }
1312
- interface ValidationResult {
1313
- valid: boolean;
1314
- errors?: Array<{
1315
- field: string;
1316
- message: string;
1317
- code?: string;
1318
- }>;
1319
- }
1320
- type AdapterFactory<TDoc> = (config: unknown) => DataAdapter<TDoc>;
1321
-
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 };