@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/discovery/index.ts"],"sourcesContent":["/**\n * Arc Auto-Discovery Plugin\n *\n * Automatically discovers and registers resource files matching a glob pattern.\n * Eliminates manual resource registration boilerplate.\n *\n * This is a SEPARATE subpath import — only loaded when explicitly used:\n * import { discoveryPlugin, discoverResources } from '@classytic/arc/discovery';\n *\n * Serverless-safe: only runs at startup, no persistent process needed.\n *\n * @example\n * ```typescript\n * import { discoveryPlugin } from '@classytic/arc/discovery';\n *\n * // Auto-discovers all *.resource.ts files\n * await fastify.register(discoveryPlugin, {\n * paths: ['./src/modules'],\n * pattern: '**\\/*.resource.{ts,js}',\n * });\n *\n * // Or use the helper directly\n * import { discoverResources } from '@classytic/arc/discovery';\n *\n * const resources = await discoverResources({\n * paths: ['./src/modules'],\n * pattern: '**\\/*.resource.{ts,js}',\n * });\n *\n * for (const resource of resources) {\n * await fastify.register(resource.toPlugin());\n * }\n * ```\n */\nimport type { FastifyInstance, FastifyPluginAsync } from 'fastify';\nimport { readdir, stat } from 'node:fs/promises';\nimport { join, resolve, extname } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** A discovered resource — must have toPlugin() method */\nexport interface DiscoverableResource {\n toPlugin(): FastifyPluginAsync;\n name?: string;\n definition?: { name: string };\n}\n\nexport interface DiscoveryOptions {\n /** Directories to scan (relative to cwd or absolute) */\n paths: string[];\n /**\n * File name pattern to match.\n * Supports simple globs: *.resource.ts, *.resource.js\n * Default: '*.resource.{ts,js}'\n */\n pattern?: string;\n /** Export name to look for in each file (default: 'default' then first ResourceDefinition) */\n exportName?: string;\n /** Filter function to include/exclude discovered resources */\n filter?: (resource: DiscoverableResource, filePath: string) => boolean;\n /** Called for each discovered resource (for logging) */\n onDiscover?: (name: string, filePath: string) => void;\n /** Whether to scan recursively (default: true) */\n recursive?: boolean;\n}\n\nexport interface DiscoveryPluginOptions extends DiscoveryOptions {\n /** URL prefix applied to all discovered resources */\n prefix?: string;\n}\n\n// ============================================================================\n// File Discovery (pure filesystem, no glob library needed)\n// ============================================================================\n\n/**\n * Match a filename against a simple pattern.\n * Supports: *.resource.ts, *.resource.js, *.resource.{ts,js}\n */\nfunction matchPattern(filename: string, pattern: string): boolean {\n // Expand {ts,js} brace patterns\n if (pattern.includes('{') && pattern.includes('}')) {\n const match = pattern.match(/\\{([^}]+)\\}/);\n if (match) {\n const alternatives = match[1]!.split(',').map((s) => s.trim());\n return alternatives.some((alt) => {\n const expanded = pattern.replace(match[0], alt);\n return matchPattern(filename, expanded);\n });\n }\n }\n\n // Simple wildcard: *.resource.ts → any file ending with .resource.ts\n if (pattern.startsWith('*')) {\n const suffix = pattern.slice(1);\n return filename.endsWith(suffix);\n }\n\n // Exact match\n return filename === pattern;\n}\n\n/**\n * Recursively scan directories for files matching a pattern.\n */\nasync function scanDirectory(\n dir: string,\n pattern: string,\n recursive: boolean\n): Promise<string[]> {\n const results: string[] = [];\n const resolvedDir = resolve(dir);\n\n const entries = await readdir(resolvedDir, { withFileTypes: true }).catch(\n () => [] as { name: string; isFile(): boolean; isDirectory(): boolean }[],\n );\n\n for (const entry of entries) {\n const fullPath = join(resolvedDir, String(entry.name));\n\n if (entry.isDirectory() && recursive) {\n const nested = await scanDirectory(fullPath, pattern, recursive);\n results.push(...nested);\n } else if (entry.isFile()) {\n // Strip any path prefix from pattern (e.g., **/*.resource.ts → *.resource.ts)\n const filePattern = pattern.replace(/^\\*\\*\\//, '');\n if (matchPattern(String(entry.name), filePattern)) {\n results.push(fullPath);\n }\n }\n }\n\n return results;\n}\n\n// ============================================================================\n// Resource Discovery\n// ============================================================================\n\n/**\n * Discover and import resource files.\n *\n * @returns Array of discovered resources with their file paths\n */\nexport async function discoverResources(\n options: DiscoveryOptions\n): Promise<Array<{ resource: DiscoverableResource; filePath: string }>> {\n const {\n paths,\n pattern = '*.resource.{ts,js}',\n exportName,\n filter,\n onDiscover,\n recursive = true,\n } = options;\n\n const discovered: Array<{ resource: DiscoverableResource; filePath: string }> = [];\n\n // Scan all directories\n const allFiles: string[] = [];\n for (const dir of paths) {\n const files = await scanDirectory(dir, pattern, recursive);\n allFiles.push(...files);\n }\n\n // Sort for deterministic registration order\n allFiles.sort();\n\n // Import each file and extract the resource\n for (const filePath of allFiles) {\n const ext = extname(filePath);\n // Only import .js and .mjs files (compiled output). .ts files need a loader.\n // In development with tsx/ts-node, .ts files work too.\n const fileUrl = pathToFileURL(filePath).href;\n\n let module: Record<string, unknown>;\n try {\n module = await import(fileUrl);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to import resource file: ${filePath}\\n${message}`);\n }\n\n // Find the resource export\n let resource: DiscoverableResource | null = null;\n\n // 1. Check specific export name\n if (exportName && module[exportName]) {\n resource = module[exportName] as DiscoverableResource;\n }\n\n // 2. Check default export\n if (!resource && module.default && typeof (module.default as Record<string, unknown>).toPlugin === 'function') {\n resource = module.default as DiscoverableResource;\n }\n\n // 3. Search for first export with toPlugin()\n if (!resource) {\n for (const value of Object.values(module)) {\n if (value && typeof value === 'object' && typeof (value as Record<string, unknown>).toPlugin === 'function') {\n resource = value as DiscoverableResource;\n break;\n }\n }\n }\n\n if (!resource) {\n throw new Error(\n `No resource found in: ${filePath}\\n` +\n 'Resource files must export an object with a toPlugin() method.\\n' +\n 'Use defineResource() or export the resource as default.'\n );\n }\n\n // Apply filter\n if (filter && !filter(resource, filePath)) {\n continue;\n }\n\n const name = resource.definition?.name ?? resource.name ?? filePath;\n onDiscover?.(name, filePath);\n discovered.push({ resource, filePath });\n }\n\n return discovered;\n}\n\n// ============================================================================\n// Fastify Plugin\n// ============================================================================\n\nconst discoveryPluginImpl: FastifyPluginAsync<DiscoveryPluginOptions> = async (\n fastify: FastifyInstance,\n options: DiscoveryPluginOptions\n) => {\n const { prefix, ...discoveryOptions } = options;\n\n const discovered = await discoverResources({\n ...discoveryOptions,\n onDiscover: discoveryOptions.onDiscover ?? ((name, filePath) => {\n fastify.log.debug({ resource: name, file: filePath }, 'Auto-discovered resource');\n }),\n });\n\n // Register all discovered resources\n for (const { resource } of discovered) {\n const plugin = resource.toPlugin();\n if (prefix) {\n await fastify.register(plugin, { prefix });\n } else {\n await fastify.register(plugin);\n }\n }\n\n fastify.log.debug(\n `Auto-discovery: registered ${discovered.length} resource(s)`\n );\n};\n\n/** Auto-discovery plugin for Arc resources */\nexport const discoveryPlugin: FastifyPluginAsync<DiscoveryPluginOptions> = discoveryPluginImpl;\nexport default discoveryPlugin;\n"],"mappings":";;;;;;;;;AAkFA,SAAS,aAAa,UAAkB,SAA0B;AAEhE,KAAI,QAAQ,SAAS,IAAI,IAAI,QAAQ,SAAS,IAAI,EAAE;EAClD,MAAM,QAAQ,QAAQ,MAAM,cAAc;AAC1C,MAAI,MAEF,QADqB,MAAM,GAAI,MAAM,IAAI,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC,CAC1C,MAAM,QAAQ;AAEhC,UAAO,aAAa,UADH,QAAQ,QAAQ,MAAM,IAAI,IAAI,CACR;IACvC;;AAKN,KAAI,QAAQ,WAAW,IAAI,EAAE;EAC3B,MAAM,SAAS,QAAQ,MAAM,EAAE;AAC/B,SAAO,SAAS,SAAS,OAAO;;AAIlC,QAAO,aAAa;;;;;AAMtB,eAAe,cACb,KACA,SACA,WACmB;CACnB,MAAM,UAAoB,EAAE;CAC5B,MAAM,cAAc,QAAQ,IAAI;CAEhC,MAAM,UAAU,MAAM,QAAQ,aAAa,EAAE,eAAe,MAAM,CAAC,CAAC,YAC5D,EAAE,CACT;AAED,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,WAAW,KAAK,aAAa,OAAO,MAAM,KAAK,CAAC;AAEtD,MAAI,MAAM,aAAa,IAAI,WAAW;GACpC,MAAM,SAAS,MAAM,cAAc,UAAU,SAAS,UAAU;AAChE,WAAQ,KAAK,GAAG,OAAO;aACd,MAAM,QAAQ,EAAE;GAEzB,MAAM,cAAc,QAAQ,QAAQ,WAAW,GAAG;AAClD,OAAI,aAAa,OAAO,MAAM,KAAK,EAAE,YAAY,CAC/C,SAAQ,KAAK,SAAS;;;AAK5B,QAAO;;;;;;;AAYT,eAAsB,kBACpB,SACsE;CACtE,MAAM,EACJ,OACA,UAAU,sBACV,YACA,QACA,YACA,YAAY,SACV;CAEJ,MAAM,aAA0E,EAAE;CAGlF,MAAM,WAAqB,EAAE;AAC7B,MAAK,MAAM,OAAO,OAAO;EACvB,MAAM,QAAQ,MAAM,cAAc,KAAK,SAAS,UAAU;AAC1D,WAAS,KAAK,GAAG,MAAM;;AAIzB,UAAS,MAAM;AAGf,MAAK,MAAM,YAAY,UAAU;AACnB,UAAQ,SAAS;EAG7B,MAAM,UAAU,cAAc,SAAS,CAAC;EAExC,IAAI;AACJ,MAAI;AACF,YAAS,MAAM,OAAO;WACf,KAAK;GACZ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAChE,SAAM,IAAI,MAAM,mCAAmC,SAAS,IAAI,UAAU;;EAI5E,IAAI,WAAwC;AAG5C,MAAI,cAAc,OAAO,YACvB,YAAW,OAAO;AAIpB,MAAI,CAAC,YAAY,OAAO,WAAW,OAAQ,OAAO,QAAoC,aAAa,WACjG,YAAW,OAAO;AAIpB,MAAI,CAAC,UACH;QAAK,MAAM,SAAS,OAAO,OAAO,OAAO,CACvC,KAAI,SAAS,OAAO,UAAU,YAAY,OAAQ,MAAkC,aAAa,YAAY;AAC3G,eAAW;AACX;;;AAKN,MAAI,CAAC,SACH,OAAM,IAAI,MACR,yBAAyB,SAAS;yDAGnC;AAIH,MAAI,UAAU,CAAC,OAAO,UAAU,SAAS,CACvC;EAGF,MAAM,OAAO,SAAS,YAAY,QAAQ,SAAS,QAAQ;AAC3D,eAAa,MAAM,SAAS;AAC5B,aAAW,KAAK;GAAE;GAAU;GAAU,CAAC;;AAGzC,QAAO;;AAOT,MAAM,sBAAkE,OACtE,SACA,YACG;CACH,MAAM,EAAE,QAAQ,GAAG,qBAAqB;CAExC,MAAM,aAAa,MAAM,kBAAkB;EACzC,GAAG;EACH,YAAY,iBAAiB,gBAAgB,MAAM,aAAa;AAC9D,WAAQ,IAAI,MAAM;IAAE,UAAU;IAAM,MAAM;IAAU,EAAE,2BAA2B;;EAEpF,CAAC;AAGF,MAAK,MAAM,EAAE,cAAc,YAAY;EACrC,MAAM,SAAS,SAAS,UAAU;AAClC,MAAI,OACF,OAAM,QAAQ,SAAS,QAAQ,EAAE,QAAQ,CAAC;MAE1C,OAAM,QAAQ,SAAS,OAAO;;AAIlC,SAAQ,IAAI,MACV,8BAA8B,WAAW,OAAO,cACjD;;;AAIH,MAAa,kBAA8D"}
@@ -0,0 +1,163 @@
1
+ import "../elevation-B_2dRLVP.mjs";
2
+ import "../interface-Ch8HU9uM.mjs";
3
+ import "../types-aYB4V7uN.mjs";
4
+ import { RegistryEntry } from "../types/index.mjs";
5
+ import { t as ExternalOpenApiPaths } from "../externalPaths-DlINfKbP.mjs";
6
+ import { FastifyPluginAsync } from "fastify";
7
+
8
+ //#region src/docs/openapi.d.ts
9
+ interface OpenApiOptions {
10
+ /** API title */
11
+ title?: string;
12
+ /** API version */
13
+ version?: string;
14
+ /** API description */
15
+ description?: string;
16
+ /** Server URL */
17
+ serverUrl?: string;
18
+ /** Route prefix for spec endpoint (default: '/_docs') */
19
+ prefix?: string;
20
+ /** API prefix for all resource paths (e.g., '/api/v1') */
21
+ apiPrefix?: string;
22
+ /** Auth roles required to access spec (default: [] = public) */
23
+ authRoles?: string[];
24
+ /** Include internal routes (default: false) */
25
+ includeInternal?: boolean;
26
+ /** Custom OpenAPI extensions */
27
+ extensions?: Record<string, unknown>;
28
+ }
29
+ interface OpenApiSpec {
30
+ openapi: string;
31
+ info: {
32
+ title: string;
33
+ version: string;
34
+ description?: string;
35
+ };
36
+ servers?: Array<{
37
+ url: string;
38
+ description?: string;
39
+ }>;
40
+ paths: Record<string, PathItem>;
41
+ components: {
42
+ schemas: Record<string, SchemaObject>;
43
+ securitySchemes?: Record<string, SecurityScheme>;
44
+ };
45
+ tags: Array<{
46
+ name: string;
47
+ description?: string;
48
+ }>;
49
+ security?: Array<Record<string, string[]>>;
50
+ }
51
+ interface OpenApiBuildOptions {
52
+ title?: string;
53
+ version?: string;
54
+ description?: string;
55
+ serverUrl?: string;
56
+ apiPrefix?: string;
57
+ }
58
+ interface PathItem {
59
+ get?: Operation;
60
+ post?: Operation;
61
+ put?: Operation;
62
+ patch?: Operation;
63
+ delete?: Operation;
64
+ options?: Operation;
65
+ head?: Operation;
66
+ }
67
+ interface Operation {
68
+ tags: string[];
69
+ summary: string;
70
+ description?: string;
71
+ operationId: string;
72
+ parameters?: Parameter[];
73
+ requestBody?: RequestBody;
74
+ responses: Record<string, Response>;
75
+ security?: Array<Record<string, string[]>>;
76
+ /** Arc permission metadata (OpenAPI extension) */
77
+ 'x-arc-permission'?: {
78
+ type: string;
79
+ roles?: readonly string[];
80
+ };
81
+ /** Arc pipeline steps (OpenAPI extension) */
82
+ 'x-arc-pipeline'?: Array<{
83
+ type: string;
84
+ name: string;
85
+ }>;
86
+ }
87
+ interface Parameter {
88
+ name: string;
89
+ in: 'path' | 'query' | 'header';
90
+ required?: boolean;
91
+ schema: SchemaObject;
92
+ description?: string;
93
+ }
94
+ interface RequestBody {
95
+ required?: boolean;
96
+ content: Record<string, {
97
+ schema: SchemaObject;
98
+ }>;
99
+ }
100
+ interface Response {
101
+ description: string;
102
+ content?: Record<string, {
103
+ schema: SchemaObject;
104
+ }>;
105
+ }
106
+ interface SchemaObject {
107
+ type?: string;
108
+ format?: string;
109
+ properties?: Record<string, SchemaObject>;
110
+ items?: SchemaObject;
111
+ required?: string[];
112
+ $ref?: string;
113
+ description?: string;
114
+ example?: unknown;
115
+ additionalProperties?: boolean | SchemaObject;
116
+ enum?: string[];
117
+ minimum?: number;
118
+ maximum?: number;
119
+ minLength?: number;
120
+ maxLength?: number;
121
+ pattern?: string;
122
+ }
123
+ interface SecurityScheme {
124
+ type: string;
125
+ scheme?: string;
126
+ bearerFormat?: string;
127
+ in?: string;
128
+ name?: string;
129
+ }
130
+ declare const openApiPlugin: FastifyPluginAsync<OpenApiOptions>;
131
+ /**
132
+ * Build OpenAPI spec from registry resources.
133
+ * Shared by HTTP docs endpoint and CLI export command.
134
+ */
135
+ declare function buildOpenApiSpec(resources: RegistryEntry[], options?: OpenApiBuildOptions, externalPaths?: ExternalOpenApiPaths[]): OpenApiSpec;
136
+ declare const _default: FastifyPluginAsync<OpenApiOptions>;
137
+ //#endregion
138
+ //#region src/docs/scalar.d.ts
139
+ interface ScalarOptions {
140
+ /** Route prefix for UI (default: '/docs') */
141
+ routePrefix?: string;
142
+ /** OpenAPI spec URL (default: '/_docs/openapi.json') */
143
+ specUrl?: string;
144
+ /** Page title */
145
+ title?: string;
146
+ /** Theme (default: 'default') */
147
+ theme?: 'default' | 'alternate' | 'moon' | 'purple' | 'solarized' | 'bluePlanet' | 'saturn' | 'kepler' | 'mars' | 'deepSpace';
148
+ /** Show sidebar (default: true) */
149
+ showSidebar?: boolean;
150
+ /** Dark mode (default: false) */
151
+ darkMode?: boolean;
152
+ /** Auth roles required to access docs */
153
+ authRoles?: string[];
154
+ /** Custom CSS */
155
+ customCss?: string;
156
+ /** Favicon URL */
157
+ favicon?: string;
158
+ }
159
+ declare const scalarPlugin: FastifyPluginAsync<ScalarOptions>;
160
+ declare const _default$1: FastifyPluginAsync<ScalarOptions>;
161
+ //#endregion
162
+ export { type ExternalOpenApiPaths, type OpenApiBuildOptions, type OpenApiOptions, type OpenApiSpec, type ScalarOptions, buildOpenApiSpec, _default as openApiPlugin, openApiPlugin as openApiPluginFn, _default$1 as scalarPlugin, scalarPlugin as scalarPluginFn };
163
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/docs/openapi.ts","../../src/docs/scalar.ts"],"mappings":";;;;;;;;UAuBiB,cAAA;EAgBf;EAdA,KAAA;EAgBa;EAdb,OAAA;EAcmB;EAZnB,WAAA;EAe0B;EAb1B,SAAA;EAoBU;EAlBV,MAAA;EAmBO;EAjBP,SAAA;EAmBW;EAjBX,SAAA;EAkBoB;EAhBpB,eAAA;EAmBiB;EAjBjB,UAAA,GAAa,MAAA;AAAA;AAAA,UAGE,WAAA;EACf,OAAA;EACA,IAAA;IACE,KAAA;IACA,OAAA;IACA,WAAA;EAAA;EAEF,OAAA,GAAU,KAAA;IAAQ,GAAA;IAAa,WAAA;EAAA;EAC/B,KAAA,EAAO,MAAA,SAAe,QAAA;EACtB,UAAA;IACE,OAAA,EAAS,MAAA,SAAe,YAAA;IACxB,eAAA,GAAkB,MAAA,SAAe,cAAA;EAAA;EAEnC,IAAA,EAAM,KAAA;IAAQ,IAAA;IAAc,WAAA;EAAA;EAC5B,QAAA,GAAW,KAAA,CAAM,MAAA;AAAA;AAAA,UAGF,mBAAA;EACf,KAAA;EACA,OAAA;EACA,WAAA;EACA,SAAA;EACA,SAAA;AAAA;AAAA,UAGQ,QAAA;EACR,GAAA,GAAM,SAAA;EACN,IAAA,GAAO,SAAA;EACP,GAAA,GAAM,SAAA;EACN,KAAA,GAAQ,SAAA;EACR,MAAA,GAAS,SAAA;EACT,OAAA,GAAU,SAAA;EACV,IAAA,GAAO,SAAA;AAAA;AAAA,UAGC,SAAA;EACR,IAAA;EACA,OAAA;EACA,WAAA;EACA,WAAA;EACA,UAAA,GAAa,SAAA;EACb,WAAA,GAAc,WAAA;EACd,SAAA,EAAW,MAAA,SAAe,QAAA;EAC1B,QAAA,GAAW,KAAA,CAAM,MAAA;EAbR;EAeT,kBAAA;IAAuB,IAAA;IAAc,KAAA;EAAA;EAnBrC;EAqBA,gBAAA,GAAmB,KAAA;IAAQ,IAAA;IAAc,IAAA;EAAA;AAAA;AAAA,UAGjC,SAAA;EACR,IAAA;EACA,EAAA;EACA,QAAA;EACA,MAAA,EAAQ,YAAA;EACR,WAAA;AAAA;AAAA,UAGQ,WAAA;EACR,QAAA;EACA,OAAA,EAAS,MAAA;IAAiB,MAAA,EAAQ,YAAA;EAAA;AAAA;AAAA,UAG1B,QAAA;EACR,WAAA;EACA,OAAA,GAAU,MAAA;IAAiB,MAAA,EAAQ,YAAA;EAAA;AAAA;AAAA,UAG3B,YAAA;EACR,IAAA;EACA,MAAA;EACA,UAAA,GAAa,MAAA,SAAe,YAAA;EAC5B,KAAA,GAAQ,YAAA;EACR,QAAA;EACA,IAAA;EACA,WAAA;EACA,OAAA;EACA,oBAAA,aAAiC,YAAA;EACjC,IAAA;EACA,OAAA;EACA,OAAA;EACA,SAAA;EACA,SAAA;EACA,OAAA;AAAA;AAAA,UAGQ,cAAA;EACR,IAAA;EACA,MAAA;EACA,YAAA;EACA,EAAA;EACA,IAAA;AAAA;AAAA,cAGI,aAAA,EAAe,kBAAA,CAAmB,cAAA;;AA/CO;;;iBAmG/B,gBAAA,CACd,SAAA,EAAW,aAAA,IACX,OAAA,GAAS,mBAAA,EACT,aAAA,GAAgB,oBAAA,KACf,WAAA;AAAA,cAkGF,QAAA;;;UChRgB,aAAA;EDiBf;ECfA,WAAA;EDmBA;ECjBA,OAAA;EDiBmB;ECfnB,KAAA;EDkBe;EChBf,KAAA;;EAEA,WAAA;EDsBsB;ECpBtB,QAAA;EDsB0B;ECpB1B,SAAA;EDqBmC;ECnBnC,SAAA;EDqBM;ECnBN,OAAA;AAAA;AAAA,cAGI,YAAA,EAAc,kBAAA,CAAmB,aAAA;AAAA,cAAa,UAAA"}
@@ -0,0 +1,73 @@
1
+ import { n as openApiPlugin, r as openapi_default, t as buildOpenApiSpec } from "../openapi-G3Cw7XuM.mjs";
2
+ import fp from "fastify-plugin";
3
+
4
+ //#region src/docs/scalar.ts
5
+ /**
6
+ * Scalar API Reference Plugin
7
+ *
8
+ * Beautiful, modern API documentation UI.
9
+ * Lighter and more modern than Swagger UI.
10
+ *
11
+ * @example
12
+ * import { scalarPlugin } from '@classytic/arc/docs';
13
+ *
14
+ * await fastify.register(scalarPlugin, {
15
+ * routePrefix: '/docs',
16
+ * specUrl: '/_docs/openapi.json',
17
+ * });
18
+ *
19
+ * // UI available at /docs
20
+ */
21
+ const scalarPlugin = async (fastify, opts = {}) => {
22
+ const { routePrefix = "/docs", specUrl = "/_docs/openapi.json", title = "API Documentation", theme = "default", showSidebar = true, darkMode = false, authRoles = [], customCss = "", favicon } = opts;
23
+ const scalarConfig = JSON.stringify({
24
+ spec: { url: specUrl },
25
+ theme,
26
+ showSidebar,
27
+ darkMode,
28
+ ...favicon && { favicon }
29
+ });
30
+ const html = `<!DOCTYPE html>
31
+ <html>
32
+ <head>
33
+ <meta charset="utf-8">
34
+ <meta name="viewport" content="width=device-width, initial-scale=1">
35
+ <title>${title}</title>
36
+ ${favicon ? `<link rel="icon" href="${favicon}">` : ""}
37
+ <style>
38
+ body { margin: 0; padding: 0; }
39
+ ${customCss}
40
+ </style>
41
+ </head>
42
+ <body>
43
+ <script id="api-reference" data-url="${specUrl}"><\/script>
44
+ <script>
45
+ var configuration = ${scalarConfig};
46
+ document.getElementById('api-reference').dataset.configuration = JSON.stringify(configuration);
47
+ <\/script>
48
+ <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"><\/script>
49
+ </body>
50
+ </html>`;
51
+ fastify.get(routePrefix, async (request, reply) => {
52
+ if (authRoles.length > 0) {
53
+ const user = request.user;
54
+ if (!authRoles.some((role) => user?.roles?.includes(role)) && !user?.roles?.includes("superadmin")) {
55
+ reply.code(403).send({ error: "Access denied" });
56
+ return;
57
+ }
58
+ }
59
+ reply.type("text/html").send(html);
60
+ });
61
+ if (!routePrefix.endsWith("/")) fastify.get(`${routePrefix}/`, async (_, reply) => {
62
+ reply.redirect(routePrefix);
63
+ });
64
+ fastify.log?.debug?.(`Scalar API docs available at ${routePrefix}`);
65
+ };
66
+ var scalar_default = fp(scalarPlugin, {
67
+ name: "arc-scalar",
68
+ fastify: "5.x"
69
+ });
70
+
71
+ //#endregion
72
+ export { buildOpenApiSpec, openapi_default as openApiPlugin, openApiPlugin as openApiPluginFn, scalar_default as scalarPlugin, scalarPlugin as scalarPluginFn };
73
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/docs/scalar.ts"],"sourcesContent":["/**\n * Scalar API Reference Plugin\n *\n * Beautiful, modern API documentation UI.\n * Lighter and more modern than Swagger UI.\n *\n * @example\n * import { scalarPlugin } from '@classytic/arc/docs';\n *\n * await fastify.register(scalarPlugin, {\n * routePrefix: '/docs',\n * specUrl: '/_docs/openapi.json',\n * });\n *\n * // UI available at /docs\n */\n\nimport fp from 'fastify-plugin';\nimport type { FastifyInstance, FastifyPluginAsync } from 'fastify';\n\nexport interface ScalarOptions {\n /** Route prefix for UI (default: '/docs') */\n routePrefix?: string;\n /** OpenAPI spec URL (default: '/_docs/openapi.json') */\n specUrl?: string;\n /** Page title */\n title?: string;\n /** Theme (default: 'default') */\n theme?: 'default' | 'alternate' | 'moon' | 'purple' | 'solarized' | 'bluePlanet' | 'saturn' | 'kepler' | 'mars' | 'deepSpace';\n /** Show sidebar (default: true) */\n showSidebar?: boolean;\n /** Dark mode (default: false) */\n darkMode?: boolean;\n /** Auth roles required to access docs */\n authRoles?: string[];\n /** Custom CSS */\n customCss?: string;\n /** Favicon URL */\n favicon?: string;\n}\n\nconst scalarPlugin: FastifyPluginAsync<ScalarOptions> = async (\n fastify: FastifyInstance,\n opts: ScalarOptions = {}\n) => {\n const {\n routePrefix = '/docs',\n specUrl = '/_docs/openapi.json',\n title = 'API Documentation',\n theme = 'default',\n showSidebar = true,\n darkMode = false,\n authRoles = [],\n customCss = '',\n favicon,\n } = opts;\n\n // Scalar configuration\n const scalarConfig = JSON.stringify({\n spec: { url: specUrl },\n theme,\n showSidebar,\n darkMode,\n ...(favicon && { favicon }),\n });\n\n // HTML template for Scalar\n const html = `<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>${title}</title>\n ${favicon ? `<link rel=\"icon\" href=\"${favicon}\">` : ''}\n <style>\n body { margin: 0; padding: 0; }\n ${customCss}\n </style>\n</head>\n<body>\n <script id=\"api-reference\" data-url=\"${specUrl}\"></script>\n <script>\n var configuration = ${scalarConfig};\n document.getElementById('api-reference').dataset.configuration = JSON.stringify(configuration);\n </script>\n <script src=\"https://cdn.jsdelivr.net/npm/@scalar/api-reference\"></script>\n</body>\n</html>`;\n\n // Serve UI (not included in OpenAPI spec)\n fastify.get(routePrefix, async (request, reply) => {\n // Check auth if required\n if (authRoles.length > 0) {\n const user = (request as { user?: { roles?: string[] } }).user;\n const hasRole = authRoles.some((role) => user?.roles?.includes(role));\n if (!hasRole && !user?.roles?.includes('superadmin')) {\n reply.code(403).send({ error: 'Access denied' });\n return;\n }\n }\n\n reply.type('text/html').send(html);\n });\n\n // Redirect /docs/ to /docs\n if (!routePrefix.endsWith('/')) {\n fastify.get(`${routePrefix}/`, async (_, reply) => {\n reply.redirect(routePrefix);\n });\n }\n\n fastify.log?.debug?.(`Scalar API docs available at ${routePrefix}`);\n};\n\nexport default fp(scalarPlugin, {\n name: 'arc-scalar',\n fastify: '5.x',\n});\n\nexport { scalarPlugin };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAyCA,MAAM,eAAkD,OACtD,SACA,OAAsB,EAAE,KACrB;CACH,MAAM,EACJ,cAAc,SACd,UAAU,uBACV,QAAQ,qBACR,QAAQ,WACR,cAAc,MACd,WAAW,OACX,YAAY,EAAE,EACd,YAAY,IACZ,YACE;CAGJ,MAAM,eAAe,KAAK,UAAU;EAClC,MAAM,EAAE,KAAK,SAAS;EACtB;EACA;EACA;EACA,GAAI,WAAW,EAAE,SAAS;EAC3B,CAAC;CAGF,MAAM,OAAO;;;;;WAKJ,MAAM;IACb,UAAU,0BAA0B,QAAQ,MAAM,GAAG;;;MAGnD,UAAU;;;;yCAIyB,QAAQ;;0BAEvB,aAAa;;;;;;AAQrC,SAAQ,IAAI,aAAa,OAAO,SAAS,UAAU;AAEjD,MAAI,UAAU,SAAS,GAAG;GACxB,MAAM,OAAQ,QAA4C;AAE1D,OAAI,CADY,UAAU,MAAM,SAAS,MAAM,OAAO,SAAS,KAAK,CAAC,IACrD,CAAC,MAAM,OAAO,SAAS,aAAa,EAAE;AACpD,UAAM,KAAK,IAAI,CAAC,KAAK,EAAE,OAAO,iBAAiB,CAAC;AAChD;;;AAIJ,QAAM,KAAK,YAAY,CAAC,KAAK,KAAK;GAClC;AAGF,KAAI,CAAC,YAAY,SAAS,IAAI,CAC5B,SAAQ,IAAI,GAAG,YAAY,IAAI,OAAO,GAAG,UAAU;AACjD,QAAM,SAAS,YAAY;GAC3B;AAGJ,SAAQ,KAAK,QAAQ,gCAAgC,cAAc;;AAGrE,qBAAe,GAAG,cAAc;CAC9B,MAAM;CACN,SAAS;CACV,CAAC"}
@@ -0,0 +1,113 @@
1
+ import { t as __exportAll } from "./chunk-C7Uep-_p.mjs";
2
+ import { t as arcLog } from "./logger-Df2O2WsW.mjs";
3
+ import fp from "fastify-plugin";
4
+
5
+ //#region src/scope/elevation.ts
6
+ /**
7
+ * Elevation Plugin — Explicit Platform Admin Access
8
+ *
9
+ * Opt-in Fastify plugin that allows platform admins to explicitly
10
+ * elevate their scope via the `x-arc-scope: platform` header.
11
+ *
12
+ * Without this header, a superadmin is treated as a normal user.
13
+ * This prevents implicit bypass and enables audit logging.
14
+ *
15
+ * ## Lifecycle
16
+ *
17
+ * Elevation wraps `fastify.authenticate` so it always runs AFTER
18
+ * authentication has set `request.user`. This avoids the `onRequest`
19
+ * timing issue where `request.user` doesn't exist yet.
20
+ *
21
+ * Flow: `authenticate()` → user is set → `elevation check` → scope is set
22
+ *
23
+ * Inspired by Stripe Connect's `Stripe-Account` header.
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * const app = await createApp({
28
+ * auth: { type: 'betterAuth', betterAuth: adapter },
29
+ * elevation: {
30
+ * platformRoles: ['superadmin'],
31
+ * onElevation: (event) => auditLog.write(event),
32
+ * },
33
+ * });
34
+ * ```
35
+ */
36
+ var elevation_exports = /* @__PURE__ */ __exportAll({
37
+ default: () => elevation_default,
38
+ elevationPlugin: () => elevationPlugin
39
+ });
40
+ const log = arcLog("elevation");
41
+ const elevationPlugin = async (fastify, opts = {}) => {
42
+ const { platformRoles = ["superadmin"], scopeHeader = "x-arc-scope", orgHeader = "x-organization-id", onElevation } = opts;
43
+ if (!fastify.hasDecorator("authenticate")) {
44
+ log.warn("authenticate decorator not found. Register auth before elevation. Elevation will not function.");
45
+ return;
46
+ }
47
+ const originalAuthenticate = fastify.authenticate;
48
+ const authenticateWithElevation = async (request, reply) => {
49
+ await originalAuthenticate.call(fastify, request, reply);
50
+ if (reply.sent) return;
51
+ if (request.headers[scopeHeader] !== "platform") return;
52
+ const user = request.user;
53
+ if (!user) {
54
+ log.debug("Elevation requested but no user after auth");
55
+ reply.code(401).send({
56
+ success: false,
57
+ error: "Unauthorized",
58
+ message: "Authentication required for platform elevation",
59
+ code: "ELEVATION_AUTH_REQUIRED"
60
+ });
61
+ return;
62
+ }
63
+ const userRoles = user.roles ?? [];
64
+ if (!platformRoles.some((r) => userRoles.includes(r))) {
65
+ log.debug("Elevation rejected — insufficient roles", {
66
+ userId: user.id ?? user._id,
67
+ userRoles,
68
+ required: platformRoles
69
+ });
70
+ reply.code(403).send({
71
+ success: false,
72
+ error: "Forbidden",
73
+ message: "Insufficient privileges for platform elevation",
74
+ code: "ELEVATION_FORBIDDEN"
75
+ });
76
+ return;
77
+ }
78
+ const orgId = request.headers[orgHeader];
79
+ const userId = String(user.id ?? user._id ?? "unknown");
80
+ request.scope = {
81
+ kind: "elevated",
82
+ organizationId: orgId || void 0,
83
+ elevatedBy: userId
84
+ };
85
+ log.debug("Scope elevated", {
86
+ userId,
87
+ organizationId: orgId
88
+ });
89
+ if (onElevation) try {
90
+ await onElevation({
91
+ userId,
92
+ organizationId: orgId || void 0,
93
+ request,
94
+ timestamp: /* @__PURE__ */ new Date()
95
+ });
96
+ } catch {
97
+ log.warn("onElevation callback threw — continuing request");
98
+ }
99
+ };
100
+ fastify.authenticate = authenticateWithElevation;
101
+ log.debug("Plugin registered", {
102
+ platformRoles,
103
+ scopeHeader
104
+ });
105
+ };
106
+ var elevation_default = fp(elevationPlugin, {
107
+ name: "arc-elevation",
108
+ fastify: "5.x"
109
+ });
110
+
111
+ //#endregion
112
+ export { elevation_default as n, elevation_exports as r, elevationPlugin as t };
113
+ //# sourceMappingURL=elevation-BRy3yFWT.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevation-BRy3yFWT.mjs","names":[],"sources":["../src/scope/elevation.ts"],"sourcesContent":["/**\n * Elevation Plugin — Explicit Platform Admin Access\n *\n * Opt-in Fastify plugin that allows platform admins to explicitly\n * elevate their scope via the `x-arc-scope: platform` header.\n *\n * Without this header, a superadmin is treated as a normal user.\n * This prevents implicit bypass and enables audit logging.\n *\n * ## Lifecycle\n *\n * Elevation wraps `fastify.authenticate` so it always runs AFTER\n * authentication has set `request.user`. This avoids the `onRequest`\n * timing issue where `request.user` doesn't exist yet.\n *\n * Flow: `authenticate()` → user is set → `elevation check` → scope is set\n *\n * Inspired by Stripe Connect's `Stripe-Account` header.\n *\n * @example\n * ```typescript\n * const app = await createApp({\n * auth: { type: 'betterAuth', betterAuth: adapter },\n * elevation: {\n * platformRoles: ['superadmin'],\n * onElevation: (event) => auditLog.write(event),\n * },\n * });\n * ```\n */\n\nimport fp from 'fastify-plugin';\nimport type { FastifyInstance, FastifyPluginAsync, FastifyReply, FastifyRequest } from 'fastify';\nimport type { RequestScope } from './types.js';\nimport { arcLog } from '../logger/index.js';\n\nconst log = arcLog('elevation');\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface ElevationOptions {\n /** Roles that can use elevation (default: ['superadmin']) */\n platformRoles?: string[];\n /** Header name for scope declaration (default: 'x-arc-scope') */\n scopeHeader?: string;\n /** Header name for target organization (default: 'x-organization-id') */\n orgHeader?: string;\n /** Called when elevation happens — use for audit logging */\n onElevation?: (event: ElevationEvent) => void | Promise<void>;\n}\n\nexport interface ElevationEvent {\n userId: string;\n organizationId?: string;\n request: FastifyRequest;\n timestamp: Date;\n}\n\n// ============================================================================\n// Plugin\n// ============================================================================\n\nconst elevationPlugin: FastifyPluginAsync<ElevationOptions> = async (\n fastify: FastifyInstance,\n opts: ElevationOptions = {},\n) => {\n const {\n platformRoles = ['superadmin'],\n scopeHeader = 'x-arc-scope',\n orgHeader = 'x-organization-id',\n onElevation,\n } = opts;\n\n // Elevation requires auth — wrap the authenticate decorator\n if (!fastify.hasDecorator('authenticate')) {\n log.warn(\n 'authenticate decorator not found. ' +\n 'Register auth before elevation. Elevation will not function.',\n );\n return;\n }\n\n const originalAuthenticate = fastify.authenticate;\n\n // Replace authenticate with elevation-aware version\n const authenticateWithElevation = async (\n request: FastifyRequest,\n reply: FastifyReply,\n ): Promise<void> => {\n // Step 1: Run original auth (sets request.user + default scope)\n await originalAuthenticate.call(fastify, request, reply);\n\n // If auth failed and sent a reply, stop\n if (reply.sent) return;\n\n // Step 2: Check elevation header\n const headerValue = request.headers[scopeHeader] as string | undefined;\n if (headerValue !== 'platform') return;\n\n // Step 3: Validate user for elevation\n const user = request.user;\n if (!user) {\n log.debug('Elevation requested but no user after auth');\n reply.code(401).send({\n success: false,\n error: 'Unauthorized',\n message: 'Authentication required for platform elevation',\n code: 'ELEVATION_AUTH_REQUIRED',\n });\n return;\n }\n\n const userRoles = (user.roles ?? []) as string[];\n if (!platformRoles.some((r) => userRoles.includes(r))) {\n log.debug('Elevation rejected — insufficient roles', {\n userId: user.id ?? user._id,\n userRoles,\n required: platformRoles,\n });\n reply.code(403).send({\n success: false,\n error: 'Forbidden',\n message: 'Insufficient privileges for platform elevation',\n code: 'ELEVATION_FORBIDDEN',\n });\n return;\n }\n\n // Step 4: Build elevated scope\n const orgId = request.headers[orgHeader] as string | undefined;\n const userId = String(user.id ?? user._id ?? 'unknown');\n\n const scope: RequestScope = {\n kind: 'elevated',\n organizationId: orgId || undefined,\n elevatedBy: userId,\n };\n\n request.scope = scope;\n log.debug('Scope elevated', { userId, organizationId: orgId });\n\n // Step 5: Fire audit callback\n if (onElevation) {\n try {\n await onElevation({\n userId,\n organizationId: orgId || undefined,\n request,\n timestamp: new Date(),\n });\n } catch {\n // Don't fail the request if audit logging fails\n log.warn('onElevation callback threw — continuing request');\n }\n }\n };\n\n // Overwrite the authenticate decorator\n fastify.authenticate = authenticateWithElevation;\n\n log.debug('Plugin registered', { platformRoles, scopeHeader });\n};\n\nexport default fp(elevationPlugin, {\n name: 'arc-elevation',\n fastify: '5.x',\n});\n\nexport { elevationPlugin };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,MAAM,MAAM,OAAO,YAAY;AA4B/B,MAAM,kBAAwD,OAC5D,SACA,OAAyB,EAAE,KACxB;CACH,MAAM,EACJ,gBAAgB,CAAC,aAAa,EAC9B,cAAc,eACd,YAAY,qBACZ,gBACE;AAGJ,KAAI,CAAC,QAAQ,aAAa,eAAe,EAAE;AACzC,MAAI,KACF,iGAED;AACD;;CAGF,MAAM,uBAAuB,QAAQ;CAGrC,MAAM,4BAA4B,OAChC,SACA,UACkB;AAElB,QAAM,qBAAqB,KAAK,SAAS,SAAS,MAAM;AAGxD,MAAI,MAAM,KAAM;AAIhB,MADoB,QAAQ,QAAQ,iBAChB,WAAY;EAGhC,MAAM,OAAO,QAAQ;AACrB,MAAI,CAAC,MAAM;AACT,OAAI,MAAM,6CAA6C;AACvD,SAAM,KAAK,IAAI,CAAC,KAAK;IACnB,SAAS;IACT,OAAO;IACP,SAAS;IACT,MAAM;IACP,CAAC;AACF;;EAGF,MAAM,YAAa,KAAK,SAAS,EAAE;AACnC,MAAI,CAAC,cAAc,MAAM,MAAM,UAAU,SAAS,EAAE,CAAC,EAAE;AACrD,OAAI,MAAM,2CAA2C;IACnD,QAAQ,KAAK,MAAM,KAAK;IACxB;IACA,UAAU;IACX,CAAC;AACF,SAAM,KAAK,IAAI,CAAC,KAAK;IACnB,SAAS;IACT,OAAO;IACP,SAAS;IACT,MAAM;IACP,CAAC;AACF;;EAIF,MAAM,QAAQ,QAAQ,QAAQ;EAC9B,MAAM,SAAS,OAAO,KAAK,MAAM,KAAK,OAAO,UAAU;AAQvD,UAAQ,QANoB;GAC1B,MAAM;GACN,gBAAgB,SAAS;GACzB,YAAY;GACb;AAGD,MAAI,MAAM,kBAAkB;GAAE;GAAQ,gBAAgB;GAAO,CAAC;AAG9D,MAAI,YACF,KAAI;AACF,SAAM,YAAY;IAChB;IACA,gBAAgB,SAAS;IACzB;IACA,2BAAW,IAAI,MAAM;IACtB,CAAC;UACI;AAEN,OAAI,KAAK,kDAAkD;;;AAMjE,SAAQ,eAAe;AAEvB,KAAI,MAAM,qBAAqB;EAAE;EAAe;EAAa,CAAC;;AAGhE,wBAAe,GAAG,iBAAiB;CACjC,MAAM;CACN,SAAS;CACV,CAAC"}
@@ -0,0 +1,88 @@
1
+ import { FastifyPluginAsync, FastifyRequest } from "fastify";
2
+
3
+ //#region src/scope/types.d.ts
4
+ /**
5
+ * Request Scope — The One Standard
6
+ *
7
+ * Discriminated union representing the access context of every request.
8
+ * Replaces scattered orgScope/orgRoles/organizationId/bypassRoles.
9
+ *
10
+ * Set once by auth adapters, read everywhere by permissions/presets/guards.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // In a permission check
15
+ * const scope = request.scope;
16
+ * if (isElevated(scope)) return true;
17
+ * if (isMember(scope) && scope.orgRoles.includes('admin')) return true;
18
+ * ```
19
+ */
20
+ /**
21
+ * Request scope — 4 kinds, 4 states, no ambiguity.
22
+ *
23
+ * | Kind | Meaning |
24
+ * |---------------|-----------------------------------|
25
+ * | public | No authentication |
26
+ * | authenticated | Logged in, no org context |
27
+ * | member | In an org with specific roles |
28
+ * | elevated | Platform admin, explicit elevation |
29
+ */
30
+ type RequestScope = {
31
+ kind: 'public';
32
+ } | {
33
+ kind: 'authenticated';
34
+ } | {
35
+ kind: 'member';
36
+ organizationId: string;
37
+ orgRoles: string[];
38
+ teamId?: string;
39
+ } | {
40
+ kind: 'elevated';
41
+ organizationId?: string;
42
+ elevatedBy: string;
43
+ };
44
+ /** Check if scope is `member` kind */
45
+ declare function isMember(scope: RequestScope): scope is Extract<RequestScope, {
46
+ kind: 'member';
47
+ }>;
48
+ /** Check if scope is `elevated` kind */
49
+ declare function isElevated(scope: RequestScope): scope is Extract<RequestScope, {
50
+ kind: 'elevated';
51
+ }>;
52
+ /** Check if scope has org access (member OR elevated) */
53
+ declare function hasOrgAccess(scope: RequestScope): boolean;
54
+ /** Check if request is authenticated (any kind except public) */
55
+ declare function isAuthenticated(scope: RequestScope): boolean;
56
+ /** Get organizationId from scope (if present) */
57
+ declare function getOrgId(scope: RequestScope): string | undefined;
58
+ /** Get org roles from scope (empty array if not a member) */
59
+ declare function getOrgRoles(scope: RequestScope): string[];
60
+ /** Get team ID from scope (only available on member kind) */
61
+ declare function getTeamId(scope: RequestScope): string | undefined;
62
+ /** Default public scope — used as initial decoration value */
63
+ declare const PUBLIC_SCOPE: Readonly<RequestScope>;
64
+ /** Default authenticated scope — used when user is logged in but no org */
65
+ declare const AUTHENTICATED_SCOPE: Readonly<RequestScope>;
66
+ //#endregion
67
+ //#region src/scope/elevation.d.ts
68
+ interface ElevationOptions {
69
+ /** Roles that can use elevation (default: ['superadmin']) */
70
+ platformRoles?: string[];
71
+ /** Header name for scope declaration (default: 'x-arc-scope') */
72
+ scopeHeader?: string;
73
+ /** Header name for target organization (default: 'x-organization-id') */
74
+ orgHeader?: string;
75
+ /** Called when elevation happens — use for audit logging */
76
+ onElevation?: (event: ElevationEvent) => void | Promise<void>;
77
+ }
78
+ interface ElevationEvent {
79
+ userId: string;
80
+ organizationId?: string;
81
+ request: FastifyRequest;
82
+ timestamp: Date;
83
+ }
84
+ declare const elevationPlugin: FastifyPluginAsync<ElevationOptions>;
85
+ declare const _default: FastifyPluginAsync<ElevationOptions>;
86
+ //#endregion
87
+ export { AUTHENTICATED_SCOPE as a, getOrgId as c, hasOrgAccess as d, isAuthenticated as f, elevationPlugin as i, getOrgRoles as l, isMember as m, ElevationOptions as n, PUBLIC_SCOPE as o, isElevated as p, _default as r, RequestScope as s, ElevationEvent as t, getTeamId as u };
88
+ //# sourceMappingURL=elevation-B_2dRLVP.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevation-B_2dRLVP.d.mts","names":[],"sources":["../src/scope/types.ts","../src/scope/elevation.ts"],"mappings":";;;;;;AA+BA;;;;;;;;;;;;;;;AAWA;;;;;;;;KAXY,YAAA;EACN,IAAA;AAAA;EACA,IAAA;AAAA;EACA,IAAA;EAAgB,cAAA;EAAwB,QAAA;EAAoB,MAAA;AAAA;EAC5D,IAAA;EAAkB,cAAA;EAAyB,UAAA;AAAA;;iBAOjC,QAAA,CAAS,KAAA,EAAO,YAAA,GAAe,KAAA,IAAS,OAAA,CAAQ,YAAA;EAAgB,IAAA;AAAA;;iBAKhE,UAAA,CAAW,KAAA,EAAO,YAAA,GAAe,KAAA,IAAS,OAAA,CAAQ,YAAA;EAAgB,IAAA;AAAA;;iBAKlE,YAAA,CAAa,KAAA,EAAO,YAAA;AAApC;AAAA,iBAKgB,eAAA,CAAgB,KAAA,EAAO,YAAA;;iBASvB,QAAA,CAAS,KAAA,EAAO,YAAA;;iBAOhB,WAAA,CAAY,KAAA,EAAO,YAAA;;iBAMnB,SAAA,CAAU,KAAA,EAAO,YAAA;;cAUpB,YAAA,EAAc,QAAA,CAAS,YAAA;AAvBpC;AAAA,cA0Ba,mBAAA,EAAqB,QAAA,CAAS,YAAA;;;UClD1B,gBAAA;EDAmE;ECElF,aAAA;EDGc;ECDd,WAAA;;EAEA,SAAA;EDDgE;ECGhE,WAAA,IAAe,KAAA,EAAO,cAAA,YAA0B,OAAA;AAAA;AAAA,UAGjC,cAAA;EACf,MAAA;EACA,cAAA;EACA,OAAA,EAAS,cAAA;EACT,SAAA,EAAW,IAAA;AAAA;AAAA,cAOP,eAAA,EAAiB,kBAAA,CAAmB,gBAAA;AAAA,cAAgB,QAAA"}
@@ -0,0 +1,73 @@
1
+ import { t as DomainEvent } from "./EventTransport-BD2U0BTc.mjs";
2
+ import { FastifyInstance, FastifyPluginAsync, FastifyRequest } from "fastify";
3
+
4
+ //#region src/plugins/caching.d.ts
5
+ interface CachingRule {
6
+ /** Path prefix to match (e.g., '/api/products') */
7
+ match: string;
8
+ /** Cache-Control max-age in seconds */
9
+ maxAge: number;
10
+ /** Cache-Control: private vs public (default: public) */
11
+ private?: boolean;
12
+ /** stale-while-revalidate directive in seconds */
13
+ staleWhileRevalidate?: number;
14
+ }
15
+ interface CachingOptions {
16
+ /** Default max-age in seconds for Cache-Control (default: 0 = no-cache) */
17
+ maxAge?: number;
18
+ /** Enable ETag generation (default: true) */
19
+ etag?: boolean;
20
+ /** Enable conditional requests — 304 Not Modified (default: true) */
21
+ conditional?: boolean;
22
+ /** HTTP methods to cache (default: ['GET', 'HEAD']) */
23
+ methods?: string[];
24
+ /** Paths to exclude from caching (prefix match) */
25
+ exclude?: string[];
26
+ /** Custom cache rules per path prefix */
27
+ rules?: CachingRule[];
28
+ }
29
+ declare const cachingPlugin: FastifyPluginAsync<CachingOptions>;
30
+ declare const _default$1: FastifyPluginAsync<CachingOptions>;
31
+ //#endregion
32
+ //#region src/plugins/sse.d.ts
33
+ interface SSEOptions {
34
+ /** SSE endpoint path (default: '/events/stream') */
35
+ path?: string;
36
+ /** Require authentication (default: true) */
37
+ requireAuth?: boolean;
38
+ /** Event patterns to stream (default: ['*'] = all) */
39
+ patterns?: string[];
40
+ /** Heartbeat interval in ms (default: 30000) */
41
+ heartbeat?: number;
42
+ /** Filter events by organizationId from request.scope (default: false) */
43
+ orgScoped?: boolean;
44
+ /** Custom event filter function */
45
+ filter?: (event: DomainEvent<unknown>, request: FastifyRequest) => boolean;
46
+ }
47
+ declare const ssePlugin: FastifyPluginAsync<SSEOptions>;
48
+ declare const _default: FastifyPluginAsync<SSEOptions>;
49
+ //#endregion
50
+ //#region src/plugins/errorHandler.d.ts
51
+ interface ErrorHandlerOptions {
52
+ /**
53
+ * Include stack trace in error responses (default: false in production)
54
+ */
55
+ includeStack?: boolean;
56
+ /**
57
+ * Custom error callback for logging to external services
58
+ */
59
+ onError?: (error: Error, request: FastifyRequest) => void | Promise<void>;
60
+ /**
61
+ * Map specific error types to custom responses
62
+ */
63
+ errorMap?: Record<string, {
64
+ statusCode: number;
65
+ code: string;
66
+ message?: string;
67
+ }>;
68
+ }
69
+ declare function errorHandlerPluginFn(fastify: FastifyInstance, options?: ErrorHandlerOptions): Promise<void>;
70
+ declare const errorHandlerPlugin: typeof errorHandlerPluginFn;
71
+ //#endregion
72
+ export { ssePlugin as a, _default$1 as c, _default as i, cachingPlugin as l, errorHandlerPlugin as n, CachingOptions as o, SSEOptions as r, CachingRule as s, ErrorHandlerOptions as t };
73
+ //# sourceMappingURL=errorHandler-BbcgBmIH.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorHandler-BbcgBmIH.d.mts","names":[],"sources":["../src/plugins/caching.ts","../src/plugins/sse.ts","../src/plugins/errorHandler.ts"],"mappings":";;;;UAwBiB,WAAA;EAqBf;EAnBA,KAAA;EAqBQ;EAnBR,MAAA;EAmBmB;EAjBnB,OAAA;EAgID;EA9HC,oBAAA;AAAA;AAAA,UAGe,cAAA;EAoCqC;EAlCpD,MAAA;;EAEA,IAAA;;EAEA,WAAA;;EAEA,OAAA;ECTe;EDWf,OAAA;;EAEA,KAAA,GAAQ,WAAA;AAAA;AAAA,cAwBJ,aAAA,EAAe,kBAAA,CAAmB,cAAA;AAAA,cAAc,UAAA;;;UCrCrC,UAAA;EDWf;ECTA,IAAA;EDWQ;ECTR,WAAA;EDSmB;ECPnB,QAAA;EDsHD;ECpHC,SAAA;ED6BmB;EC3BnB,SAAA;ED2BoD;ECzBpD,MAAA,IAAU,KAAA,EAAO,WAAA,WAAsB,OAAA,EAAS,cAAA;AAAA;AAAA,cAO5C,SAAA,EAAW,kBAAA,CAAmB,UAAA;AAAA,cAAU,QAAA;;;UC/B7B,mBAAA;EFiBf;;;EEbA,YAAA;EFqBA;;;EEhBA,OAAA,IAAW,KAAA,EAAO,KAAA,EAAO,OAAA,EAAS,cAAA,YAA0B,OAAA;EFwCxD;;;EEnCJ,QAAA,GAAW,MAAA;IACT,UAAA;IACA,IAAA;IACA,OAAA;EAAA;AAAA;AAAA,iBAcW,oBAAA,CACb,OAAA,EAAS,eAAA,EACT,OAAA,GAAS,mBAAA,GACR,OAAA;AAAA,cAoJU,kBAAA,SAAkB,oBAAA"}