@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.
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 +194 -68
  269. package/dist/BaseController-DVAiHxEQ.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-CsShQdyP.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 -2786
  286. package/dist/createApp-Ce9wl8W9.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 -1652
  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-B4t03KQ0.d.ts +0 -1366
  299. package/dist/index.d.ts +0 -135
  300. package/dist/index.js +0 -4756
  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 -48020
  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-BvckRbs2.d.ts +0 -143
  321. package/dist/utils/index.d.ts +0 -679
  322. package/dist/utils/index.js +0 -931
@@ -0,0 +1,250 @@
1
+ import { s as DEFAULT_UPDATE_METHOD, t as CRUD_OPERATIONS } from "./constants-DdXFXQtN.mjs";
2
+
3
+ //#region src/registry/ResourceRegistry.ts
4
+ var ResourceRegistry = class {
5
+ _resources;
6
+ _frozen;
7
+ constructor() {
8
+ this._resources = /* @__PURE__ */ new Map();
9
+ this._frozen = false;
10
+ }
11
+ /**
12
+ * Register a resource
13
+ */
14
+ register(resource, options = {}) {
15
+ if (this._frozen) throw new Error(`Registry frozen. Cannot register '${resource.name}' after startup.`);
16
+ if (this._resources.has(resource.name)) throw new Error(`Resource '${resource.name}' already registered.`);
17
+ const entry = {
18
+ name: resource.name,
19
+ displayName: resource.displayName,
20
+ tag: resource.tag,
21
+ prefix: resource.prefix,
22
+ module: options.module ?? void 0,
23
+ adapter: resource.adapter ? {
24
+ type: resource.adapter.type,
25
+ name: resource.adapter.name
26
+ } : null,
27
+ permissions: resource.permissions,
28
+ presets: resource._appliedPresets ?? [],
29
+ routes: [],
30
+ additionalRoutes: resource.additionalRoutes.map((r) => ({
31
+ method: r.method,
32
+ path: r.path,
33
+ handler: typeof r.handler === "string" ? r.handler : r.handler.name || "anonymous",
34
+ operation: r.operation,
35
+ summary: r.summary,
36
+ description: r.description,
37
+ permissions: r.permissions,
38
+ wrapHandler: r.wrapHandler,
39
+ schema: r.schema
40
+ })),
41
+ events: Object.keys(resource.events ?? {}),
42
+ registeredAt: (/* @__PURE__ */ new Date()).toISOString(),
43
+ disableDefaultRoutes: resource.disableDefaultRoutes,
44
+ updateMethod: resource.updateMethod,
45
+ disabledRoutes: resource.disabledRoutes,
46
+ openApiSchemas: options.openApiSchemas,
47
+ fieldPermissions: extractFieldPermissions(resource.fields),
48
+ pipelineSteps: extractPipelineSteps(resource.pipe),
49
+ rateLimit: resource.rateLimit,
50
+ plugin: resource.toPlugin()
51
+ };
52
+ this._resources.set(resource.name, entry);
53
+ return this;
54
+ }
55
+ /**
56
+ * Get resource by name
57
+ */
58
+ get(name) {
59
+ return this._resources.get(name);
60
+ }
61
+ /**
62
+ * Get all resources
63
+ */
64
+ getAll() {
65
+ return Array.from(this._resources.values());
66
+ }
67
+ /**
68
+ * Get resources by module
69
+ */
70
+ getByModule(moduleName) {
71
+ return this.getAll().filter((r) => r.module === moduleName);
72
+ }
73
+ /**
74
+ * Get resources by preset
75
+ */
76
+ getByPreset(presetName) {
77
+ return this.getAll().filter((r) => r.presets.includes(presetName));
78
+ }
79
+ /**
80
+ * Check if resource exists
81
+ */
82
+ has(name) {
83
+ return this._resources.has(name);
84
+ }
85
+ /**
86
+ * Get registry statistics
87
+ */
88
+ getStats() {
89
+ const resources = this.getAll();
90
+ const presetCounts = {};
91
+ for (const r of resources) for (const preset of r.presets) presetCounts[preset] = (presetCounts[preset] ?? 0) + 1;
92
+ return {
93
+ totalResources: resources.length,
94
+ byModule: this._groupBy(resources, "module"),
95
+ presetUsage: presetCounts,
96
+ totalRoutes: resources.reduce((sum, r) => {
97
+ if (r.disableDefaultRoutes) return sum + (r.additionalRoutes?.length ?? 0);
98
+ const disabledSet = new Set(r.disabledRoutes ?? []);
99
+ let defaultCount = CRUD_OPERATIONS.filter((route) => !disabledSet.has(route)).length;
100
+ if (!disabledSet.has("update") && r.updateMethod === "both") defaultCount += 1;
101
+ return sum + defaultCount + (r.additionalRoutes?.length ?? 0);
102
+ }, 0),
103
+ totalEvents: resources.reduce((sum, r) => sum + (r.events?.length ?? 0), 0)
104
+ };
105
+ }
106
+ /**
107
+ * Get full introspection data
108
+ */
109
+ getIntrospection() {
110
+ return {
111
+ resources: this.getAll().map((r) => {
112
+ const disabledSet = new Set(r.disabledRoutes ?? []);
113
+ const updateMethod = r.updateMethod ?? DEFAULT_UPDATE_METHOD;
114
+ const defaultRoutes = r.disableDefaultRoutes ? [] : [
115
+ ...!disabledSet.has("list") ? [{
116
+ method: "GET",
117
+ path: r.prefix,
118
+ operation: "list"
119
+ }] : [],
120
+ ...!disabledSet.has("get") ? [{
121
+ method: "GET",
122
+ path: `${r.prefix}/:id`,
123
+ operation: "get"
124
+ }] : [],
125
+ ...!disabledSet.has("create") ? [{
126
+ method: "POST",
127
+ path: r.prefix,
128
+ operation: "create"
129
+ }] : [],
130
+ ...!disabledSet.has("update") ? updateMethod === "both" ? [{
131
+ method: "PUT",
132
+ path: `${r.prefix}/:id`,
133
+ operation: "update"
134
+ }, {
135
+ method: "PATCH",
136
+ path: `${r.prefix}/:id`,
137
+ operation: "update"
138
+ }] : [{
139
+ method: updateMethod,
140
+ path: `${r.prefix}/:id`,
141
+ operation: "update"
142
+ }] : [],
143
+ ...!disabledSet.has("delete") ? [{
144
+ method: "DELETE",
145
+ path: `${r.prefix}/:id`,
146
+ operation: "delete"
147
+ }] : []
148
+ ];
149
+ return {
150
+ name: r.name,
151
+ displayName: r.displayName,
152
+ prefix: r.prefix,
153
+ module: r.module,
154
+ presets: r.presets,
155
+ permissions: r.permissions,
156
+ routes: [...defaultRoutes, ...r.additionalRoutes?.map((ar) => ({
157
+ method: ar.method,
158
+ path: `${r.prefix}${ar.path}`,
159
+ operation: ar.operation ?? (typeof ar.handler === "string" ? ar.handler : "custom"),
160
+ handler: typeof ar.handler === "string" ? ar.handler : void 0,
161
+ summary: ar.summary
162
+ })) ?? []],
163
+ events: r.events
164
+ };
165
+ }),
166
+ stats: this.getStats(),
167
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString()
168
+ };
169
+ }
170
+ /**
171
+ * Freeze registry (prevent further registrations)
172
+ */
173
+ freeze() {
174
+ this._frozen = true;
175
+ }
176
+ /**
177
+ * Check if frozen
178
+ */
179
+ isFrozen() {
180
+ return this._frozen;
181
+ }
182
+ /**
183
+ * Unfreeze registry (allow new registrations)
184
+ */
185
+ unfreeze() {
186
+ this._frozen = false;
187
+ }
188
+ /**
189
+ * Reset registry — clear all resources and unfreeze
190
+ */
191
+ reset() {
192
+ this._resources.clear();
193
+ this._frozen = false;
194
+ }
195
+ /** @internal Alias for unfreeze() */
196
+ _unfreeze() {
197
+ this.unfreeze();
198
+ }
199
+ /** @internal Alias for reset() */
200
+ _clear() {
201
+ this.reset();
202
+ }
203
+ /**
204
+ * Group by key
205
+ */
206
+ _groupBy(arr, key) {
207
+ const result = {};
208
+ for (const item of arr) {
209
+ const k = String(item[key] ?? "uncategorized");
210
+ result[k] = (result[k] ?? 0) + 1;
211
+ }
212
+ return result;
213
+ }
214
+ };
215
+ function extractFieldPermissions(fields) {
216
+ if (!fields || Object.keys(fields).length === 0) return void 0;
217
+ const result = {};
218
+ for (const [field, perm] of Object.entries(fields)) {
219
+ const entry = { type: perm._type };
220
+ if (perm.roles?.length) entry.roles = perm.roles;
221
+ if (perm.redactValue !== void 0) entry.redactValue = perm.redactValue;
222
+ result[field] = entry;
223
+ }
224
+ return result;
225
+ }
226
+ function extractPipelineSteps(pipe) {
227
+ if (!pipe) return void 0;
228
+ const steps = [];
229
+ if (Array.isArray(pipe)) steps.push(...pipe);
230
+ else {
231
+ const seen = /* @__PURE__ */ new Set();
232
+ for (const opSteps of Object.values(pipe)) if (Array.isArray(opSteps)) for (const step of opSteps) {
233
+ const key = `${step._type}:${step.name}`;
234
+ if (!seen.has(key)) {
235
+ seen.add(key);
236
+ steps.push(step);
237
+ }
238
+ }
239
+ }
240
+ if (steps.length === 0) return void 0;
241
+ return steps.map((s) => ({
242
+ type: s._type,
243
+ name: s.name,
244
+ operations: s.operations ? [...s.operations] : void 0
245
+ }));
246
+ }
247
+
248
+ //#endregion
249
+ export { ResourceRegistry as t };
250
+ //# sourceMappingURL=ResourceRegistry-DsN4KJjV.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResourceRegistry-DsN4KJjV.mjs","names":[],"sources":["../src/registry/ResourceRegistry.ts"],"sourcesContent":["/**\n * Resource Registry\n *\n * Singleton that tracks all registered resources for introspection.\n */\n\nimport type {\n IntrospectionData,\n OpenApiSchemas,\n RegistryEntry,\n RegistryStats,\n ResourcePermissions,\n} from '../types/index.js';\nimport type { ResourceDefinition } from '../core/defineResource.js';\nimport type { FieldPermissionMap } from '../permissions/fields.js';\nimport type { PipelineConfig, PipelineStep } from '../pipeline/types.js';\nimport { CRUD_OPERATIONS, DEFAULT_UPDATE_METHOD } from '../constants.js';\n\nexport interface RegisterOptions {\n module?: string;\n /** Pre-generated OpenAPI schemas */\n openApiSchemas?: OpenApiSchemas;\n}\n\nexport class ResourceRegistry {\n private _resources: Map<string, RegistryEntry>;\n private _frozen: boolean;\n\n constructor() {\n this._resources = new Map();\n this._frozen = false;\n }\n\n /**\n * Register a resource\n */\n register(resource: ResourceDefinition<unknown>, options: RegisterOptions = {}): this {\n if (this._frozen) {\n throw new Error(\n `Registry frozen. Cannot register '${resource.name}' after startup.`\n );\n }\n\n if (this._resources.has(resource.name)) {\n throw new Error(`Resource '${resource.name}' already registered.`);\n }\n\n const entry: RegistryEntry = {\n name: resource.name,\n displayName: resource.displayName,\n tag: resource.tag,\n prefix: resource.prefix,\n module: options.module ?? undefined,\n adapter: resource.adapter\n ? {\n type: resource.adapter.type,\n name: resource.adapter.name,\n }\n : null,\n permissions: resource.permissions as ResourcePermissions | undefined,\n presets: resource._appliedPresets ?? [],\n routes: [], // Populated later by getIntrospection()\n additionalRoutes: resource.additionalRoutes.map((r) => ({\n method: r.method,\n path: r.path,\n handler:\n typeof r.handler === 'string'\n ? r.handler\n : (r.handler as Function).name || 'anonymous',\n operation: r.operation,\n summary: r.summary,\n description: r.description,\n permissions: r.permissions,\n wrapHandler: r.wrapHandler,\n schema: r.schema, // Include schema for OpenAPI docs\n })),\n events: Object.keys(resource.events ?? {}),\n registeredAt: new Date().toISOString(),\n disableDefaultRoutes: resource.disableDefaultRoutes,\n updateMethod: resource.updateMethod,\n disabledRoutes: resource.disabledRoutes,\n openApiSchemas: options.openApiSchemas,\n fieldPermissions: extractFieldPermissions(resource.fields),\n pipelineSteps: extractPipelineSteps(resource.pipe),\n rateLimit: resource.rateLimit,\n plugin: resource.toPlugin(), // Store plugin factory\n };\n\n this._resources.set(resource.name, entry);\n return this;\n }\n\n /**\n * Get resource by name\n */\n get(name: string): RegistryEntry | undefined {\n return this._resources.get(name);\n }\n\n /**\n * Get all resources\n */\n getAll(): RegistryEntry[] {\n return Array.from(this._resources.values());\n }\n\n /**\n * Get resources by module\n */\n getByModule(moduleName: string): RegistryEntry[] {\n return this.getAll().filter((r) => r.module === moduleName);\n }\n\n /**\n * Get resources by preset\n */\n getByPreset(presetName: string): RegistryEntry[] {\n return this.getAll().filter((r) => r.presets.includes(presetName));\n }\n\n /**\n * Check if resource exists\n */\n has(name: string): boolean {\n return this._resources.has(name);\n }\n\n /**\n * Get registry statistics\n */\n getStats(): RegistryStats {\n const resources = this.getAll();\n const presetCounts: Record<string, number> = {};\n\n for (const r of resources) {\n for (const preset of r.presets) {\n presetCounts[preset] = (presetCounts[preset] ?? 0) + 1;\n }\n }\n\n return {\n totalResources: resources.length,\n byModule: this._groupBy(resources, 'module'),\n presetUsage: presetCounts,\n totalRoutes: resources.reduce((sum, r) => {\n if (r.disableDefaultRoutes) {\n return sum + (r.additionalRoutes?.length ?? 0);\n }\n const disabledSet = new Set(r.disabledRoutes ?? []);\n let defaultCount = CRUD_OPERATIONS.filter(route => !disabledSet.has(route)).length;\n // 'update' creates 2 routes when updateMethod is 'both' (PUT + PATCH)\n if (!disabledSet.has('update') && r.updateMethod === 'both') {\n defaultCount += 1;\n }\n return sum + defaultCount + (r.additionalRoutes?.length ?? 0);\n }, 0),\n totalEvents: resources.reduce((sum, r) => sum + (r.events?.length ?? 0), 0),\n };\n }\n\n /**\n * Get full introspection data\n */\n getIntrospection(): IntrospectionData {\n return {\n resources: this.getAll().map((r) => {\n // Build default routes accounting for disabledRoutes and updateMethod\n const disabledSet = new Set(r.disabledRoutes ?? []);\n const updateMethod = r.updateMethod ?? DEFAULT_UPDATE_METHOD;\n const defaultRoutes = r.disableDefaultRoutes ? [] : [\n ...(!disabledSet.has('list') ? [{ method: 'GET', path: r.prefix, operation: 'list' }] : []),\n ...(!disabledSet.has('get') ? [{ method: 'GET', path: `${r.prefix}/:id`, operation: 'get' }] : []),\n ...(!disabledSet.has('create') ? [{ method: 'POST', path: r.prefix, operation: 'create' }] : []),\n ...(!disabledSet.has('update') ? (\n updateMethod === 'both'\n ? [\n { method: 'PUT', path: `${r.prefix}/:id`, operation: 'update' },\n { method: 'PATCH', path: `${r.prefix}/:id`, operation: 'update' },\n ]\n : [{ method: updateMethod, path: `${r.prefix}/:id`, operation: 'update' }]\n ) : []),\n ...(!disabledSet.has('delete') ? [{ method: 'DELETE', path: `${r.prefix}/:id`, operation: 'delete' }] : []),\n ];\n\n return {\n name: r.name,\n displayName: r.displayName,\n prefix: r.prefix,\n module: r.module,\n presets: r.presets,\n permissions: r.permissions,\n routes: [\n ...defaultRoutes,\n ...(r.additionalRoutes?.map((ar) => ({\n method: ar.method,\n path: `${r.prefix}${ar.path}`,\n operation: ar.operation ?? (typeof ar.handler === 'string' ? ar.handler : 'custom'),\n handler: typeof ar.handler === 'string' ? ar.handler : undefined,\n summary: ar.summary,\n })) ?? []),\n ],\n events: r.events,\n };\n }),\n stats: this.getStats(),\n generatedAt: new Date().toISOString(),\n };\n }\n\n /**\n * Freeze registry (prevent further registrations)\n */\n freeze(): void {\n this._frozen = true;\n }\n\n /**\n * Check if frozen\n */\n isFrozen(): boolean {\n return this._frozen;\n }\n\n /**\n * Unfreeze registry (allow new registrations)\n */\n unfreeze(): void {\n this._frozen = false;\n }\n\n /**\n * Reset registry — clear all resources and unfreeze\n */\n reset(): void {\n this._resources.clear();\n this._frozen = false;\n }\n\n /** @internal Alias for unfreeze() */\n _unfreeze(): void {\n this.unfreeze();\n }\n\n /** @internal Alias for reset() */\n _clear(): void {\n this.reset();\n }\n\n /**\n * Group by key\n */\n private _groupBy(\n arr: RegistryEntry[],\n key: keyof RegistryEntry\n ): Record<string, number> {\n const result: Record<string, number> = {};\n for (const item of arr) {\n const k = String(item[key] ?? 'uncategorized');\n result[k] = (result[k] ?? 0) + 1;\n }\n return result;\n }\n}\n\nexport default ResourceRegistry;\n\n// ---------------------------------------------------------------------------\n// Helpers for extracting v2.0 metadata\n// ---------------------------------------------------------------------------\n\nfunction extractFieldPermissions(\n fields?: FieldPermissionMap,\n): RegistryEntry['fieldPermissions'] {\n if (!fields || Object.keys(fields).length === 0) return undefined;\n\n const result: NonNullable<RegistryEntry['fieldPermissions']> = {};\n for (const [field, perm] of Object.entries(fields)) {\n const entry: { type: string; roles?: readonly string[]; redactValue?: unknown } = {\n type: perm._type,\n };\n if (perm.roles?.length) entry.roles = perm.roles;\n if (perm.redactValue !== undefined) entry.redactValue = perm.redactValue;\n result[field] = entry;\n }\n return result;\n}\n\nfunction extractPipelineSteps(\n pipe?: PipelineConfig,\n): RegistryEntry['pipelineSteps'] {\n if (!pipe) return undefined;\n\n const steps: PipelineStep[] = [];\n if (Array.isArray(pipe)) {\n steps.push(...pipe);\n } else {\n const seen = new Set<string>();\n for (const opSteps of Object.values(pipe)) {\n if (Array.isArray(opSteps)) {\n for (const step of opSteps) {\n const key = `${step._type}:${step.name}`;\n if (!seen.has(key)) {\n seen.add(key);\n steps.push(step);\n }\n }\n }\n }\n }\n\n if (steps.length === 0) return undefined;\n\n return steps.map((s) => ({\n type: s._type,\n name: s.name,\n operations: s.operations ? [...s.operations] : undefined,\n }));\n}\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import "../elevation-B_2dRLVP.mjs";
2
+ import { a as RepositoryLike, i as RelationMetadata, n as DataAdapter, o as SchemaMetadata, r as FieldMetadata, s as ValidationResult, t as AdapterFactory } from "../interface-Ch8HU9uM.mjs";
3
+ import "../types-aYB4V7uN.mjs";
4
+ import { a as PrismaQueryParserOptions, c as MongooseAdapterOptions, i as PrismaQueryParser, l as createMongooseAdapter, n as PrismaAdapterOptions, o as createPrismaAdapter, r as PrismaQueryOptions, s as MongooseAdapter, t as PrismaAdapter } from "../prisma-Dg9GoVdj.mjs";
5
+ export { type AdapterFactory, type DataAdapter, type FieldMetadata, MongooseAdapter, type MongooseAdapterOptions, PrismaAdapter, type PrismaAdapterOptions, type PrismaQueryOptions, PrismaQueryParser, type PrismaQueryParserOptions, type RelationMetadata, type RepositoryLike, type SchemaMetadata, type ValidationResult, createMongooseAdapter, createPrismaAdapter };
@@ -0,0 +1,3 @@
1
+ import { a as createMongooseAdapter, i as MongooseAdapter, n as PrismaQueryParser, r as createPrismaAdapter, t as PrismaAdapter } from "../prisma-DJbMt3yf.mjs";
2
+
3
+ export { MongooseAdapter, PrismaAdapter, PrismaQueryParser, createMongooseAdapter, createPrismaAdapter };
@@ -0,0 +1,82 @@
1
+ import "../elevation-B_2dRLVP.mjs";
2
+ import "../interface-Ch8HU9uM.mjs";
3
+ import "../types-aYB4V7uN.mjs";
4
+ import { a as AuditContext, c as AuditStore, i as AuditAction, l as AuditStoreOptions, n as MongoAuditStoreOptions, o as AuditEntry, r as MongoConnection, s as AuditQueryOptions, u as createAuditEntry } from "../mongodb-CGzRbfAK.mjs";
5
+ import { FastifyPluginAsync } from "fastify";
6
+
7
+ //#region src/audit/auditPlugin.d.ts
8
+ interface AuditPluginOptions {
9
+ /** Enable audit logging (default: false) */
10
+ enabled?: boolean;
11
+ /** Storage backends to use */
12
+ stores?: ('memory' | 'mongodb')[];
13
+ /** MongoDB connection (required if using mongodb store) */
14
+ mongoConnection?: MongoConnection;
15
+ /** MongoDB collection name (default: 'audit_logs') */
16
+ mongoCollection?: string;
17
+ /** TTL in days for MongoDB (default: 90) */
18
+ ttlDays?: number;
19
+ /** Custom stores (advanced) */
20
+ customStores?: AuditStore[];
21
+ /**
22
+ * Automatically audit CRUD operations via the hook system (default: true when enabled).
23
+ * When enabled, create/update/delete operations are auto-logged without manual calls.
24
+ *
25
+ * - `true`: Auto-audit all CRUD operations on all resources
26
+ * - `{ operations: ['create', 'delete'] }`: Only auto-audit specific operations
27
+ * - `{ exclude: ['health', 'metrics'] }`: Skip specific resources
28
+ * - `false`: Disable auto-audit (manual calls only)
29
+ */
30
+ autoAudit?: boolean | {
31
+ operations?: ('create' | 'update' | 'delete')[];
32
+ exclude?: string[];
33
+ };
34
+ }
35
+ declare module 'fastify' {
36
+ interface FastifyInstance {
37
+ /** Log an audit entry */
38
+ audit: AuditLogger;
39
+ }
40
+ interface FastifyRequest {
41
+ /** Audit context for current request */
42
+ auditContext?: AuditContext;
43
+ }
44
+ }
45
+ interface AuditLogger {
46
+ /** Log a create action */
47
+ create: (resource: string, documentId: string, data: Record<string, unknown>, context?: AuditContext) => Promise<void>;
48
+ /** Log an update action */
49
+ update: (resource: string, documentId: string, before: Record<string, unknown>, after: Record<string, unknown>, context?: AuditContext) => Promise<void>;
50
+ /** Log a delete action */
51
+ delete: (resource: string, documentId: string, data: Record<string, unknown>, context?: AuditContext) => Promise<void>;
52
+ /** Log a restore action (soft delete undo) */
53
+ restore: (resource: string, documentId: string, data: Record<string, unknown>, context?: AuditContext) => Promise<void>;
54
+ /** Log a custom action */
55
+ custom: (resource: string, documentId: string, action: string, data?: Record<string, unknown>, context?: AuditContext) => Promise<void>;
56
+ /** Query audit logs (if stores support it) */
57
+ query: (options: AuditQueryOptions) => Promise<AuditEntry[]>;
58
+ }
59
+ declare const auditPlugin: FastifyPluginAsync<AuditPluginOptions>;
60
+ declare const _default: FastifyPluginAsync<AuditPluginOptions>;
61
+ //#endregion
62
+ //#region src/audit/stores/memory.d.ts
63
+ interface MemoryAuditStoreOptions {
64
+ /** Maximum entries to keep (default: 1000) */
65
+ maxEntries?: number;
66
+ }
67
+ declare class MemoryAuditStore implements AuditStore {
68
+ readonly name = "memory";
69
+ private entries;
70
+ private maxEntries;
71
+ constructor(options?: MemoryAuditStoreOptions);
72
+ log(entry: AuditEntry): Promise<void>;
73
+ query(options?: AuditQueryOptions): Promise<AuditEntry[]>;
74
+ close(): Promise<void>;
75
+ /** Get all entries (for testing) */
76
+ getAll(): AuditEntry[];
77
+ /** Clear all entries (for testing) */
78
+ clear(): void;
79
+ }
80
+ //#endregion
81
+ export { type AuditAction, type AuditContext, type AuditEntry, type AuditLogger, type AuditPluginOptions, type AuditQueryOptions, type AuditStore, type AuditStoreOptions, MemoryAuditStore, type MemoryAuditStoreOptions, type MongoAuditStoreOptions, _default as auditPlugin, auditPlugin as auditPluginFn, createAuditEntry };
82
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/audit/auditPlugin.ts","../../src/audit/stores/memory.ts"],"mappings":";;;;;;;UAgCiB,kBAAA;EAoCc;EAlC7B,OAAA;EA6BE;EA3BF,MAAA;EA8BU;EA5BV,eAAA,GAAkB,eAAA;EA8BD;EA5BjB,eAAA;EA4B6B;EA1B7B,OAAA;EA8Be;EA5Bf,YAAA,GAAe,UAAA;;;;;;;;;;EAUf,SAAA;IACE,UAAA;IACA,OAAA;EAAA;AAAA;AAAA;EAAA,UAKQ,eAAA;IAoDL;IAlDH,KAAA,EAAO,WAAA;EAAA;EAAA,UAGC,cAAA;IAkDoE;IAhD5E,YAAA,GAAe,YAAA;EAAA;AAAA;AAAA,UAIF,WAAA;EAKP;EAHR,MAAA,GACE,QAAA,UACA,UAAA,UACA,IAAA,EAAM,MAAA,mBACN,OAAA,GAAU,YAAA,KACP,OAAA;EADO;EAIZ,MAAA,GACE,QAAA,UACA,UAAA,UACA,MAAA,EAAQ,MAAA,mBACR,KAAA,EAAO,MAAA,mBACP,OAAA,GAAU,YAAA,KACP,OAAA;EATA;EAYL,MAAA,GACE,QAAA,UACA,UAAA,UACA,IAAA,EAAM,MAAA,mBACN,OAAA,GAAU,YAAA,KACP,OAAA;EAbH;EAgBF,OAAA,GACE,QAAA,UACA,UAAA,UACA,IAAA,EAAM,MAAA,mBACN,OAAA,GAAU,YAAA,KACP,OAAA;EAnBK;EAsBV,MAAA,GACE,QAAA,UACA,UAAA,UACA,MAAA,UACA,IAAA,GAAO,MAAA,mBACP,OAAA,GAAU,YAAA,KACP,OAAA;EA3BI;EA8BT,KAAA,GAAQ,OAAA,EAHI,iBAAA,KAG2D,OAAA,CAAQ,UAAA;AAAA;AAAA,cAG3E,WAAA,EAAa,kBAAA,CAAmB,kBAAA;AAAA,cAAkB,QAAA;;;UC9GvC,uBAAA;EDuBkB;ECrBjC,UAAA;AAAA;AAAA,cAGW,gBAAA,YAA4B,UAAA;EAAA,SAC9B,IAAA;EAAA,QACD,OAAA;EAAA,QACA,UAAA;cAEI,OAAA,GAAS,uBAAA;EAIf,GAAA,CAAI,KAAA,EAAO,UAAA,GAAa,OAAA;EASxB,KAAA,CAAM,OAAA,GAAS,iBAAA,GAAyB,OAAA,CAAQ,UAAA;EAwChD,KAAA,CAAA,GAAS,OAAA;EDlBf;ECuBA,MAAA,CAAA,GAAU,UAAA;EDrBR;EC0BF,KAAA,CAAA;AAAA"}
@@ -0,0 +1,276 @@
1
+ import { t as MongoAuditStore } from "../mongodb-BfJVlUJH.mjs";
2
+ import fp from "fastify-plugin";
3
+
4
+ //#region src/audit/stores/interface.ts
5
+ /**
6
+ * Create audit entry from context
7
+ */
8
+ function createAuditEntry(resource, documentId, action, context, data) {
9
+ const changes = data?.before && data?.after ? detectChanges(data.before, data.after) : void 0;
10
+ return {
11
+ id: generateAuditId(),
12
+ resource,
13
+ documentId,
14
+ action,
15
+ userId: context.user?._id?.toString() ?? context.user?.id,
16
+ organizationId: context.organizationId,
17
+ before: data?.before,
18
+ after: data?.after,
19
+ changes,
20
+ requestId: context.requestId,
21
+ ipAddress: context.ipAddress,
22
+ userAgent: context.userAgent,
23
+ metadata: data?.metadata,
24
+ timestamp: /* @__PURE__ */ new Date()
25
+ };
26
+ }
27
+ /**
28
+ * Detect changed fields between two objects
29
+ */
30
+ function detectChanges(before, after) {
31
+ const changes = [];
32
+ const allKeys = new Set([...Object.keys(before), ...Object.keys(after)]);
33
+ for (const key of allKeys) {
34
+ if (key.startsWith("_") || key === "updatedAt") continue;
35
+ if (JSON.stringify(before[key]) !== JSON.stringify(after[key])) changes.push(key);
36
+ }
37
+ return changes;
38
+ }
39
+ /**
40
+ * Generate unique audit ID
41
+ */
42
+ function generateAuditId() {
43
+ return `aud_${Date.now().toString(36)}${Math.random().toString(36).substring(2, 10)}`;
44
+ }
45
+
46
+ //#endregion
47
+ //#region src/audit/stores/memory.ts
48
+ var MemoryAuditStore = class {
49
+ name = "memory";
50
+ entries = [];
51
+ maxEntries;
52
+ constructor(options = {}) {
53
+ this.maxEntries = options.maxEntries ?? 1e3;
54
+ }
55
+ async log(entry) {
56
+ this.entries.unshift(entry);
57
+ if (this.entries.length > this.maxEntries) this.entries = this.entries.slice(0, this.maxEntries);
58
+ }
59
+ async query(options = {}) {
60
+ let results = [...this.entries];
61
+ if (options.resource) results = results.filter((e) => e.resource === options.resource);
62
+ if (options.documentId) results = results.filter((e) => e.documentId === options.documentId);
63
+ if (options.userId) results = results.filter((e) => e.userId === options.userId);
64
+ if (options.organizationId) results = results.filter((e) => e.organizationId === options.organizationId);
65
+ if (options.action) {
66
+ const actions = Array.isArray(options.action) ? options.action : [options.action];
67
+ results = results.filter((e) => actions.includes(e.action));
68
+ }
69
+ if (options.from) results = results.filter((e) => e.timestamp >= options.from);
70
+ if (options.to) results = results.filter((e) => e.timestamp <= options.to);
71
+ const offset = options.offset ?? 0;
72
+ const limit = options.limit ?? 100;
73
+ results = results.slice(offset, offset + limit);
74
+ return results;
75
+ }
76
+ async close() {
77
+ this.entries = [];
78
+ }
79
+ /** Get all entries (for testing) */
80
+ getAll() {
81
+ return [...this.entries];
82
+ }
83
+ /** Clear all entries (for testing) */
84
+ clear() {
85
+ this.entries = [];
86
+ }
87
+ };
88
+
89
+ //#endregion
90
+ //#region src/audit/auditPlugin.ts
91
+ /**
92
+ * Audit Plugin
93
+ *
94
+ * Optional audit trail with flexible storage options.
95
+ * Disabled by default - enable explicitly for enterprise use cases.
96
+ *
97
+ * @example
98
+ * import { auditPlugin } from '@classytic/arc/audit';
99
+ *
100
+ * // Development: in-memory
101
+ * await fastify.register(auditPlugin, {
102
+ * enabled: true,
103
+ * stores: ['memory'],
104
+ * });
105
+ *
106
+ * // Production: MongoDB with TTL
107
+ * await fastify.register(auditPlugin, {
108
+ * enabled: true,
109
+ * stores: ['mongodb'],
110
+ * mongoConnection: mongoose.connection,
111
+ * ttlDays: 90,
112
+ * });
113
+ */
114
+ const auditPlugin = async (fastify, opts = {}) => {
115
+ const { enabled = false, stores: storeTypes = ["memory"], mongoConnection, mongoCollection = "audit_logs", ttlDays = 90, customStores = [] } = opts;
116
+ if (!enabled) {
117
+ fastify.decorate("audit", createNoopLogger());
118
+ fastify.decorateRequest("auditContext", void 0);
119
+ fastify.log?.debug?.("Audit plugin disabled");
120
+ return;
121
+ }
122
+ const stores = [...customStores];
123
+ for (const type of storeTypes) switch (type) {
124
+ case "memory":
125
+ stores.push(new MemoryAuditStore());
126
+ break;
127
+ case "mongodb":
128
+ if (!mongoConnection) throw new Error("Audit: mongoConnection required for mongodb store");
129
+ stores.push(new MongoAuditStore({
130
+ connection: mongoConnection,
131
+ collection: mongoCollection,
132
+ ttlDays
133
+ }));
134
+ break;
135
+ }
136
+ if (stores.length === 0) throw new Error("Audit: at least one store must be configured");
137
+ async function logToStores(entry) {
138
+ await Promise.all(stores.map((store) => store.log(entry)));
139
+ }
140
+ const audit = {
141
+ async create(resource, documentId, data, context) {
142
+ await logToStores(createAuditEntry(resource, documentId, "create", context ?? {}, { after: data }));
143
+ },
144
+ async update(resource, documentId, before, after, context) {
145
+ await logToStores(createAuditEntry(resource, documentId, "update", context ?? {}, {
146
+ before,
147
+ after
148
+ }));
149
+ },
150
+ async delete(resource, documentId, data, context) {
151
+ await logToStores(createAuditEntry(resource, documentId, "delete", context ?? {}, { before: data }));
152
+ },
153
+ async restore(resource, documentId, data, context) {
154
+ await logToStores(createAuditEntry(resource, documentId, "restore", context ?? {}, { after: data }));
155
+ },
156
+ async custom(resource, documentId, action, data, context) {
157
+ await logToStores(createAuditEntry(resource, documentId, "custom", context ?? {}, { metadata: {
158
+ customAction: action,
159
+ ...data
160
+ } }));
161
+ },
162
+ async query(options) {
163
+ for (const store of stores) if (store.query) return store.query(options);
164
+ return [];
165
+ }
166
+ };
167
+ fastify.decorate("audit", audit);
168
+ fastify.decorateRequest("auditContext", void 0);
169
+ fastify.addHook("onRequest", async (request) => {
170
+ const user = request.user;
171
+ request.context;
172
+ const scope = request.scope;
173
+ request.auditContext = {
174
+ user,
175
+ organizationId: scope?.kind === "member" ? scope.organizationId : scope?.kind === "elevated" ? scope.organizationId : void 0,
176
+ requestId: request.id,
177
+ ipAddress: request.ip,
178
+ userAgent: request.headers["user-agent"],
179
+ endpoint: void 0,
180
+ duration: void 0
181
+ };
182
+ });
183
+ fastify.addHook("onResponse", async (request, reply) => {
184
+ if (request.auditContext) {
185
+ request.auditContext.endpoint = `${request.method} ${request.routeOptions?.url ?? request.url}`;
186
+ request.auditContext.duration = Math.round(reply.elapsedTime);
187
+ }
188
+ });
189
+ fastify.addHook("onClose", async () => {
190
+ await Promise.all(stores.map((store) => store.close?.()));
191
+ });
192
+ const autoAuditConfig = opts.autoAudit ?? true;
193
+ if (autoAuditConfig !== false) {
194
+ const defaultOps = [
195
+ "create",
196
+ "update",
197
+ "delete"
198
+ ];
199
+ const ops = typeof autoAuditConfig === "object" ? autoAuditConfig.operations ?? defaultOps : defaultOps;
200
+ const excludeResources = new Set(typeof autoAuditConfig === "object" ? autoAuditConfig.exclude ?? [] : []);
201
+ fastify.addHook("onReady", async () => {
202
+ const arc = "arc" in fastify ? fastify.arc : void 0;
203
+ if (!arc?.hooks) {
204
+ fastify.log?.debug?.("Auto-audit skipped: arc-core plugin not registered");
205
+ return;
206
+ }
207
+ for (const op of ops) arc.hooks.after("*", op, async (ctx) => {
208
+ if (excludeResources.has(ctx.resource)) return;
209
+ const docId = autoAuditExtractId(ctx.result);
210
+ const scope = ctx.context?._scope;
211
+ const auditCtx = {
212
+ user: ctx.user,
213
+ organizationId: scope ? autoAuditGetOrgId(scope) : void 0
214
+ };
215
+ try {
216
+ if (op === "create") await audit.create(ctx.resource, docId, autoAuditToPlain(ctx.result), auditCtx);
217
+ else if (op === "update") await audit.update(ctx.resource, docId, autoAuditToPlain(ctx.meta?.existing), autoAuditToPlain(ctx.result), auditCtx);
218
+ else if (op === "delete") await audit.delete(ctx.resource, docId, autoAuditToPlain(ctx.result), auditCtx);
219
+ } catch (err) {
220
+ fastify.log?.warn?.({
221
+ resource: ctx.resource,
222
+ op,
223
+ err
224
+ }, "Auto-audit failed");
225
+ }
226
+ }, 90);
227
+ fastify.log?.debug?.({
228
+ ops,
229
+ exclude: [...excludeResources]
230
+ }, "Auto-audit hooks registered");
231
+ });
232
+ }
233
+ fastify.log?.debug?.({ stores: storeTypes }, "Audit plugin enabled");
234
+ };
235
+ /** Extract document ID from a result */
236
+ function autoAuditExtractId(doc) {
237
+ if (!doc || typeof doc !== "object") return "";
238
+ const d = doc;
239
+ const rawId = d._id ?? d.id;
240
+ return rawId != null ? String(rawId) : "";
241
+ }
242
+ /** Convert Mongoose doc or plain object to plain object */
243
+ function autoAuditToPlain(doc) {
244
+ if (!doc || typeof doc !== "object") return {};
245
+ if (typeof doc.toObject === "function") return doc.toObject();
246
+ return doc;
247
+ }
248
+ /** Extract org ID from scope (avoids importing scope module to prevent circular deps) */
249
+ function autoAuditGetOrgId(scope) {
250
+ if (!scope || typeof scope !== "object") return void 0;
251
+ const s = scope;
252
+ if (s.kind === "member" || s.kind === "elevated") return s.organizationId;
253
+ }
254
+ /**
255
+ * Create no-op logger for when audit is disabled
256
+ */
257
+ function createNoopLogger() {
258
+ const noop = async () => {};
259
+ return {
260
+ create: noop,
261
+ update: noop,
262
+ delete: noop,
263
+ restore: noop,
264
+ custom: noop,
265
+ query: async () => []
266
+ };
267
+ }
268
+ var auditPlugin_default = fp(auditPlugin, {
269
+ name: "arc-audit",
270
+ fastify: "5.x",
271
+ dependencies: ["arc-core"]
272
+ });
273
+
274
+ //#endregion
275
+ export { MemoryAuditStore, auditPlugin_default as auditPlugin, auditPlugin as auditPluginFn, createAuditEntry };
276
+ //# sourceMappingURL=index.mjs.map