@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,908 @@
1
+ import "../elevation-B_2dRLVP.mjs";
2
+ import { D as CrudRepository, T as ResourceDefinition } from "../interface-Ch8HU9uM.mjs";
3
+ import "../types-aYB4V7uN.mjs";
4
+ import { AnyRecord } from "../types/index.mjs";
5
+ import "../queryCachePlugin-7THaI5mt.mjs";
6
+ import "../eventPlugin-CTrLH3mt.mjs";
7
+ import "../errorHandler-BbcgBmIH.mjs";
8
+ import { r as CreateAppOptions } from "../types-CIgB7UUl.mjs";
9
+ import Fastify, { FastifyInstance } from "fastify";
10
+ import { Mock } from "vitest";
11
+ import { Connection } from "mongoose";
12
+
13
+ //#region src/testing/TestHarness.d.ts
14
+ /**
15
+ * Test fixtures for a resource
16
+ */
17
+ interface TestFixtures$1<T = any> {
18
+ /** Valid create payload */
19
+ valid: Partial<T>;
20
+ /** Update payload (optional, defaults to valid) */
21
+ update?: Partial<T>;
22
+ /** Invalid payload for validation tests (optional) */
23
+ invalid?: Partial<T>;
24
+ }
25
+ /**
26
+ * Test harness options
27
+ */
28
+ interface TestHarnessOptions<T = any> {
29
+ /** Test data fixtures */
30
+ fixtures: TestFixtures$1<T>;
31
+ /** Custom setup function (runs before all tests) */
32
+ setupFn?: () => Promise<void> | void;
33
+ /** Custom teardown function (runs after all tests) */
34
+ teardownFn?: () => Promise<void> | void;
35
+ /** MongoDB connection URI (defaults to process.env.MONGO_URI) */
36
+ mongoUri?: string;
37
+ }
38
+ /**
39
+ * Test harness for Arc resources
40
+ *
41
+ * Provides automatic test generation for:
42
+ * - CRUD operations (create, read, update, delete)
43
+ * - Schema validation
44
+ * - Preset-specific functionality (softDelete, slugLookup, tree, etc.)
45
+ */
46
+ declare class TestHarness<T = unknown> {
47
+ private resource;
48
+ private fixtures;
49
+ private setupFn?;
50
+ private teardownFn?;
51
+ private mongoUri;
52
+ private _createdIds;
53
+ private Model;
54
+ constructor(resource: ResourceDefinition<unknown>, options: TestHarnessOptions<T>);
55
+ /**
56
+ * Run all baseline tests
57
+ *
58
+ * Executes CRUD, validation, and preset tests
59
+ */
60
+ runAll(): void;
61
+ /**
62
+ * Run CRUD operation tests (model-level)
63
+ *
64
+ * Tests: create, read (list + getById), update, delete
65
+ *
66
+ * @deprecated Use `HttpTestHarness.runCrud()` for HTTP-level CRUD tests.
67
+ * This method tests Mongoose models directly and does not exercise
68
+ * HTTP routes, authentication, permissions, or the Arc pipeline.
69
+ */
70
+ runCrud(): void;
71
+ /**
72
+ * Run validation tests
73
+ *
74
+ * Tests schema validation, required fields, etc.
75
+ */
76
+ runValidation(): void;
77
+ /**
78
+ * Run preset-specific tests
79
+ *
80
+ * Auto-detects applied presets and tests their functionality:
81
+ * - softDelete: deletedAt field, soft delete/restore
82
+ * - slugLookup: slug generation
83
+ * - tree: parent references, displayOrder
84
+ * - multiTenant: organizationId requirement
85
+ * - ownedByUser: userId requirement
86
+ */
87
+ runPresets(): void;
88
+ /**
89
+ * Run field-level permission tests
90
+ *
91
+ * Auto-generates tests for each field permission:
92
+ * - hidden: field is stripped from responses
93
+ * - visibleTo: field only shown to specified roles
94
+ * - writableBy: field stripped from writes by non-privileged users
95
+ * - redactFor: field shows redacted value for specified roles
96
+ */
97
+ runFieldPermissions(): void;
98
+ /**
99
+ * Run pipeline configuration tests
100
+ *
101
+ * Validates that pipeline steps are properly configured:
102
+ * - All steps have names
103
+ * - All steps have valid _type discriminants
104
+ * - Operation filters (if set) use valid CRUD operation names
105
+ */
106
+ runPipeline(): void;
107
+ /**
108
+ * Run event definition tests
109
+ *
110
+ * Validates that events are properly defined:
111
+ * - All events have handler functions
112
+ * - Event names follow resource:action convention
113
+ * - Schema definitions (if present) are valid objects
114
+ */
115
+ runEvents(): void;
116
+ }
117
+ /**
118
+ * Create a test harness for an Arc resource
119
+ *
120
+ * @param resource - The Arc resource definition to test
121
+ * @param options - Test harness configuration
122
+ * @returns Test harness instance
123
+ *
124
+ * @example
125
+ * import { createTestHarness } from '@classytic/arc/testing';
126
+ *
127
+ * const harness = createTestHarness(productResource, {
128
+ * fixtures: {
129
+ * valid: { name: 'Product', price: 100 },
130
+ * update: { name: 'Updated' },
131
+ * },
132
+ * });
133
+ *
134
+ * harness.runAll(); // Generates 50+ baseline tests
135
+ */
136
+ declare function createTestHarness<T = any>(resource: ResourceDefinition, options: TestHarnessOptions<T>): TestHarness<T>;
137
+ /**
138
+ * Test file generation options
139
+ */
140
+ interface GenerateTestFileOptions {
141
+ /** Applied presets (e.g., ['softDelete', 'slugLookup']) */
142
+ presets?: string[];
143
+ /** Module path for imports (default: '.') */
144
+ modulePath?: string;
145
+ }
146
+ /**
147
+ * Generate test file content for a resource
148
+ *
149
+ * Useful for scaffolding new resource tests via CLI
150
+ *
151
+ * @param resourceName - Resource name in kebab-case (e.g., 'product')
152
+ * @param options - Generation options
153
+ * @returns Complete test file content as string
154
+ *
155
+ * @example
156
+ * const testContent = generateTestFile('product', {
157
+ * presets: ['softDelete'],
158
+ * modulePath: './modules/catalog',
159
+ * });
160
+ * fs.writeFileSync('product.test.js', testContent);
161
+ */
162
+ declare function generateTestFile(resourceName: string, options?: GenerateTestFileOptions): string;
163
+ /**
164
+ * Run config-level tests for a resource (no DB required)
165
+ *
166
+ * Tests field permissions, pipeline configuration, and event definitions.
167
+ * Works with any adapter — no Mongoose dependency.
168
+ *
169
+ * @param resource - The Arc resource definition to test
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * import { createConfigTestSuite } from '@classytic/arc/testing';
174
+ * import productResource from './product.resource.js';
175
+ *
176
+ * // Generates field permission, pipeline, and event tests
177
+ * createConfigTestSuite(productResource);
178
+ * ```
179
+ */
180
+ declare function createConfigTestSuite(resource: ResourceDefinition<unknown>): void;
181
+ //#endregion
182
+ //#region src/testing/testFactory.d.ts
183
+ interface CreateTestAppOptions extends Partial<CreateAppOptions> {
184
+ /**
185
+ * Use in-memory MongoDB for faster tests (default: true)
186
+ * Requires: mongodb-memory-server
187
+ *
188
+ * Set to false to use a provided mongoUri instead
189
+ */
190
+ useInMemoryDb?: boolean;
191
+ /**
192
+ * MongoDB connection URI (only used if useInMemoryDb is false)
193
+ */
194
+ mongoUri?: string;
195
+ }
196
+ interface TestAppResult {
197
+ /** Fastify app instance */
198
+ app: FastifyInstance;
199
+ /**
200
+ * Cleanup function to close app and disconnect database
201
+ * Call this in afterAll() or afterEach()
202
+ */
203
+ close: () => Promise<void>;
204
+ /** MongoDB connection URI (useful for connecting models) */
205
+ mongoUri?: string;
206
+ }
207
+ /**
208
+ * Create a test application instance with optional in-memory MongoDB
209
+ *
210
+ * **Performance Boost**: Uses in-memory MongoDB by default for 10x faster tests.
211
+ *
212
+ * @example Basic usage with in-memory DB
213
+ * ```typescript
214
+ * import { createTestApp } from '@classytic/arc/testing';
215
+ *
216
+ * describe('API Tests', () => {
217
+ * let testApp: TestAppResult;
218
+ *
219
+ * beforeAll(async () => {
220
+ * testApp = await createTestApp({
221
+ * auth: { type: 'jwt', jwt: { secret: 'test-secret' } },
222
+ * });
223
+ * });
224
+ *
225
+ * afterAll(async () => {
226
+ * await testApp.close(); // Cleans up DB and disconnects
227
+ * });
228
+ *
229
+ * test('GET /health', async () => {
230
+ * const response = await testApp.app.inject({
231
+ * method: 'GET',
232
+ * url: '/health',
233
+ * });
234
+ * expect(response.statusCode).toBe(200);
235
+ * });
236
+ * });
237
+ * ```
238
+ *
239
+ * @example Using external MongoDB
240
+ * ```typescript
241
+ * const testApp = await createTestApp({
242
+ * auth: { type: 'jwt', jwt: { secret: 'test-secret' } },
243
+ * useInMemoryDb: false,
244
+ * mongoUri: 'mongodb://localhost:27017/test-db',
245
+ * });
246
+ * ```
247
+ *
248
+ * @example Accessing MongoDB URI for model connections
249
+ * ```typescript
250
+ * const testApp = await createTestApp({
251
+ * auth: { type: 'jwt', jwt: { secret: 'test-secret' } },
252
+ * });
253
+ * await mongoose.connect(testApp.mongoUri); // Connect your models
254
+ * ```
255
+ */
256
+ declare function createTestApp(options?: CreateTestAppOptions): Promise<TestAppResult>;
257
+ /**
258
+ * Create a minimal Fastify instance for unit tests
259
+ *
260
+ * Use when you don't need Arc's full plugin stack
261
+ *
262
+ * @example
263
+ * const app = createMinimalTestApp();
264
+ * app.get('/test', async () => ({ success: true }));
265
+ *
266
+ * const response = await app.inject({ method: 'GET', url: '/test' });
267
+ * expect(response.json()).toEqual({ success: true });
268
+ */
269
+ declare function createMinimalTestApp(options?: Partial<any>): FastifyInstance;
270
+ /**
271
+ * Test request builder for cleaner tests
272
+ *
273
+ * @example
274
+ * const request = new TestRequestBuilder(app)
275
+ * .get('/products')
276
+ * .withAuth(mockUser)
277
+ * .withQuery({ page: 1, limit: 10 });
278
+ *
279
+ * const response = await request.send();
280
+ * expect(response.statusCode).toBe(200);
281
+ */
282
+ declare class TestRequestBuilder {
283
+ private method;
284
+ private url;
285
+ private body?;
286
+ private query?;
287
+ private headers;
288
+ private app;
289
+ constructor(app: FastifyInstance);
290
+ get(url: string): this;
291
+ post(url: string): this;
292
+ put(url: string): this;
293
+ patch(url: string): this;
294
+ delete(url: string): this;
295
+ withBody(body: any): this;
296
+ withQuery(query: Record<string, any>): this;
297
+ withHeader(key: string, value: string): this;
298
+ withAuth(userOrHeaders: Record<string, unknown>): this;
299
+ withContentType(type: string): this;
300
+ send(): Promise<Fastify.LightMyRequestResponse>;
301
+ }
302
+ /**
303
+ * Helper to create a test request builder
304
+ */
305
+ declare function request(app: FastifyInstance): TestRequestBuilder;
306
+ /**
307
+ * Test helper for authentication
308
+ */
309
+ declare function createTestAuth(app: FastifyInstance): {
310
+ /**
311
+ * Generate a JWT token for testing
312
+ */
313
+ generateToken(user: any): string;
314
+ /**
315
+ * Decode a JWT token
316
+ */
317
+ decodeToken(token: string): any;
318
+ /**
319
+ * Verify a JWT token
320
+ */
321
+ verifyToken(token: string): Promise<any>;
322
+ };
323
+ /**
324
+ * Snapshot testing helper for API responses
325
+ */
326
+ declare function createSnapshotMatcher(): {
327
+ /**
328
+ * Match response structure (ignores dynamic values like timestamps)
329
+ */
330
+ matchStructure(response: any, expected: any): boolean;
331
+ };
332
+ /**
333
+ * Bulk test data loader
334
+ */
335
+ declare class TestDataLoader {
336
+ private data;
337
+ private app;
338
+ constructor(app: FastifyInstance);
339
+ /**
340
+ * Load test data into database
341
+ */
342
+ load(collection: string, items: any[]): Promise<any[]>;
343
+ /**
344
+ * Clear all loaded test data
345
+ */
346
+ cleanup(): Promise<void>;
347
+ }
348
+ //#endregion
349
+ //#region src/testing/mocks.d.ts
350
+ /**
351
+ * Extended repository interface for testing (includes optional preset methods)
352
+ */
353
+ interface MockRepository<T> extends CrudRepository<T> {
354
+ getBySlug?: Mock;
355
+ getDeleted?: Mock;
356
+ restore?: Mock;
357
+ getTree?: Mock;
358
+ getChildren?: Mock;
359
+ [key: string]: unknown;
360
+ }
361
+ /**
362
+ * Create a mock repository for testing
363
+ *
364
+ * @example
365
+ * const mockRepo = createMockRepository<Product>({
366
+ * getById: vi.fn().mockResolvedValue({ id: '1', name: 'Test' }),
367
+ * create: vi.fn().mockImplementation(data => Promise.resolve({ id: '1', ...data })),
368
+ * });
369
+ *
370
+ * await mockRepo.getById('1'); // Returns mocked product
371
+ */
372
+ declare function createMockRepository<T extends AnyRecord = AnyRecord>(overrides?: Partial<MockRepository<T>>): MockRepository<T>;
373
+ /**
374
+ * Create a mock user for authentication testing
375
+ */
376
+ declare function createMockUser(overrides?: Partial<AnyRecord>): {
377
+ _id: string;
378
+ id: string;
379
+ email: string;
380
+ roles: string[];
381
+ organizationId: null;
382
+ };
383
+ /**
384
+ * Create a mock Fastify request
385
+ */
386
+ declare function createMockRequest(overrides?: Partial<AnyRecord>): unknown;
387
+ /**
388
+ * Create a mock Fastify reply
389
+ */
390
+ declare function createMockReply(): unknown;
391
+ /**
392
+ * Create a mock controller for testing
393
+ */
394
+ declare function createMockController(repository: CrudRepository<AnyRecord>): {
395
+ repository: CrudRepository<AnyRecord>;
396
+ list: Mock<(...args: any[]) => any>;
397
+ get: Mock<(...args: any[]) => any>;
398
+ create: Mock<(...args: any[]) => any>;
399
+ update: Mock<(...args: any[]) => any>;
400
+ delete: Mock<(...args: any[]) => any>;
401
+ };
402
+ /**
403
+ * Create mock data factory
404
+ *
405
+ * @example
406
+ * const productFactory = createDataFactory<Product>({
407
+ * name: () => faker.commerce.productName(),
408
+ * price: () => faker.number.int({ min: 10, max: 1000 }),
409
+ * sku: (i) => `SKU-${i}`,
410
+ * });
411
+ *
412
+ * const product = productFactory.build();
413
+ * const products = productFactory.buildMany(10);
414
+ */
415
+ declare function createDataFactory<T extends AnyRecord>(template: Record<keyof T, (index: number) => unknown>): {
416
+ build(overrides?: Partial<T>): T;
417
+ buildMany(count: number, overrides?: Partial<T>): T[];
418
+ reset(): void;
419
+ };
420
+ /**
421
+ * Create a spy that tracks function calls
422
+ *
423
+ * Useful for testing side effects without full mocking
424
+ */
425
+ declare function createSpy<T extends (...args: unknown[]) => unknown>(_name?: string): Mock<T> & {
426
+ getCalls(): unknown[][];
427
+ getLastCall(): unknown[];
428
+ };
429
+ /**
430
+ * Wait for a condition to be true
431
+ *
432
+ * Useful for async testing
433
+ */
434
+ declare function waitFor(condition: () => boolean | Promise<boolean>, options?: {
435
+ timeout?: number;
436
+ interval?: number;
437
+ }): Promise<void>;
438
+ /**
439
+ * Create a test timer that can be controlled
440
+ */
441
+ declare function createTestTimer(): {
442
+ now: () => number;
443
+ advance: (ms: number) => void;
444
+ set: (timestamp: number) => void;
445
+ reset: () => void;
446
+ };
447
+ //#endregion
448
+ //#region src/testing/authHelpers.d.ts
449
+ interface BetterAuthTestHelpersOptions {
450
+ /** Base path for auth routes (default: '/api/auth') */
451
+ basePath?: string;
452
+ }
453
+ interface AuthResponse {
454
+ statusCode: number;
455
+ token: string;
456
+ user: any;
457
+ body: any;
458
+ }
459
+ interface OrgResponse {
460
+ statusCode: number;
461
+ orgId: string;
462
+ body: any;
463
+ }
464
+ interface BetterAuthTestHelpers {
465
+ signUp(app: FastifyInstance, data: {
466
+ email: string;
467
+ password: string;
468
+ name: string;
469
+ }): Promise<AuthResponse>;
470
+ signIn(app: FastifyInstance, data: {
471
+ email: string;
472
+ password: string;
473
+ }): Promise<AuthResponse>;
474
+ createOrg(app: FastifyInstance, token: string, data: {
475
+ name: string;
476
+ slug: string;
477
+ }): Promise<OrgResponse>;
478
+ setActiveOrg(app: FastifyInstance, token: string, orgId: string): Promise<{
479
+ statusCode: number;
480
+ body: any;
481
+ }>;
482
+ authHeaders(token: string, orgId?: string): Record<string, string>;
483
+ }
484
+ interface TestUserContext {
485
+ token: string;
486
+ userId: string;
487
+ email: string;
488
+ }
489
+ interface TestOrgContext<T = Record<string, TestUserContext>> {
490
+ app: FastifyInstance;
491
+ orgId: string;
492
+ users: T;
493
+ teardown: () => Promise<void>;
494
+ }
495
+ interface SetupUserConfig {
496
+ /** Key used to reference this user in the context (e.g. 'admin', 'member') */
497
+ key: string;
498
+ email: string;
499
+ password: string;
500
+ name: string;
501
+ /** Organization role assigned after joining */
502
+ role: string;
503
+ /** If true, this user creates the org (becomes org owner). Exactly one user should have this. */
504
+ isCreator?: boolean;
505
+ }
506
+ interface SetupBetterAuthOrgOptions {
507
+ /** Factory function to create the Fastify app instance */
508
+ createApp: () => Promise<FastifyInstance>;
509
+ /** Organization to create */
510
+ org: {
511
+ name: string;
512
+ slug: string;
513
+ };
514
+ /** Users to create and add to the organization */
515
+ users: SetupUserConfig[];
516
+ /**
517
+ * Callback to add a member to the org.
518
+ * Apps wire Better Auth differently — some use auth.api.addMember, others use HTTP.
519
+ */
520
+ addMember: (data: {
521
+ organizationId: string;
522
+ userId: string;
523
+ role: string;
524
+ }) => Promise<{
525
+ statusCode: number;
526
+ }>;
527
+ /**
528
+ * Optional hook for app-specific initialization after all users are set up.
529
+ * Use this for things like recruiter→account manager hierarchy.
530
+ */
531
+ afterSetup?: (ctx: TestOrgContext) => Promise<void>;
532
+ /** Override auth helper options (e.g. custom basePath) */
533
+ authHelpers?: BetterAuthTestHelpersOptions;
534
+ }
535
+ /**
536
+ * Safely parse a JSON response body.
537
+ * Returns null if parsing fails.
538
+ */
539
+ declare function safeParseBody(body: string): any;
540
+ /**
541
+ * Create stateless Better Auth test helpers.
542
+ *
543
+ * All methods take the app instance as a parameter, making them
544
+ * safe to use across multiple test suites.
545
+ */
546
+ declare function createBetterAuthTestHelpers(options?: BetterAuthTestHelpersOptions): BetterAuthTestHelpers;
547
+ /**
548
+ * Set up a complete test organization with users.
549
+ *
550
+ * Creates the app, signs up users, creates an org, adds members,
551
+ * and returns a context object with tokens and a teardown function.
552
+ *
553
+ * @example
554
+ * ```typescript
555
+ * const ctx = await setupBetterAuthOrg({
556
+ * createApp: () => createAppInstance(),
557
+ * org: { name: 'Test Corp', slug: 'test-corp' },
558
+ * users: [
559
+ * { key: 'admin', email: 'admin@test.com', password: 'pass', name: 'Admin', role: 'admin', isCreator: true },
560
+ * { key: 'member', email: 'user@test.com', password: 'pass', name: 'User', role: 'member' },
561
+ * ],
562
+ * addMember: async (data) => {
563
+ * await auth.api.addMember({ body: data });
564
+ * return { statusCode: 200 };
565
+ * },
566
+ * });
567
+ *
568
+ * // Use in tests:
569
+ * const res = await ctx.app.inject({
570
+ * method: 'GET',
571
+ * url: '/api/products',
572
+ * headers: auth.authHeaders(ctx.users.admin.token, ctx.orgId),
573
+ * });
574
+ *
575
+ * // Cleanup:
576
+ * await ctx.teardown();
577
+ * ```
578
+ */
579
+ declare function setupBetterAuthOrg(options: SetupBetterAuthOrgOptions): Promise<TestOrgContext>;
580
+ //#endregion
581
+ //#region src/testing/HttpTestHarness.d.ts
582
+ /**
583
+ * Abstraction for generating auth headers in tests.
584
+ * Supports JWT, Better Auth, or any custom auth mechanism.
585
+ */
586
+ interface AuthProvider {
587
+ /** Get HTTP headers for a given role key */
588
+ getHeaders(role: string): Record<string, string>;
589
+ /** Available role keys (e.g. ['admin', 'member', 'viewer']) */
590
+ availableRoles: string[];
591
+ /** Role key that has full CRUD access */
592
+ adminRole: string;
593
+ }
594
+ /**
595
+ * Create an auth provider for JWT-based apps.
596
+ *
597
+ * Generates JWT tokens on the fly using the app's JWT plugin.
598
+ *
599
+ * @example
600
+ * ```typescript
601
+ * const auth = createJwtAuthProvider({
602
+ * app,
603
+ * users: {
604
+ * admin: { payload: { id: '1', roles: ['admin'] }, organizationId: 'org1' },
605
+ * viewer: { payload: { id: '2', roles: ['viewer'] } },
606
+ * },
607
+ * adminRole: 'admin',
608
+ * });
609
+ * ```
610
+ */
611
+ declare function createJwtAuthProvider(options: {
612
+ app: FastifyInstance;
613
+ users: Record<string, {
614
+ payload: Record<string, unknown>;
615
+ organizationId?: string;
616
+ }>;
617
+ adminRole: string;
618
+ }): AuthProvider;
619
+ /**
620
+ * Create an auth provider for Better Auth apps.
621
+ *
622
+ * Uses pre-existing tokens (from signUp/signIn) rather than generating them.
623
+ *
624
+ * @example
625
+ * ```typescript
626
+ * const auth = createBetterAuthProvider({
627
+ * tokens: {
628
+ * admin: ctx.users.admin.token,
629
+ * member: ctx.users.member.token,
630
+ * },
631
+ * orgId: ctx.orgId,
632
+ * adminRole: 'admin',
633
+ * });
634
+ * ```
635
+ */
636
+ declare function createBetterAuthProvider(options: {
637
+ tokens: Record<string, string>;
638
+ orgId: string;
639
+ adminRole: string;
640
+ }): AuthProvider;
641
+ interface HttpTestHarnessOptions<T = unknown> {
642
+ /** Fastify app instance (must be ready) */
643
+ app: FastifyInstance;
644
+ /** Test data fixtures */
645
+ fixtures: {
646
+ /** Valid payload for creating a resource */valid: Partial<T>; /** Payload for updating a resource (defaults to valid) */
647
+ update?: Partial<T>; /** Invalid payload that should fail validation */
648
+ invalid?: Partial<T>;
649
+ };
650
+ /** Auth provider for generating request headers */
651
+ auth: AuthProvider;
652
+ /** API path prefix (default: '/api') */
653
+ apiPrefix?: string;
654
+ }
655
+ /** Options can be passed directly or as a getter for deferred resolution */
656
+ type OptionsOrGetter<T> = HttpTestHarnessOptions<T> | (() => HttpTestHarnessOptions<T>);
657
+ /**
658
+ * HTTP-level test harness for Arc resources.
659
+ *
660
+ * Generates tests that exercise the full HTTP lifecycle:
661
+ * routes, auth, permissions, pipeline, and response envelope.
662
+ *
663
+ * Supports deferred options via a getter function, which is essential
664
+ * when the app instance comes from async `beforeAll()` setup.
665
+ */
666
+ declare class HttpTestHarness<T = unknown> {
667
+ private resource;
668
+ private optionsOrGetter;
669
+ private baseUrl;
670
+ private enabledRoutes;
671
+ private updateMethod;
672
+ constructor(resource: ResourceDefinition<unknown>, optionsOrGetter: OptionsOrGetter<T>);
673
+ /** Resolve options (supports both direct and deferred) */
674
+ private getOptions;
675
+ /**
676
+ * Run all test suites: CRUD + permissions + validation
677
+ */
678
+ runAll(): void;
679
+ /**
680
+ * Run HTTP-level CRUD tests.
681
+ *
682
+ * Tests each enabled CRUD operation through app.inject():
683
+ * - POST (create) → 200/201 with { success: true, data }
684
+ * - GET (list) → 200 with array or paginated response
685
+ * - GET /:id → 200 with { success: true, data }
686
+ * - PATCH/PUT /:id → 200 with { success: true, data }
687
+ * - DELETE /:id → 200
688
+ * - GET /:id with non-existent ID → 404
689
+ */
690
+ runCrud(): void;
691
+ /**
692
+ * Run permission tests.
693
+ *
694
+ * Tests that:
695
+ * - Unauthenticated requests return 401
696
+ * - Admin role gets 2xx for all operations
697
+ */
698
+ runPermissions(): void;
699
+ /**
700
+ * Run validation tests.
701
+ *
702
+ * Tests that invalid payloads return 400.
703
+ */
704
+ runValidation(): void;
705
+ }
706
+ /**
707
+ * Create an HTTP test harness for an Arc resource.
708
+ *
709
+ * Accepts options directly or as a getter function for deferred resolution.
710
+ *
711
+ * @example Deferred (recommended for async setup)
712
+ * ```typescript
713
+ * let ctx: TestContext;
714
+ * beforeAll(async () => { ctx = await setupTestOrg(); });
715
+ *
716
+ * createHttpTestHarness(jobResource, () => ({
717
+ * app: ctx.app,
718
+ * fixtures: { valid: { title: 'Test' } },
719
+ * auth: createBetterAuthProvider({ ... }),
720
+ * })).runAll();
721
+ * ```
722
+ */
723
+ declare function createHttpTestHarness<T = unknown>(resource: ResourceDefinition<unknown>, optionsOrGetter: HttpTestHarnessOptions<T> | (() => HttpTestHarnessOptions<T>)): HttpTestHarness<T>;
724
+ //#endregion
725
+ //#region src/testing/dbHelpers.d.ts
726
+ /**
727
+ * Test database manager
728
+ */
729
+ declare class TestDatabase {
730
+ private connection?;
731
+ private dbName;
732
+ constructor(dbName?: string);
733
+ /**
734
+ * Connect to test database
735
+ */
736
+ connect(uri?: string): Promise<Connection>;
737
+ /**
738
+ * Disconnect and cleanup
739
+ */
740
+ disconnect(): Promise<void>;
741
+ /**
742
+ * Clear all collections
743
+ */
744
+ clear(): Promise<void>;
745
+ /**
746
+ * Get connection
747
+ */
748
+ getConnection(): Connection;
749
+ }
750
+ /**
751
+ * Higher-order function to wrap tests with database setup/teardown
752
+ *
753
+ * @example
754
+ * describe('Product Tests', () => {
755
+ * withTestDb(async (db) => {
756
+ * test('create product', async () => {
757
+ * const Product = db.getConnection().model('Product', schema);
758
+ * const product = await Product.create({ name: 'Test' });
759
+ * expect(product.name).toBe('Test');
760
+ * });
761
+ * });
762
+ * });
763
+ */
764
+ declare function withTestDb(tests: (db: TestDatabase) => void | Promise<void>, options?: {
765
+ uri?: string;
766
+ dbName?: string;
767
+ }): void;
768
+ /**
769
+ * Create test fixtures
770
+ *
771
+ * @example
772
+ * const fixtures = new TestFixtures(connection);
773
+ *
774
+ * await fixtures.load('products', [
775
+ * { name: 'Product 1', price: 100 },
776
+ * { name: 'Product 2', price: 200 },
777
+ * ]);
778
+ *
779
+ * const products = await fixtures.get('products');
780
+ */
781
+ declare class TestFixtures {
782
+ private fixtures;
783
+ private connection;
784
+ constructor(connection: Connection);
785
+ /**
786
+ * Load fixtures into a collection
787
+ */
788
+ load<T = any>(collectionName: string, data: Partial<T>[]): Promise<T[]>;
789
+ /**
790
+ * Get loaded fixtures
791
+ */
792
+ get<T = any>(collectionName: string): T[];
793
+ /**
794
+ * Get first fixture
795
+ */
796
+ getFirst<T = any>(collectionName: string): T | null;
797
+ /**
798
+ * Clear all fixtures
799
+ */
800
+ clear(): Promise<void>;
801
+ }
802
+ /**
803
+ * In-memory MongoDB for ultra-fast tests
804
+ *
805
+ * Requires: mongodb-memory-server
806
+ *
807
+ * @example
808
+ * import { InMemoryDatabase } from '@classytic/arc/testing';
809
+ *
810
+ * describe('Fast Tests', () => {
811
+ * const memoryDb = new InMemoryDatabase();
812
+ *
813
+ * beforeAll(async () => {
814
+ * await memoryDb.start();
815
+ * });
816
+ *
817
+ * afterAll(async () => {
818
+ * await memoryDb.stop();
819
+ * });
820
+ *
821
+ * test('create user', async () => {
822
+ * const uri = memoryDb.getUri();
823
+ * // Use uri for connection
824
+ * });
825
+ * });
826
+ */
827
+ declare class InMemoryDatabase {
828
+ private mongod?;
829
+ private uri?;
830
+ /**
831
+ * Start in-memory MongoDB
832
+ */
833
+ start(): Promise<string>;
834
+ /**
835
+ * Stop in-memory MongoDB
836
+ */
837
+ stop(): Promise<void>;
838
+ /**
839
+ * Get connection URI
840
+ */
841
+ getUri(): string;
842
+ }
843
+ /**
844
+ * Database transaction helper for testing
845
+ */
846
+ declare class TestTransaction {
847
+ private session?;
848
+ private connection;
849
+ constructor(connection: Connection);
850
+ /**
851
+ * Start transaction
852
+ */
853
+ start(): Promise<void>;
854
+ /**
855
+ * Commit transaction
856
+ */
857
+ commit(): Promise<void>;
858
+ /**
859
+ * Rollback transaction
860
+ */
861
+ rollback(): Promise<void>;
862
+ /**
863
+ * Get session
864
+ */
865
+ getSession(): any;
866
+ }
867
+ /**
868
+ * Seed data helper
869
+ */
870
+ declare class TestSeeder {
871
+ private connection;
872
+ constructor(connection: Connection);
873
+ /**
874
+ * Seed collection with data
875
+ */
876
+ seed<T>(collectionName: string, generator: () => T[], count?: number): Promise<T[]>;
877
+ /**
878
+ * Clear collection
879
+ */
880
+ clear(collectionName: string): Promise<void>;
881
+ /**
882
+ * Clear all collections
883
+ */
884
+ clearAll(): Promise<void>;
885
+ }
886
+ /**
887
+ * Database snapshot helper for rollback testing
888
+ */
889
+ declare class DatabaseSnapshot {
890
+ private snapshots;
891
+ private connection;
892
+ constructor(connection: Connection);
893
+ /**
894
+ * Take snapshot of current database state
895
+ */
896
+ take(): Promise<void>;
897
+ /**
898
+ * Restore database to snapshot
899
+ */
900
+ restore(): Promise<void>;
901
+ /**
902
+ * Clear snapshot
903
+ */
904
+ clear(): void;
905
+ }
906
+ //#endregion
907
+ export { type AuthProvider, type AuthResponse, type BetterAuthTestHelpers, type BetterAuthTestHelpersOptions, type CreateTestAppOptions, DatabaseSnapshot, TestFixtures as DbTestFixtures, type GenerateTestFileOptions, HttpTestHarness, type HttpTestHarnessOptions, InMemoryDatabase, type OrgResponse, type SetupBetterAuthOrgOptions, type SetupUserConfig, type TestAppResult, TestDataLoader, TestDatabase, type TestFixtures$1 as TestFixtures, TestHarness, type TestHarnessOptions, type TestOrgContext, TestRequestBuilder, TestSeeder, TestTransaction, type TestUserContext, createBetterAuthProvider, createBetterAuthTestHelpers, createConfigTestSuite, createDataFactory, createHttpTestHarness, createJwtAuthProvider, createMinimalTestApp, createMockController, createMockReply, createMockRepository, createMockRequest, createMockUser, createSnapshotMatcher, createSpy, createTestApp, createTestAuth, createTestHarness, createTestTimer, generateTestFile, request, safeParseBody, setupBetterAuthOrg, waitFor, withTestDb };
908
+ //# sourceMappingURL=index.d.mts.map