@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 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/audit/stores/interface.ts","../../src/audit/stores/memory.ts","../../src/audit/auditPlugin.ts"],"sourcesContent":["/**\n * Audit Store Interface\n *\n * Pluggable storage backend for audit logs.\n * Implementations: memory (dev), mongodb, event (emit only)\n */\n\nimport type { UserBase } from '../../types/index.js';\n\nexport type AuditAction = 'create' | 'update' | 'delete' | 'restore' | 'custom';\n\nexport interface AuditEntry {\n /** Unique audit log ID */\n id: string;\n /** Resource name (e.g., 'product', 'user') */\n resource: string;\n /** Document/entity ID */\n documentId: string;\n /** Action performed */\n action: AuditAction;\n /** User who performed the action */\n userId?: string;\n /** Organization context */\n organizationId?: string;\n /** Previous state (for updates) */\n before?: Record<string, unknown>;\n /** New state (for creates/updates) */\n after?: Record<string, unknown>;\n /** Changed fields (for updates) */\n changes?: string[];\n /** Request ID for tracing */\n requestId?: string;\n /** IP address */\n ipAddress?: string;\n /** User agent */\n userAgent?: string;\n /** Custom metadata */\n metadata?: Record<string, unknown>;\n /** When the action occurred */\n timestamp: Date;\n}\n\nexport interface AuditContext {\n user?: UserBase;\n organizationId?: string;\n requestId?: string;\n ipAddress?: string;\n userAgent?: string;\n /** HTTP method + route pattern (e.g., 'PATCH /api/products/:id') */\n endpoint?: string;\n /** Request duration in milliseconds */\n duration?: number;\n}\n\nexport interface AuditStoreOptions {\n /** Store name for logging */\n name: string;\n}\n\n/**\n * Abstract audit store interface\n */\nexport interface AuditStore {\n /** Store name */\n readonly name: string;\n\n /** Log an audit entry */\n log(entry: AuditEntry): Promise<void>;\n\n /** Query audit logs (optional - not all stores support querying) */\n query?(options: AuditQueryOptions): Promise<AuditEntry[]>;\n\n /** Close/cleanup (optional) */\n close?(): Promise<void>;\n}\n\nexport interface AuditQueryOptions {\n resource?: string;\n documentId?: string;\n userId?: string;\n organizationId?: string;\n action?: AuditAction | AuditAction[];\n from?: Date;\n to?: Date;\n limit?: number;\n offset?: number;\n}\n\n/**\n * Create audit entry from context\n */\nexport function createAuditEntry(\n resource: string,\n documentId: string,\n action: AuditAction,\n context: AuditContext,\n data?: {\n before?: Record<string, unknown>;\n after?: Record<string, unknown>;\n metadata?: Record<string, unknown>;\n }\n): AuditEntry {\n const changes = data?.before && data?.after\n ? detectChanges(data.before, data.after)\n : undefined;\n\n return {\n id: generateAuditId(),\n resource,\n documentId,\n action,\n userId: context.user?._id?.toString() ?? context.user?.id,\n organizationId: context.organizationId,\n before: data?.before,\n after: data?.after,\n changes,\n requestId: context.requestId,\n ipAddress: context.ipAddress,\n userAgent: context.userAgent,\n metadata: data?.metadata,\n timestamp: new Date(),\n };\n}\n\n/**\n * Detect changed fields between two objects\n */\nfunction detectChanges(\n before: Record<string, unknown>,\n after: Record<string, unknown>\n): string[] {\n const changes: string[] = [];\n const allKeys = new Set([...Object.keys(before), ...Object.keys(after)]);\n\n for (const key of allKeys) {\n // Skip internal fields\n if (key.startsWith('_') || key === 'updatedAt') continue;\n\n const oldVal = JSON.stringify(before[key]);\n const newVal = JSON.stringify(after[key]);\n\n if (oldVal !== newVal) {\n changes.push(key);\n }\n }\n\n return changes;\n}\n\n/**\n * Generate unique audit ID\n */\nfunction generateAuditId(): string {\n const timestamp = Date.now().toString(36);\n const random = Math.random().toString(36).substring(2, 10);\n return `aud_${timestamp}${random}`;\n}\n","/**\n * In-Memory Audit Store\n *\n * For development and testing. Not suitable for production.\n * Logs are lost on restart.\n */\n\nimport type { AuditEntry, AuditQueryOptions, AuditStore } from './interface.js';\n\nexport interface MemoryAuditStoreOptions {\n /** Maximum entries to keep (default: 1000) */\n maxEntries?: number;\n}\n\nexport class MemoryAuditStore implements AuditStore {\n readonly name = 'memory';\n private entries: AuditEntry[] = [];\n private maxEntries: number;\n\n constructor(options: MemoryAuditStoreOptions = {}) {\n this.maxEntries = options.maxEntries ?? 1000;\n }\n\n async log(entry: AuditEntry): Promise<void> {\n this.entries.unshift(entry);\n\n // Trim to max size\n if (this.entries.length > this.maxEntries) {\n this.entries = this.entries.slice(0, this.maxEntries);\n }\n }\n\n async query(options: AuditQueryOptions = {}): Promise<AuditEntry[]> {\n let results = [...this.entries];\n\n if (options.resource) {\n results = results.filter((e) => e.resource === options.resource);\n }\n\n if (options.documentId) {\n results = results.filter((e) => e.documentId === options.documentId);\n }\n\n if (options.userId) {\n results = results.filter((e) => e.userId === options.userId);\n }\n\n if (options.organizationId) {\n results = results.filter((e) => e.organizationId === options.organizationId);\n }\n\n if (options.action) {\n const actions = Array.isArray(options.action) ? options.action : [options.action];\n results = results.filter((e) => actions.includes(e.action));\n }\n\n if (options.from) {\n results = results.filter((e) => e.timestamp >= options.from!);\n }\n\n if (options.to) {\n results = results.filter((e) => e.timestamp <= options.to!);\n }\n\n // Pagination\n const offset = options.offset ?? 0;\n const limit = options.limit ?? 100;\n results = results.slice(offset, offset + limit);\n\n return results;\n }\n\n async close(): Promise<void> {\n this.entries = [];\n }\n\n /** Get all entries (for testing) */\n getAll(): AuditEntry[] {\n return [...this.entries];\n }\n\n /** Clear all entries (for testing) */\n clear(): void {\n this.entries = [];\n }\n}\n\nexport default MemoryAuditStore;\n","/**\n * Audit Plugin\n *\n * Optional audit trail with flexible storage options.\n * Disabled by default - enable explicitly for enterprise use cases.\n *\n * @example\n * import { auditPlugin } from '@classytic/arc/audit';\n *\n * // Development: in-memory\n * await fastify.register(auditPlugin, {\n * enabled: true,\n * stores: ['memory'],\n * });\n *\n * // Production: MongoDB with TTL\n * await fastify.register(auditPlugin, {\n * enabled: true,\n * stores: ['mongodb'],\n * mongoConnection: mongoose.connection,\n * ttlDays: 90,\n * });\n */\n\nimport fp from 'fastify-plugin';\nimport type { FastifyInstance, FastifyPluginAsync, FastifyRequest } from 'fastify';\nimport type { AuditContext, AuditEntry, AuditStore } from './stores/interface.js';\nimport { createAuditEntry } from './stores/interface.js';\nimport { MemoryAuditStore } from './stores/memory.js';\nimport { MongoAuditStore, type MongoConnection } from './stores/mongodb.js';\nimport type { UserBase, RequestContext } from '../types/index.js';\n\nexport interface AuditPluginOptions {\n /** Enable audit logging (default: false) */\n enabled?: boolean;\n /** Storage backends to use */\n stores?: ('memory' | 'mongodb')[];\n /** MongoDB connection (required if using mongodb store) */\n mongoConnection?: MongoConnection;\n /** MongoDB collection name (default: 'audit_logs') */\n mongoCollection?: string;\n /** TTL in days for MongoDB (default: 90) */\n ttlDays?: number;\n /** Custom stores (advanced) */\n customStores?: AuditStore[];\n /**\n * Automatically audit CRUD operations via the hook system (default: true when enabled).\n * When enabled, create/update/delete operations are auto-logged without manual calls.\n *\n * - `true`: Auto-audit all CRUD operations on all resources\n * - `{ operations: ['create', 'delete'] }`: Only auto-audit specific operations\n * - `{ exclude: ['health', 'metrics'] }`: Skip specific resources\n * - `false`: Disable auto-audit (manual calls only)\n */\n autoAudit?: boolean | {\n operations?: ('create' | 'update' | 'delete')[];\n exclude?: string[];\n };\n}\n\ndeclare module 'fastify' {\n interface FastifyInstance {\n /** Log an audit entry */\n audit: AuditLogger;\n }\n\n interface FastifyRequest {\n /** Audit context for current request */\n auditContext?: AuditContext;\n }\n}\n\nexport interface AuditLogger {\n /** Log a create action */\n create: (\n resource: string,\n documentId: string,\n data: Record<string, unknown>,\n context?: AuditContext\n ) => Promise<void>;\n\n /** Log an update action */\n update: (\n resource: string,\n documentId: string,\n before: Record<string, unknown>,\n after: Record<string, unknown>,\n context?: AuditContext\n ) => Promise<void>;\n\n /** Log a delete action */\n delete: (\n resource: string,\n documentId: string,\n data: Record<string, unknown>,\n context?: AuditContext\n ) => Promise<void>;\n\n /** Log a restore action (soft delete undo) */\n restore: (\n resource: string,\n documentId: string,\n data: Record<string, unknown>,\n context?: AuditContext\n ) => Promise<void>;\n\n /** Log a custom action */\n custom: (\n resource: string,\n documentId: string,\n action: string,\n data?: Record<string, unknown>,\n context?: AuditContext\n ) => Promise<void>;\n\n /** Query audit logs (if stores support it) */\n query: (options: import('./stores/interface.js').AuditQueryOptions) => Promise<AuditEntry[]>;\n}\n\nconst auditPlugin: FastifyPluginAsync<AuditPluginOptions> = async (\n fastify: FastifyInstance,\n opts: AuditPluginOptions = {}\n) => {\n const {\n enabled = false,\n stores: storeTypes = ['memory'],\n mongoConnection,\n mongoCollection = 'audit_logs',\n ttlDays = 90,\n customStores = [],\n } = opts;\n\n // Skip if not enabled\n if (!enabled) {\n // Provide no-op audit methods\n fastify.decorate('audit', createNoopLogger());\n fastify.decorateRequest('auditContext', undefined);\n fastify.log?.debug?.('Audit plugin disabled');\n return;\n }\n\n // Initialize stores\n const stores: AuditStore[] = [...customStores];\n\n for (const type of storeTypes) {\n switch (type) {\n case 'memory':\n stores.push(new MemoryAuditStore());\n break;\n case 'mongodb':\n if (!mongoConnection) {\n throw new Error('Audit: mongoConnection required for mongodb store');\n }\n stores.push(new MongoAuditStore({\n connection: mongoConnection,\n collection: mongoCollection,\n ttlDays,\n }));\n break;\n }\n }\n\n if (stores.length === 0) {\n throw new Error('Audit: at least one store must be configured');\n }\n\n // Log to all stores\n async function logToStores(entry: AuditEntry): Promise<void> {\n await Promise.all(stores.map((store) => store.log(entry)));\n }\n\n // Create audit logger\n const audit: AuditLogger = {\n async create(resource, documentId, data, context) {\n const entry = createAuditEntry(resource, documentId, 'create', context ?? {}, {\n after: data,\n });\n await logToStores(entry);\n },\n\n async update(resource, documentId, before, after, context) {\n const entry = createAuditEntry(resource, documentId, 'update', context ?? {}, {\n before,\n after,\n });\n await logToStores(entry);\n },\n\n async delete(resource, documentId, data, context) {\n const entry = createAuditEntry(resource, documentId, 'delete', context ?? {}, {\n before: data,\n });\n await logToStores(entry);\n },\n\n async restore(resource, documentId, data, context) {\n const entry = createAuditEntry(resource, documentId, 'restore', context ?? {}, {\n after: data,\n });\n await logToStores(entry);\n },\n\n async custom(resource, documentId, action, data, context) {\n const entry = createAuditEntry(resource, documentId, 'custom', context ?? {}, {\n metadata: { customAction: action, ...data },\n });\n await logToStores(entry);\n },\n\n async query(options) {\n // Use first store that supports querying\n for (const store of stores) {\n if (store.query) {\n return store.query(options);\n }\n }\n return [];\n },\n };\n\n fastify.decorate('audit', audit);\n\n // Extract audit context from request\n fastify.decorateRequest('auditContext', undefined);\n\n fastify.addHook('onRequest', async (request) => {\n const user = (request as FastifyRequest & { user?: UserBase }).user;\n const context = (request as FastifyRequest & { context?: RequestContext }).context;\n\n // Derive org ID from request.scope (set by auth adapters)\n const scope = request.scope;\n const auditOrgId = scope?.kind === 'member' ? scope.organizationId\n : scope?.kind === 'elevated' ? scope.organizationId\n : undefined;\n\n request.auditContext = {\n user,\n organizationId: auditOrgId,\n requestId: request.id,\n ipAddress: request.ip,\n userAgent: request.headers['user-agent'],\n endpoint: undefined,\n duration: undefined,\n };\n });\n\n // Populate endpoint and duration after response is sent\n fastify.addHook('onResponse', async (request, reply) => {\n if (request.auditContext) {\n request.auditContext.endpoint = `${request.method} ${request.routeOptions?.url ?? request.url}`;\n request.auditContext.duration = Math.round(reply.elapsedTime);\n }\n });\n\n // Cleanup on close\n fastify.addHook('onClose', async () => {\n await Promise.all(stores.map((store) => store.close?.()));\n });\n\n // Auto-audit CRUD operations via hook system\n const autoAuditConfig = opts.autoAudit ?? true;\n if (autoAuditConfig !== false) {\n const defaultOps = ['create', 'update', 'delete'] as const;\n const ops = typeof autoAuditConfig === 'object'\n ? autoAuditConfig.operations ?? defaultOps\n : defaultOps;\n const excludeResources = new Set(\n typeof autoAuditConfig === 'object' ? autoAuditConfig.exclude ?? [] : [],\n );\n\n // Wire hooks after all plugins are registered (onReady) so arc-core is available\n fastify.addHook('onReady', async () => {\n // fastify.arc is declared via module augmentation in arcCorePlugin.ts\n const arc = 'arc' in fastify ? fastify.arc : undefined;\n if (!arc?.hooks) {\n fastify.log?.debug?.('Auto-audit skipped: arc-core plugin not registered');\n return;\n }\n\n for (const op of ops) {\n arc.hooks.after('*', op, async (ctx) => {\n if (excludeResources.has(ctx.resource)) return;\n\n const docId = autoAuditExtractId(ctx.result);\n const scope = (ctx.context as Record<string, unknown> | undefined)?._scope;\n const auditCtx: AuditContext = {\n user: ctx.user,\n organizationId: scope ? autoAuditGetOrgId(scope) : undefined,\n };\n\n try {\n if (op === 'create') {\n await audit.create(ctx.resource, docId, autoAuditToPlain(ctx.result), auditCtx);\n } else if (op === 'update') {\n await audit.update(\n ctx.resource,\n docId,\n autoAuditToPlain(ctx.meta?.existing),\n autoAuditToPlain(ctx.result),\n auditCtx,\n );\n } else if (op === 'delete') {\n await audit.delete(ctx.resource, docId, autoAuditToPlain(ctx.result), auditCtx);\n }\n } catch (err) {\n fastify.log?.warn?.(\n { resource: ctx.resource, op, err },\n 'Auto-audit failed',\n );\n }\n }, 90); // Priority 90 — after user hooks, before event hooks at 100\n }\n\n fastify.log?.debug?.({ ops, exclude: [...excludeResources] }, 'Auto-audit hooks registered');\n });\n }\n\n fastify.log?.debug?.({ stores: storeTypes }, 'Audit plugin enabled');\n};\n\n/** Extract document ID from a result */\nfunction autoAuditExtractId(doc: unknown): string {\n if (!doc || typeof doc !== 'object') return '';\n const d = doc as Record<string, unknown>;\n const rawId = d._id ?? d.id;\n return rawId != null ? String(rawId) : '';\n}\n\n/** Convert Mongoose doc or plain object to plain object */\nfunction autoAuditToPlain(doc: unknown): Record<string, unknown> {\n if (!doc || typeof doc !== 'object') return {};\n if (typeof (doc as Record<string, unknown>).toObject === 'function') {\n return (doc as { toObject: () => Record<string, unknown> }).toObject();\n }\n return doc as Record<string, unknown>;\n}\n\n/** Extract org ID from scope (avoids importing scope module to prevent circular deps) */\nfunction autoAuditGetOrgId(scope: unknown): string | undefined {\n if (!scope || typeof scope !== 'object') return undefined;\n const s = scope as Record<string, unknown>;\n if (s.kind === 'member' || s.kind === 'elevated') {\n return s.organizationId as string | undefined;\n }\n return undefined;\n}\n\n/**\n * Create no-op logger for when audit is disabled\n */\nfunction createNoopLogger(): AuditLogger {\n const noop = async () => {};\n return {\n create: noop,\n update: noop,\n delete: noop,\n restore: noop,\n custom: noop,\n query: async () => [],\n };\n}\n\nexport default fp(auditPlugin, {\n name: 'arc-audit',\n fastify: '5.x',\n dependencies: ['arc-core'],\n});\n\nexport { auditPlugin };\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import "../elevation-B_2dRLVP.mjs";
2
+ import "../interface-Ch8HU9uM.mjs";
3
+ import "../types-aYB4V7uN.mjs";
4
+ import { n as MongoAuditStoreOptions, t as MongoAuditStore } from "../mongodb-CGzRbfAK.mjs";
5
+ export { MongoAuditStore, type MongoAuditStoreOptions };
@@ -0,0 +1,3 @@
1
+ import { t as MongoAuditStore } from "../mongodb-BfJVlUJH.mjs";
2
+
3
+ export { MongoAuditStore };
@@ -0,0 +1,141 @@
1
+ import { c as isElevated, n as PUBLIC_SCOPE } from "./types-Beqn1Un7.mjs";
2
+ import { allowPublic, requireRoles } from "./permissions/index.mjs";
3
+
4
+ //#region src/presets/softDelete.ts
5
+ function softDeletePreset() {
6
+ return {
7
+ name: "softDelete",
8
+ additionalRoutes: (permissions) => [{
9
+ method: "GET",
10
+ path: "/deleted",
11
+ handler: "getDeleted",
12
+ summary: "Get soft-deleted items",
13
+ permissions: permissions.list ?? requireRoles(["admin"]),
14
+ wrapHandler: true,
15
+ operation: "listDeleted"
16
+ }, {
17
+ method: "POST",
18
+ path: "/:id/restore",
19
+ handler: "restore",
20
+ summary: "Restore soft-deleted item",
21
+ permissions: permissions.update ?? requireRoles(["admin"]),
22
+ wrapHandler: true,
23
+ operation: "restore"
24
+ }]
25
+ };
26
+ }
27
+
28
+ //#endregion
29
+ //#region src/presets/slugLookup.ts
30
+ function slugLookupPreset(options = {}) {
31
+ const { slugField = "slug" } = options;
32
+ return {
33
+ name: "slugLookup",
34
+ additionalRoutes: (permissions) => [{
35
+ method: "GET",
36
+ path: `/slug/:${slugField}`,
37
+ handler: "getBySlug",
38
+ summary: "Get by slug",
39
+ permissions: permissions.get ?? allowPublic(),
40
+ wrapHandler: true,
41
+ operation: "getBySlug"
42
+ }],
43
+ controllerOptions: { slugField }
44
+ };
45
+ }
46
+
47
+ //#endregion
48
+ //#region src/presets/ownedByUser.ts
49
+ /**
50
+ * Create ownership check middleware.
51
+ * Elevated scope (platform admin) bypasses ownership checks.
52
+ */
53
+ function createOwnershipCheck(ownerField) {
54
+ return async (request, _reply) => {
55
+ const user = request.user;
56
+ if (!user) return;
57
+ if (isElevated(request.scope ?? PUBLIC_SCOPE)) return;
58
+ const userWithId = user;
59
+ const userId = userWithId._id ?? userWithId.id;
60
+ if (userId) request._ownershipCheck = {
61
+ field: ownerField,
62
+ userId
63
+ };
64
+ };
65
+ }
66
+ function ownedByUserPreset(options = {}) {
67
+ const { ownerField = "userId" } = options;
68
+ const ownershipMiddleware = createOwnershipCheck(ownerField);
69
+ return {
70
+ name: "ownedByUser",
71
+ middlewares: {
72
+ update: [ownershipMiddleware],
73
+ delete: [ownershipMiddleware]
74
+ }
75
+ };
76
+ }
77
+
78
+ //#endregion
79
+ //#region src/presets/tree.ts
80
+ function treePreset(options = {}) {
81
+ const { parentField = "parent" } = options;
82
+ return {
83
+ name: "tree",
84
+ additionalRoutes: (permissions) => [{
85
+ method: "GET",
86
+ path: "/tree",
87
+ handler: "getTree",
88
+ summary: "Get hierarchical tree",
89
+ permissions: permissions.list ?? allowPublic(),
90
+ wrapHandler: true,
91
+ operation: "getTree"
92
+ }, {
93
+ method: "GET",
94
+ path: `/:${parentField}/children`,
95
+ handler: "getChildren",
96
+ summary: "Get children of parent",
97
+ permissions: permissions.list ?? allowPublic(),
98
+ wrapHandler: true,
99
+ operation: "getChildren"
100
+ }],
101
+ controllerOptions: { parentField }
102
+ };
103
+ }
104
+
105
+ //#endregion
106
+ //#region src/presets/audited.ts
107
+ /**
108
+ * Audited preset - adds createdBy/updatedBy tracking
109
+ */
110
+ function auditedPreset(options = {}) {
111
+ const { createdByField = "createdBy", updatedByField = "updatedBy" } = options;
112
+ const injectCreatedBy = async (request, _reply) => {
113
+ const userWithId = request.user;
114
+ if (userWithId?._id || userWithId?.id) {
115
+ const userId = userWithId._id ?? userWithId.id;
116
+ request.body[createdByField] = userId;
117
+ request.body[updatedByField] = userId;
118
+ }
119
+ };
120
+ const injectUpdatedBy = async (request, _reply) => {
121
+ const userWithId = request.user;
122
+ if (userWithId?._id || userWithId?.id) request.body[updatedByField] = userWithId._id ?? userWithId.id;
123
+ };
124
+ return {
125
+ name: "audited",
126
+ schemaOptions: { fieldRules: {
127
+ [createdByField]: { systemManaged: true },
128
+ [updatedByField]: { systemManaged: true },
129
+ createdAt: { systemManaged: true },
130
+ updatedAt: { systemManaged: true }
131
+ } },
132
+ middlewares: {
133
+ create: [injectCreatedBy],
134
+ update: [injectUpdatedBy]
135
+ }
136
+ };
137
+ }
138
+
139
+ //#endregion
140
+ export { softDeletePreset as a, slugLookupPreset as i, treePreset as n, ownedByUserPreset as r, auditedPreset as t };
141
+ //# sourceMappingURL=audited-C3T5DTUx.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audited-C3T5DTUx.mjs","names":[],"sources":["../src/presets/softDelete.ts","../src/presets/slugLookup.ts","../src/presets/ownedByUser.ts","../src/presets/tree.ts","../src/presets/audited.ts"],"sourcesContent":["/**\n * Soft Delete Preset\n *\n * Adds routes for listing deleted items and restoring them.\n * The actual soft-delete behavior (deletedAt field, query filtering)\n * is handled by the repository/adapter layer (e.g., MongoKit's softDelete plugin).\n */\n\nimport type { AdditionalRoute, PresetResult, ResourcePermissions } from '../types/index.js';\nimport { requireRoles } from '../permissions/index.js';\n\nexport function softDeletePreset(): PresetResult {\n return {\n name: 'softDelete',\n additionalRoutes: (permissions: ResourcePermissions): AdditionalRoute[] => [\n {\n method: 'GET',\n path: '/deleted',\n handler: 'getDeleted',\n summary: 'Get soft-deleted items',\n permissions: permissions.list ?? requireRoles(['admin']),\n wrapHandler: true,\n operation: 'listDeleted',\n },\n {\n method: 'POST',\n path: '/:id/restore',\n handler: 'restore',\n summary: 'Restore soft-deleted item',\n permissions: permissions.update ?? requireRoles(['admin']),\n wrapHandler: true,\n operation: 'restore',\n },\n ],\n };\n}\n\nexport default softDeletePreset;\n","/**\n * Slug Lookup Preset\n *\n * Adds a route to get resource by slug.\n */\n\nimport type { AdditionalRoute, ResourcePermissions, PresetResult } from '../types/index.js';\nimport { allowPublic } from '../permissions/index.js';\n\nexport interface SlugLookupOptions {\n slugField?: string;\n}\n\nexport function slugLookupPreset(options: SlugLookupOptions = {}): PresetResult {\n const { slugField = 'slug' } = options;\n\n return {\n name: 'slugLookup',\n additionalRoutes: (permissions: ResourcePermissions): AdditionalRoute[] => [\n {\n method: 'GET',\n path: `/slug/:${slugField}`,\n handler: 'getBySlug',\n summary: 'Get by slug',\n permissions: permissions.get ?? allowPublic(),\n wrapHandler: true,\n operation: 'getBySlug',\n },\n ],\n // Pass to controller so it knows which param to read\n controllerOptions: {\n slugField,\n },\n };\n}\n\nexport default slugLookupPreset;\n","/**\n * Owned By User Preset\n *\n * Adds ownership validation for update/delete operations.\n *\n * BEHAVIOR:\n * - On update/remove, sets _ownershipCheck on request\n * - BaseController enforces ownership before mutation\n * - Users can only modify resources where ownerField matches their ID\n *\n * BYPASS:\n * - Users with bypassRoles (default: ['admin', 'superadmin']) skip check\n * - Resources without the ownerField are not checked\n *\n * @example\n * defineResource({\n * name: 'post',\n * presets: [{ name: 'ownedByUser', ownerField: 'authorId' }],\n * });\n *\n * // User A cannot update/delete User B's posts\n * // Admins can modify any post\n */\n\nimport type { FastifyReply } from 'fastify';\nimport type {\n MiddlewareConfig,\n PresetResult,\n RequestWithExtras,\n RouteHandler,\n} from '../types/index.js';\nimport { isElevated, PUBLIC_SCOPE } from '../scope/types.js';\nimport type { RequestScope } from '../scope/types.js';\n\nexport interface OwnedByUserOptions {\n ownerField?: string;\n}\n\n/**\n * Create ownership check middleware.\n * Elevated scope (platform admin) bypasses ownership checks.\n */\nfunction createOwnershipCheck(ownerField: string): RouteHandler {\n return async (request: RequestWithExtras, _reply: FastifyReply): Promise<void> => {\n const user = request.user;\n if (!user) return;\n\n // Elevated scope bypasses ownership check\n const scope = request.scope ?? PUBLIC_SCOPE;\n if (isElevated(scope)) return;\n\n // Set ownership check for controller to validate\n const userWithId = user as { _id?: string; id?: string };\n const userId = userWithId._id ?? userWithId.id;\n if (userId) {\n request._ownershipCheck = {\n field: ownerField,\n userId,\n };\n }\n };\n}\n\nexport function ownedByUserPreset(options: OwnedByUserOptions = {}): PresetResult {\n const { ownerField = 'userId' } = options;\n\n const ownershipMiddleware = createOwnershipCheck(ownerField);\n\n return {\n name: 'ownedByUser',\n middlewares: {\n update: [ownershipMiddleware],\n delete: [ownershipMiddleware],\n } as MiddlewareConfig,\n };\n}\n\nexport default ownedByUserPreset;\n","/**\n * Tree Preset\n *\n * Adds routes for hierarchical tree structures.\n */\n\nimport type { AdditionalRoute, ResourcePermissions, PresetResult } from '../types/index.js';\nimport { allowPublic } from '../permissions/index.js';\n\nexport interface TreeOptions {\n parentField?: string;\n}\n\nexport function treePreset(options: TreeOptions = {}): PresetResult {\n const { parentField = 'parent' } = options;\n\n return {\n name: 'tree',\n additionalRoutes: (permissions: ResourcePermissions): AdditionalRoute[] => [\n {\n method: 'GET',\n path: '/tree',\n handler: 'getTree',\n summary: 'Get hierarchical tree',\n permissions: permissions.list ?? allowPublic(),\n wrapHandler: true,\n operation: 'getTree',\n },\n {\n method: 'GET',\n path: `/:${parentField}/children`,\n handler: 'getChildren',\n summary: 'Get children of parent',\n permissions: permissions.list ?? allowPublic(),\n wrapHandler: true,\n operation: 'getChildren',\n },\n ],\n // Pass to controller so it knows which param to read\n controllerOptions: {\n parentField,\n },\n };\n}\n\nexport default treePreset;\n","/**\n * Audited Preset\n *\n * Adds createdBy/updatedBy tracking to resources.\n * Works with the audit plugin for full change tracking.\n *\n * @example\n * defineResource({\n * name: 'product',\n * presets: ['audited'],\n * // Fields createdBy, updatedBy auto-populated from user context\n * });\n */\n\nimport type { FastifyReply } from 'fastify';\nimport type { PresetResult, RequestWithExtras, MiddlewareHandler } from '../types/index.js';\n\nexport interface AuditedPresetOptions {\n /** Field name for creator (default: 'createdBy') */\n createdByField?: string;\n /** Field name for updater (default: 'updatedBy') */\n updatedByField?: string;\n}\n\n/**\n * Audited preset - adds createdBy/updatedBy tracking\n */\nexport function auditedPreset(options: AuditedPresetOptions = {}): PresetResult {\n const { createdByField = 'createdBy', updatedByField = 'updatedBy' } = options;\n\n const injectCreatedBy: MiddlewareHandler = async (\n request: RequestWithExtras,\n _reply: FastifyReply\n ): Promise<unknown> => {\n const userWithId = request.user as { _id?: string; id?: string };\n if (userWithId?._id || userWithId?.id) {\n const userId = userWithId._id ?? userWithId.id;\n (request.body as Record<string, unknown>)[createdByField] = userId;\n (request.body as Record<string, unknown>)[updatedByField] = userId;\n }\n return undefined;\n };\n\n const injectUpdatedBy: MiddlewareHandler = async (\n request: RequestWithExtras,\n _reply: FastifyReply\n ): Promise<unknown> => {\n const userWithId = request.user as { _id?: string; id?: string };\n if (userWithId?._id || userWithId?.id) {\n (request.body as Record<string, unknown>)[updatedByField] = userWithId._id ?? userWithId.id;\n }\n return undefined;\n };\n\n return {\n name: 'audited',\n schemaOptions: {\n fieldRules: {\n [createdByField]: { systemManaged: true },\n [updatedByField]: { systemManaged: true },\n createdAt: { systemManaged: true },\n updatedAt: { systemManaged: true },\n },\n },\n middlewares: {\n create: [injectCreatedBy],\n update: [injectUpdatedBy],\n },\n };\n}\n\nexport default auditedPreset;\n"],"mappings":";;;;AAWA,SAAgB,mBAAiC;AAC/C,QAAO;EACL,MAAM;EACN,mBAAmB,gBAAwD,CACzE;GACE,QAAQ;GACR,MAAM;GACN,SAAS;GACT,SAAS;GACT,aAAa,YAAY,QAAQ,aAAa,CAAC,QAAQ,CAAC;GACxD,aAAa;GACb,WAAW;GACZ,EACD;GACE,QAAQ;GACR,MAAM;GACN,SAAS;GACT,SAAS;GACT,aAAa,YAAY,UAAU,aAAa,CAAC,QAAQ,CAAC;GAC1D,aAAa;GACb,WAAW;GACZ,CACF;EACF;;;;;ACrBH,SAAgB,iBAAiB,UAA6B,EAAE,EAAgB;CAC9E,MAAM,EAAE,YAAY,WAAW;AAE/B,QAAO;EACL,MAAM;EACN,mBAAmB,gBAAwD,CACzE;GACE,QAAQ;GACR,MAAM,UAAU;GAChB,SAAS;GACT,SAAS;GACT,aAAa,YAAY,OAAO,aAAa;GAC7C,aAAa;GACb,WAAW;GACZ,CACF;EAED,mBAAmB,EACjB,WACD;EACF;;;;;;;;;ACSH,SAAS,qBAAqB,YAAkC;AAC9D,QAAO,OAAO,SAA4B,WAAwC;EAChF,MAAM,OAAO,QAAQ;AACrB,MAAI,CAAC,KAAM;AAIX,MAAI,WADU,QAAQ,SAAS,aACV,CAAE;EAGvB,MAAM,aAAa;EACnB,MAAM,SAAS,WAAW,OAAO,WAAW;AAC5C,MAAI,OACF,SAAQ,kBAAkB;GACxB,OAAO;GACP;GACD;;;AAKP,SAAgB,kBAAkB,UAA8B,EAAE,EAAgB;CAChF,MAAM,EAAE,aAAa,aAAa;CAElC,MAAM,sBAAsB,qBAAqB,WAAW;AAE5D,QAAO;EACL,MAAM;EACN,aAAa;GACX,QAAQ,CAAC,oBAAoB;GAC7B,QAAQ,CAAC,oBAAoB;GAC9B;EACF;;;;;AC7DH,SAAgB,WAAW,UAAuB,EAAE,EAAgB;CAClE,MAAM,EAAE,cAAc,aAAa;AAEnC,QAAO;EACL,MAAM;EACN,mBAAmB,gBAAwD,CACzE;GACE,QAAQ;GACR,MAAM;GACN,SAAS;GACT,SAAS;GACT,aAAa,YAAY,QAAQ,aAAa;GAC9C,aAAa;GACb,WAAW;GACZ,EACD;GACE,QAAQ;GACR,MAAM,KAAK,YAAY;GACvB,SAAS;GACT,SAAS;GACT,aAAa,YAAY,QAAQ,aAAa;GAC9C,aAAa;GACb,WAAW;GACZ,CACF;EAED,mBAAmB,EACjB,aACD;EACF;;;;;;;;ACfH,SAAgB,cAAc,UAAgC,EAAE,EAAgB;CAC9E,MAAM,EAAE,iBAAiB,aAAa,iBAAiB,gBAAgB;CAEvE,MAAM,kBAAqC,OACzC,SACA,WACqB;EACrB,MAAM,aAAa,QAAQ;AAC3B,MAAI,YAAY,OAAO,YAAY,IAAI;GACrC,MAAM,SAAS,WAAW,OAAO,WAAW;AAC5C,GAAC,QAAQ,KAAiC,kBAAkB;AAC5D,GAAC,QAAQ,KAAiC,kBAAkB;;;CAKhE,MAAM,kBAAqC,OACzC,SACA,WACqB;EACrB,MAAM,aAAa,QAAQ;AAC3B,MAAI,YAAY,OAAO,YAAY,GACjC,CAAC,QAAQ,KAAiC,kBAAkB,WAAW,OAAO,WAAW;;AAK7F,QAAO;EACL,MAAM;EACN,eAAe,EACb,YAAY;IACT,iBAAiB,EAAE,eAAe,MAAM;IACxC,iBAAiB,EAAE,eAAe,MAAM;GACzC,WAAW,EAAE,eAAe,MAAM;GAClC,WAAW,EAAE,eAAe,MAAM;GACnC,EACF;EACD,aAAa;GACX,QAAQ,CAAC,gBAAgB;GACzB,QAAQ,CAAC,gBAAgB;GAC1B;EACF"}
@@ -0,0 +1,189 @@
1
+ import "../elevation-B_2dRLVP.mjs";
2
+ import "../interface-Ch8HU9uM.mjs";
3
+ import { t as PermissionCheck } from "../types-aYB4V7uN.mjs";
4
+ import { AuthHelpers, AuthPluginOptions } from "../types/index.mjs";
5
+ import { t as ExternalOpenApiPaths } from "../externalPaths-DlINfKbP.mjs";
6
+ import { a as SessionManagerOptions, c as createSessionManager, i as SessionData, n as MemorySessionStoreOptions, o as SessionManagerResult, r as SessionCookieOptions, s as SessionStore, t as MemorySessionStore } from "../sessionManager-jPKLbHE0.mjs";
7
+ import { FastifyPluginAsync, FastifyReply as FastifyReply$1, FastifyRequest as FastifyRequest$1 } from "fastify";
8
+
9
+ //#region src/auth/authPlugin.d.ts
10
+ declare module 'fastify' {
11
+ interface FastifyInstance {
12
+ /** Authenticate middleware - use in preHandler for protected routes */
13
+ authenticate: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
14
+ /** Optional authenticate - parses JWT if present, doesn't fail if absent */
15
+ optionalAuthenticate: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
16
+ /** Authorize middleware factory - checks if user has required roles */
17
+ authorize: (...roles: string[]) => (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
18
+ /** Auth helpers - issueTokens, jwt utilities */
19
+ auth: AuthHelpers;
20
+ }
21
+ }
22
+ declare const authPlugin: FastifyPluginAsync<AuthPluginOptions>;
23
+ declare const _default: FastifyPluginAsync<AuthPluginOptions>;
24
+ //#endregion
25
+ //#region src/auth/betterAuth.d.ts
26
+ declare module 'fastify' {
27
+ interface FastifyRequest {
28
+ /** Raw request body (from @fastify/raw-body plugin, if registered) */
29
+ rawBody?: Buffer | string;
30
+ }
31
+ }
32
+ /**
33
+ * Minimal interface for a Better Auth instance.
34
+ * We only require the `handler` method -- the full Better Auth type
35
+ * comes from the user's `better-auth` installation.
36
+ */
37
+ interface BetterAuthHandler {
38
+ handler: (request: Request) => Promise<Response>;
39
+ /** The API endpoint map — each value has .path and .options. Used for OpenAPI docs extraction. */
40
+ api?: Record<string, unknown>;
41
+ }
42
+ interface BetterAuthAdapterOptions {
43
+ /** Better Auth instance (from betterAuth() in user's app) */
44
+ auth: BetterAuthHandler;
45
+ /** Base path for auth routes (default: '/api/auth') */
46
+ basePath?: string;
47
+ /**
48
+ * Enable org context extraction from Better Auth's organization plugin.
49
+ * When enabled, the adapter will look up the user's active organization
50
+ * membership and populate `request.scope` with org roles.
51
+ *
52
+ * @default false
53
+ */
54
+ orgContext?: boolean;
55
+ /**
56
+ * OpenAPI documentation for auth endpoints.
57
+ * - `true` (default): auto-extract from auth.api if available
58
+ * - `false`: disable (auth routes won't appear in OpenAPI docs)
59
+ * - `ExternalOpenApiPaths`: manual spec override
60
+ */
61
+ openapi?: boolean | ExternalOpenApiPaths;
62
+ /**
63
+ * Additional user fields from Better Auth config.
64
+ * These get merged into signUpEmail/updateUser request body schemas
65
+ * and the User component schema in OpenAPI docs.
66
+ *
67
+ * Fields with `input: false` are excluded from request bodies
68
+ * but still appear in the User component schema (output-only).
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * userFields: {
73
+ * department: { type: 'string', description: 'Department', required: true },
74
+ * roles: { type: 'array', description: 'User roles', input: false },
75
+ * }
76
+ * ```
77
+ */
78
+ userFields?: Record<string, {
79
+ type: string;
80
+ description?: string;
81
+ required?: boolean;
82
+ input?: boolean;
83
+ }>;
84
+ /**
85
+ * Expose detailed auth error messages in 401 responses.
86
+ * When false (default), returns generic "Authentication required".
87
+ * When true, includes the actual error message for debugging.
88
+ */
89
+ exposeAuthErrors?: boolean;
90
+ }
91
+ interface BetterAuthAdapterResult {
92
+ /** Fastify plugin that registers catch-all auth routes */
93
+ plugin: FastifyPluginAsync;
94
+ /** Authenticate preHandler -- validates session via Better Auth */
95
+ authenticate: (request: FastifyRequest$1, reply: FastifyReply$1) => Promise<void>;
96
+ /** Optional authenticate -- resolves session silently, continues as unauthenticated on failure */
97
+ optionalAuthenticate: (request: FastifyRequest$1, reply: FastifyReply$1) => Promise<void>;
98
+ /** Permission helpers bound to this auth adapter (available when orgContext is enabled) */
99
+ permissions: {
100
+ requireOrgRole: (...roles: string[]) => PermissionCheck;
101
+ requireOrgMembership: () => PermissionCheck;
102
+ requireTeamMembership: () => PermissionCheck;
103
+ };
104
+ /** OpenAPI paths extracted from Better Auth endpoints (undefined if openapi: false) */
105
+ openapi?: ExternalOpenApiPaths;
106
+ }
107
+ declare module 'fastify' {
108
+ interface FastifyInstance {
109
+ /**
110
+ * Authenticate middleware (Better Auth variant).
111
+ * Validates session by calling Better Auth's session endpoint internally.
112
+ * Set by the Better Auth adapter plugin.
113
+ */
114
+ authenticate: (request: FastifyRequest$1, reply: FastifyReply$1) => Promise<void>;
115
+ /**
116
+ * Optional authenticate middleware (Better Auth variant).
117
+ * Tries to resolve session silently — populates request.user if valid,
118
+ * continues as unauthenticated if no session or invalid session.
119
+ * Used on allowPublic() routes so downstream middleware can apply
120
+ * org-scoped queries when a user IS authenticated.
121
+ */
122
+ optionalAuthenticate: (request: FastifyRequest$1, reply: FastifyReply$1) => Promise<void>;
123
+ }
124
+ }
125
+ /**
126
+ * Create a Better Auth adapter for Arc/Fastify.
127
+ *
128
+ * Returns a Fastify plugin (registers catch-all auth routes) and an
129
+ * `authenticate` preHandler that validates sessions via Better Auth.
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * import { betterAuth } from 'better-auth';
134
+ * import { createBetterAuthAdapter } from '@classytic/arc/auth';
135
+ *
136
+ * const auth = betterAuth({
137
+ * database: ...,
138
+ * emailAndPassword: { enabled: true },
139
+ * });
140
+ *
141
+ * const { plugin, authenticate } = createBetterAuthAdapter({ auth });
142
+ *
143
+ * // Register the plugin (catch-all auth routes)
144
+ * await fastify.register(plugin);
145
+ *
146
+ * // Use authenticate as a preHandler on protected routes
147
+ * fastify.get('/me', { preHandler: [authenticate] }, handler);
148
+ * ```
149
+ */
150
+ declare function createBetterAuthAdapter(options: BetterAuthAdapterOptions): BetterAuthAdapterResult;
151
+ //#endregion
152
+ //#region src/auth/betterAuthOpenApi.d.ts
153
+ interface BetterAuthOpenApiOptions {
154
+ /** Base path prefix for auth routes (default: '/api/auth') */
155
+ basePath?: string;
156
+ /** Tag name for auth routes in OpenAPI (default: 'Authentication') */
157
+ tagName?: string;
158
+ /** Tag description */
159
+ tagDescription?: string;
160
+ /** Exclude specific paths from the spec (e.g. ['/ok', '/error']) */
161
+ excludePaths?: string[];
162
+ /** Exclude SERVER_ONLY endpoints (default: true) */
163
+ excludeServerOnly?: boolean;
164
+ /**
165
+ * Additional user fields from Better Auth config.
166
+ * These get merged into signUpEmail/updateUser request body schemas
167
+ * and the User component schema for $ref resolution.
168
+ *
169
+ * Fields with `input: false` are excluded from request bodies
170
+ * but still appear in the User component schema (output-only).
171
+ */
172
+ userFields?: Record<string, {
173
+ type: string;
174
+ description?: string; /** Whether this field is required in sign-up (default: false) */
175
+ required?: boolean; /** Whether this field is accepted in request body (default: true). Set false for output-only fields. */
176
+ input?: boolean;
177
+ }>;
178
+ }
179
+ /**
180
+ * Extract OpenAPI paths from a Better Auth instance's API object.
181
+ *
182
+ * Walks `authApi` (the `auth.api` object from Better Auth), discovers
183
+ * endpoints, converts their Zod schemas to JSON Schema via `z.toJSONSchema()`,
184
+ * and returns a complete `ExternalOpenApiPaths` object ready for Arc's spec builder.
185
+ */
186
+ declare function extractBetterAuthOpenApi(authApi: Record<string, unknown>, options?: BetterAuthOpenApiOptions): ExternalOpenApiPaths;
187
+ //#endregion
188
+ export { type AuthPluginOptions, type BetterAuthAdapterOptions, type BetterAuthAdapterResult, type BetterAuthHandler, type BetterAuthOpenApiOptions, MemorySessionStore, type MemorySessionStoreOptions, type SessionCookieOptions, type SessionData, type SessionManagerOptions, type SessionManagerResult, type SessionStore, _default as authPlugin, authPlugin as authPluginFn, createBetterAuthAdapter, createSessionManager, extractBetterAuthOpenApi };
189
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/auth/authPlugin.ts","../../src/auth/betterAuth.ts","../../src/auth/betterAuthOpenApi.ts"],"mappings":";;;;;;;;;;YA6CY,eAAA;IAIR;IAFA,YAAA,GAAe,OAAA,EAAS,cAAA,EAAgB,KAAA,EAAO,YAAA,KAAiB,OAAA;IAEzC;IAAvB,oBAAA,GAAuB,OAAA,EAAS,cAAA,EAAgB,KAAA,EAAO,YAAA,KAAiB,OAAA;IAAxB;IAEhD,SAAA,MAAe,KAAA,gBAAqB,OAAA,EAAS,cAAA,EAAgB,KAAA,EAAO,YAAA,KAAiB,OAAA;IAArF;IAEA,IAAA,EAAM,WAAA;EAAA;AAAA;AAAA,cAsCJ,UAAA,EAAY,kBAAA,CAAmB,iBAAA;AAAA,cAAiB,QAAA;;;;YChE1C,cAAA;IDwB6E;ICtBrF,OAAA,GAAU,MAAA;EAAA;AAAA;;;;;;UAaG,iBAAA;EACf,OAAA,GAAU,OAAA,EAAS,OAAA,KAAY,OAAA,CAAQ,QAAA;EDMrC;ECJF,GAAA,GAAM,MAAA;AAAA;AAAA,UAGS,wBAAA;EDCmC;ECClD,IAAA,EAAM,iBAAA;EDCJ;ECCF,QAAA;EDD+C;;;;;;;ECS/C,UAAA;EDPmB;;AAAA;;;;ECcnB,OAAA,aAAoB,oBAAA;EDwBgC;;;;;;;;ACvEe;;;;;;;;EAgEnE,UAAA,GAAa,MAAA;IACX,IAAA;IACA,WAAA;IACA,QAAA;IACA,KAAA;EAAA;EA7CqC;;;;;EAoDvC,gBAAA;AAAA;AAAA,UAGe,uBAAA;EAvDgB;EAyD/B,MAAA,EAAQ,kBAAA;EAvDR;EAyDA,YAAA,GAAe,OAAA,EAAS,gBAAA,EAAgB,KAAA,EAAO,cAAA,KAAiB,OAAA;EAzDpD;EA2DZ,oBAAA,GAAuB,OAAA,EAAS,gBAAA,EAAgB,KAAA,EAAO,cAAA,KAAiB,OAAA;EAxDzD;EA0Df,WAAA;IACE,cAAA,MAAoB,KAAA,eAHyD,eAAA;IAI7E,oBAAA,QADyF,eAAA;IAEzF,qBAAA,QAD6E,eAAA;EAAA;EAxB5D;EA4BnB,OAAA,GAAU,oBAAA;AAAA;AAAA;EAAA,UAQA,eAAA;IA5DV;;;;;IAkEE,YAAA,GAAe,OAAA,EAAS,gBAAA,EAAgB,KAAA,EAAO,cAAA,KAAiB,OAAA;IAxChE;;;;;;AAYJ;IAoCI,oBAAA,GAAuB,OAAA,EAAS,gBAAA,EAAgB,KAAA,EAAO,cAAA,KAAiB,OAAA;EAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuX5D,uBAAA,CACd,OAAA,EAAS,wBAAA,GACR,uBAAA;;;UCrec,wBAAA;EFyBwE;EEvBvF,QAAA;EFyBmB;EEvBnB,OAAA;EFeU;EEbV,cAAA;EFe0B;EEb1B,YAAA;EFaiD;EEXjD,iBAAA;EFWkE;;;;;;;;EEFlE,UAAA,GAAa,MAAA;IACX,IAAA;IACA,WAAA,WFIoE;IEFpE,QAAA,YFEqF;IEArF,KAAA;EAAA;AAAA;;;AFEiB;;;;;iBE8EL,wBAAA,CACd,OAAA,EAAS,MAAA,mBACT,OAAA,GAAS,wBAAA,GACR,oBAAA"}