@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,187 @@
1
+ import { FastifyPluginAsync, FastifyReply, FastifyRequest } from "fastify";
2
+
3
+ //#region src/auth/sessionManager.d.ts
4
+ /**
5
+ * Session data stored in the session store.
6
+ */
7
+ interface SessionData {
8
+ /** User ID associated with this session */
9
+ userId: string;
10
+ /** Timestamp (ms since epoch) when session was created */
11
+ createdAt: number;
12
+ /** Timestamp (ms since epoch) when session was last refreshed */
13
+ updatedAt: number;
14
+ /** Timestamp (ms since epoch) when session expires */
15
+ expiresAt: number;
16
+ /** Optional metadata attached to the session */
17
+ metadata?: Record<string, unknown>;
18
+ }
19
+ /**
20
+ * Session store interface.
21
+ * Implement this for custom storage backends (Redis, database, etc.).
22
+ */
23
+ interface SessionStore {
24
+ /** Retrieve a session by ID. Returns null if not found or expired. */
25
+ get(sessionId: string): Promise<SessionData | null>;
26
+ /** Create or update a session. */
27
+ set(sessionId: string, data: SessionData): Promise<void>;
28
+ /** Delete a single session. */
29
+ delete(sessionId: string): Promise<void>;
30
+ /** Delete all sessions for a user. */
31
+ deleteAll(userId: string): Promise<void>;
32
+ /** Delete all sessions for a user except the specified one. */
33
+ deleteAllExcept(userId: string, currentSessionId: string): Promise<void>;
34
+ }
35
+ /**
36
+ * Cookie configuration options.
37
+ */
38
+ interface SessionCookieOptions {
39
+ /** Send cookie only over HTTPS (default: true in production) */
40
+ secure?: boolean;
41
+ /** Prevent client-side JavaScript access (default: true) */
42
+ httpOnly?: boolean;
43
+ /** SameSite attribute (default: 'lax') */
44
+ sameSite?: 'strict' | 'lax' | 'none';
45
+ /** Cookie path (default: '/') */
46
+ path?: string;
47
+ /** Cookie domain */
48
+ domain?: string;
49
+ }
50
+ /**
51
+ * Options for creating a session manager.
52
+ */
53
+ interface SessionManagerOptions {
54
+ /** Session store implementation */
55
+ store: SessionStore;
56
+ /** Secret for signing session cookies (min 32 characters) */
57
+ secret: string;
58
+ /** Session max age in seconds (default: 604800 = 7 days) */
59
+ maxAge?: number;
60
+ /** Minimum interval between session updates in seconds (default: 86400 = 24h) */
61
+ updateAge?: number;
62
+ /** Time in seconds after which a session is no longer "fresh" (default: 600 = 10 min) */
63
+ freshAge?: number;
64
+ /** Cookie name (default: 'arc.session') */
65
+ cookieName?: string;
66
+ /** Cookie options */
67
+ cookie?: SessionCookieOptions;
68
+ }
69
+ /**
70
+ * Return type from createSessionManager.
71
+ */
72
+ interface SessionManagerResult {
73
+ /** Fastify plugin that adds session middleware */
74
+ plugin: FastifyPluginAsync;
75
+ /** PreHandler that rejects requests without a fresh session */
76
+ requireFresh: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
77
+ }
78
+ declare module 'fastify' {
79
+ interface FastifyInstance {
80
+ /** Authenticate middleware — validates session and sets request.user */
81
+ authenticate: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
82
+ /** Session management helpers */
83
+ sessionManager: {
84
+ /** Create a new session for a user */createSession: (userId: string, metadata?: Record<string, unknown>) => Promise<{
85
+ sessionId: string;
86
+ cookie: string;
87
+ }>; /** Revoke a specific session */
88
+ revokeSession: (sessionId: string) => Promise<void>; /** Revoke all sessions for a user */
89
+ revokeAllSessions: (userId: string) => Promise<void>; /** Revoke all sessions except the current one */
90
+ revokeOtherSessions: (userId: string, currentSessionId: string) => Promise<void>; /** Refresh a session (reset updatedAt, extend expiry if needed) */
91
+ refreshSession: (sessionId: string) => Promise<SessionData | null>;
92
+ };
93
+ }
94
+ interface FastifyRequest {
95
+ /** Current session data (set by session plugin) */
96
+ session?: SessionData & {
97
+ id: string;
98
+ };
99
+ }
100
+ }
101
+ interface MemorySessionStoreOptions {
102
+ /** Cleanup interval in milliseconds (default: 60000 = 1 min) */
103
+ cleanupIntervalMs?: number;
104
+ }
105
+ /**
106
+ * In-memory session store for development and single-instance deployments.
107
+ * NOT suitable for multi-instance/clustered deployments — use Redis or similar.
108
+ */
109
+ declare class MemorySessionStore implements SessionStore {
110
+ private sessions;
111
+ /** Reverse index: userId -> Set<sessionId> for efficient bulk operations */
112
+ private userIndex;
113
+ private cleanupInterval;
114
+ constructor(options?: MemorySessionStoreOptions);
115
+ get(sessionId: string): Promise<SessionData | null>;
116
+ set(sessionId: string, data: SessionData): Promise<void>;
117
+ delete(sessionId: string): Promise<void>;
118
+ deleteAll(userId: string): Promise<void>;
119
+ deleteAllExcept(userId: string, currentSessionId: string): Promise<void>;
120
+ /**
121
+ * Close the store and clean up resources.
122
+ */
123
+ close(): void;
124
+ /**
125
+ * Get current stats (for debugging/monitoring).
126
+ */
127
+ getStats(): {
128
+ sessions: number;
129
+ users: number;
130
+ };
131
+ /**
132
+ * Remove expired sessions.
133
+ */
134
+ private cleanup;
135
+ }
136
+ /**
137
+ * Create a session manager for Arc.
138
+ *
139
+ * Returns a Fastify plugin and a `requireFresh` preHandler.
140
+ *
141
+ * The plugin:
142
+ * - Parses session cookie on each request
143
+ * - Validates session against the store
144
+ * - Sets `request.user` and `request.session` from session data
145
+ * - Refreshes session token if older than `updateAge`
146
+ * - Provides `fastify.authenticate` decorator
147
+ * - Provides `fastify.sessionManager` decorator for session CRUD
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * import { createSessionManager, MemorySessionStore } from '@classytic/arc/auth';
152
+ *
153
+ * const sessions = createSessionManager({
154
+ * store: new MemorySessionStore(),
155
+ * secret: process.env.SESSION_SECRET!,
156
+ * maxAge: 7 * 24 * 60 * 60,
157
+ * updateAge: 24 * 60 * 60,
158
+ * freshAge: 10 * 60,
159
+ * });
160
+ *
161
+ * await fastify.register(sessions.plugin);
162
+ *
163
+ * // Login route
164
+ * fastify.post('/login', async (request, reply) => {
165
+ * const user = await authenticateUser(request.body);
166
+ * const { cookie } = await fastify.sessionManager.createSession(user.id);
167
+ * reply.header('Set-Cookie', cookie);
168
+ * return { success: true, user };
169
+ * });
170
+ *
171
+ * // Protected route
172
+ * fastify.get('/me', {
173
+ * preHandler: [fastify.authenticate],
174
+ * }, async (request) => {
175
+ * return { user: request.user };
176
+ * });
177
+ *
178
+ * // Sensitive route (requires fresh session)
179
+ * fastify.post('/change-password', {
180
+ * preHandler: [fastify.authenticate, sessions.requireFresh],
181
+ * }, handler);
182
+ * ```
183
+ */
184
+ declare function createSessionManager(options: SessionManagerOptions): SessionManagerResult;
185
+ //#endregion
186
+ export { SessionManagerOptions as a, createSessionManager as c, SessionData as i, MemorySessionStoreOptions as n, SessionManagerResult as o, SessionCookieOptions as r, SessionStore as s, MemorySessionStore as t };
187
+ //# sourceMappingURL=sessionManager-jPKLbHE0.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionManager-jPKLbHE0.d.mts","names":[],"sources":["../src/auth/sessionManager.ts"],"mappings":";;;;;;UA+CiB,WAAA;EAyBL;EAvBV,MAAA;EAyBA;EAvBA,SAAA;EAuBgC;EArBhC,SAAA;EAqBkE;EAnBlE,SAAA;EAyBe;EAvBf,QAAA,GAAW,MAAA;AAAA;;;;;UAOI,YAAA;EA0Bf;EAxBA,GAAA,CAAI,SAAA,WAAoB,OAAA,CAAQ,WAAA;EAwB1B;EAtBN,GAAA,CAAI,SAAA,UAAmB,IAAA,EAAM,WAAA,GAAc,OAAA;EA4BP;EA1BpC,MAAA,CAAO,SAAA,WAAoB,OAAA;EAwCE;EAtC7B,SAAA,CAAU,MAAA,WAAiB,OAAA;EA0BpB;EAxBP,eAAA,CAAgB,MAAA,UAAgB,gBAAA,WAA2B,OAAA;AAAA;;;;UAM5C,oBAAA;EA8BN;EA5BT,MAAA;EA4B6B;EA1B7B,QAAA;EAgCmC;EA9BnC,QAAA;EAgCQ;EA9BR,IAAA;EAgC+C;EA9B/C,MAAA;AAAA;;;;UAMe,qBAAA;EAwBS;EAtBxB,KAAA,EAAO,YAAA;EAsBwC;EApB/C,MAAA;EAoBgE;EAlBhE,MAAA;EAkBuE;EAhBvE,SAAA;EAiBD;EAfC,QAAA;EAwB0B;EAtB1B,UAAA;EAsBkE;EApBlE,MAAA,GAAS,oBAAA;AAAA;;;;UAMM,oBAAA;EA6B4B;EA3B3C,MAAA,EAAQ,kBAAA;EAiCe;EA/BvB,YAAA,GAAe,OAAA,EAAS,cAAA,EAAgB,KAAA,EAAO,YAAA,KAAiB,OAAA;AAAA;AAAA;EAAA,UAQtD,eAAA;IAEO;IAAf,YAAA,GAAe,OAAA,EAAS,cAAA,EAAgB,KAAA,EAAO,YAAA,KAAiB,OAAA;IAAxB;IAExC,cAAA;MAAA,sCAEE,aAAA,GACE,MAAA,UACA,QAAA,GAAW,MAAA,sBACR,OAAA;QAAU,SAAA;QAAmB,MAAA;MAAA,IAA7B;MAEL,aAAA,GAAgB,SAAA,aAAsB,OAAA,QAFJ;MAIlC,iBAAA,GAAoB,MAAA,aAAmB,OAAA,QAFvB;MAIhB,mBAAA,GAAsB,MAAA,UAAgB,gBAAA,aAA6B,OAAA,QAFnE;MAIA,cAAA,GAAiB,SAAA,aAAsB,OAAA,CAAQ,WAAA;IAAA;EAAA;EAAA,UAIzC,cAAA;IANgC;IAQxC,OAAA,GAAU,WAAA;MAAgB,EAAA;IAAA;EAAA;AAAA;AAAA,UAuHb,yBAAA;EAvHb;EAyHF,iBAAA;AAAA;;;;AAFF;cASa,kBAAA,YAA8B,YAAA;EAAA,QACjC,QAAA;EARR;EAAA,QAUQ,SAAA;EAAA,QACA,eAAA;cAEI,OAAA,GAAS,yBAAA;EAYf,GAAA,CAAI,SAAA,WAAoB,OAAA,CAAQ,WAAA;EAahC,GAAA,CAAI,SAAA,UAAmB,IAAA,EAAM,WAAA,GAAc,OAAA;EAY3C,MAAA,CAAO,SAAA,WAAoB,OAAA;EAe3B,SAAA,CAAU,MAAA,WAAiB,OAAA;EAU3B,eAAA,CAAgB,MAAA,UAAgB,gBAAA,WAA2B,OAAA;EArChB;;;EA0DjD,KAAA,CAAA;EAzFyC;;;EAqGzC,QAAA,CAAA;IAAc,QAAA;IAAkB,KAAA;EAAA;;;;UAUxB,OAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;AAuEV;;;;;;;;;;;;;;;;;;;;;;;;iBAAgB,oBAAA,CAAqB,OAAA,EAAS,qBAAA,GAAwB,oBAAA"}
@@ -0,0 +1,124 @@
1
+ import { t as __exportAll } from "./chunk-C7Uep-_p.mjs";
2
+ import { n as PUBLIC_SCOPE, r as getOrgId } from "./types-Beqn1Un7.mjs";
3
+ import { t as arcLog } from "./logger-Df2O2WsW.mjs";
4
+ import fp from "fastify-plugin";
5
+
6
+ //#region src/plugins/sse.ts
7
+ /**
8
+ * SSE Plugin (Server-Sent Events)
9
+ *
10
+ * Streams domain events to clients over HTTP using Server-Sent Events.
11
+ * Requires the events plugin (`arc-events`) to be registered first.
12
+ *
13
+ * @example
14
+ * import { ssePlugin } from '@classytic/arc/plugins';
15
+ *
16
+ * // Basic — stream all events at /events/stream
17
+ * await fastify.register(ssePlugin);
18
+ *
19
+ * // Filtered + org-scoped
20
+ * await fastify.register(ssePlugin, {
21
+ * path: '/api/events',
22
+ * patterns: ['order.*', 'product.*'],
23
+ * orgScoped: true,
24
+ * });
25
+ */
26
+ var sse_exports = /* @__PURE__ */ __exportAll({
27
+ default: () => sse_default,
28
+ ssePlugin: () => ssePlugin
29
+ });
30
+ const log = arcLog("sse");
31
+ const ssePlugin = async (fastify, opts = {}) => {
32
+ const { path = "/events/stream", requireAuth = true, patterns = ["*"], heartbeat = 3e4, orgScoped = false, filter: customFilter } = opts;
33
+ if (!fastify.hasDecorator("events")) {
34
+ log.warn("Events plugin (arc-events) not registered. SSE plugin will not function. Register eventPlugin before ssePlugin.");
35
+ return;
36
+ }
37
+ const activeConnections = /* @__PURE__ */ new Set();
38
+ const routeOpts = {
39
+ method: "GET",
40
+ url: path,
41
+ schema: {
42
+ tags: ["Events"],
43
+ summary: "SSE event stream",
44
+ description: "Server-Sent Events stream for real-time domain events",
45
+ response: { 200: {
46
+ type: "string",
47
+ description: "text/event-stream"
48
+ } }
49
+ },
50
+ handler: async (request, reply) => {
51
+ reply.hijack();
52
+ reply.raw.writeHead(200, {
53
+ "content-type": "text/event-stream",
54
+ "cache-control": "no-cache",
55
+ connection: "keep-alive",
56
+ "x-accel-buffering": "no"
57
+ });
58
+ reply.raw.flushHeaders();
59
+ const unsubscribers = [];
60
+ const requestOrgId = getOrgId(request.scope ?? PUBLIC_SCOPE);
61
+ const dropOrgEvents = orgScoped && !requestOrgId;
62
+ for (const pattern of patterns) {
63
+ const unsub = await fastify.events.subscribe(pattern, async (event) => {
64
+ if (orgScoped) {
65
+ const eventOrgId = event.meta?.organizationId;
66
+ if (dropOrgEvents && eventOrgId) return;
67
+ if (requestOrgId && eventOrgId && eventOrgId !== requestOrgId) return;
68
+ }
69
+ if (customFilter && !customFilter(event, request)) return;
70
+ const data = JSON.stringify({
71
+ type: event.type,
72
+ payload: event.payload,
73
+ meta: {
74
+ id: event.meta.id,
75
+ timestamp: event.meta.timestamp
76
+ }
77
+ });
78
+ if (!reply.raw.write(`event: ${event.type}\ndata: ${data}\n\n`)) {
79
+ request.raw.destroy(/* @__PURE__ */ new Error("SSE connection terminated: slow client backpressure"));
80
+ cleanup();
81
+ }
82
+ });
83
+ unsubscribers.push(unsub);
84
+ }
85
+ const heartbeatTimer = setInterval(() => {
86
+ if (!reply.raw.write(": heartbeat\n\n")) {
87
+ request.raw.destroy(/* @__PURE__ */ new Error("SSE connection terminated: heartbeat backpressure"));
88
+ cleanup();
89
+ }
90
+ }, heartbeat);
91
+ const cleanup = () => {
92
+ clearInterval(heartbeatTimer);
93
+ for (const unsub of unsubscribers) unsub();
94
+ if (!reply.raw.writableEnded) reply.raw.end();
95
+ activeConnections.delete(cleanup);
96
+ };
97
+ activeConnections.add(cleanup);
98
+ request.raw.on("close", cleanup);
99
+ }
100
+ };
101
+ if (requireAuth) {
102
+ if (!fastify.hasDecorator("authenticate")) throw new Error("[arc-sse] requireAuth is true but fastify.authenticate is not registered. Register an auth plugin before SSE, or set requireAuth: false.");
103
+ routeOpts.preHandler = fastify.authenticate;
104
+ }
105
+ fastify.route(routeOpts);
106
+ fastify.addHook("onClose", async () => {
107
+ for (const cleanup of activeConnections) cleanup();
108
+ activeConnections.clear();
109
+ });
110
+ log.debug("Plugin registered", {
111
+ path,
112
+ patterns,
113
+ orgScoped
114
+ });
115
+ };
116
+ var sse_default = fp(ssePlugin, {
117
+ name: "arc-sse",
118
+ fastify: "5.x",
119
+ dependencies: ["arc-events"]
120
+ });
121
+
122
+ //#endregion
123
+ export { sse_default as n, sse_exports as r, ssePlugin as t };
124
+ //# sourceMappingURL=sse-B3c3_yZp.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse-B3c3_yZp.mjs","names":[],"sources":["../src/plugins/sse.ts"],"sourcesContent":["/**\n * SSE Plugin (Server-Sent Events)\n *\n * Streams domain events to clients over HTTP using Server-Sent Events.\n * Requires the events plugin (`arc-events`) to be registered first.\n *\n * @example\n * import { ssePlugin } from '@classytic/arc/plugins';\n *\n * // Basic — stream all events at /events/stream\n * await fastify.register(ssePlugin);\n *\n * // Filtered + org-scoped\n * await fastify.register(ssePlugin, {\n * path: '/api/events',\n * patterns: ['order.*', 'product.*'],\n * orgScoped: true,\n * });\n */\n\nimport fp from \"fastify-plugin\";\nimport type {\n FastifyInstance,\n FastifyPluginAsync,\n FastifyRequest,\n FastifyReply,\n} from \"fastify\";\nimport type { DomainEvent } from \"../events/EventTransport.js\";\nimport { getOrgId, PUBLIC_SCOPE } from \"../scope/types.js\";\nimport type { RequestScope } from \"../scope/types.js\";\nimport { arcLog } from \"../logger/index.js\";\n\nconst log = arcLog(\"sse\");\n\nexport interface SSEOptions {\n /** SSE endpoint path (default: '/events/stream') */\n path?: string;\n /** Require authentication (default: true) */\n requireAuth?: boolean;\n /** Event patterns to stream (default: ['*'] = all) */\n patterns?: string[];\n /** Heartbeat interval in ms (default: 30000) */\n heartbeat?: number;\n /** Filter events by organizationId from request.scope (default: false) */\n orgScoped?: boolean;\n /** Custom event filter function */\n filter?: (event: DomainEvent<unknown>, request: FastifyRequest) => boolean;\n}\n\n// ============================================================================\n// Plugin\n// ============================================================================\n\nconst ssePlugin: FastifyPluginAsync<SSEOptions> = async (\n fastify: FastifyInstance,\n opts: SSEOptions = {},\n) => {\n const {\n path = \"/events/stream\",\n requireAuth = true,\n patterns = [\"*\"],\n heartbeat = 30000,\n orgScoped = false,\n filter: customFilter,\n } = opts;\n\n // Check that events plugin is registered\n if (!fastify.hasDecorator(\"events\")) {\n log.warn(\n \"Events plugin (arc-events) not registered. SSE plugin will not function. \" +\n \"Register eventPlugin before ssePlugin.\",\n );\n return;\n }\n\n // Track active connections for cleanup\n const activeConnections = new Set<() => void>();\n\n // Build route options\n const routeOpts: {\n method: \"GET\";\n url: string;\n schema: Record<string, unknown>;\n preHandler?: (\n request: FastifyRequest,\n reply: FastifyReply,\n ) => Promise<void>;\n handler: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;\n } = {\n method: \"GET\",\n url: path,\n schema: {\n tags: [\"Events\"],\n summary: \"SSE event stream\",\n description: \"Server-Sent Events stream for real-time domain events\",\n response: {\n 200: {\n type: \"string\",\n description: \"text/event-stream\",\n },\n },\n },\n handler: async (\n request: FastifyRequest,\n reply: FastifyReply,\n ): Promise<void> => {\n // 1. Tell Fastify we are taking over the socket\n reply.hijack();\n\n // Set SSE headers and flush immediately so clients detect the connection\n reply.raw.writeHead(200, {\n \"content-type\": \"text/event-stream\",\n \"cache-control\": \"no-cache\",\n connection: \"keep-alive\",\n \"x-accel-buffering\": \"no\", // Disable nginx buffering\n });\n reply.raw.flushHeaders();\n\n // Track unsubscribers for cleanup\n const unsubscribers: (() => void)[] = [];\n\n // Get org context from request.scope for filtering\n const scope: RequestScope = request.scope ?? PUBLIC_SCOPE;\n const requestOrgId = getOrgId(scope);\n\n // Subscribe to each pattern\n // If orgScoped is enabled but caller has no org context, drop all org events\n // to prevent leaking data across organizations\n const dropOrgEvents = orgScoped && !requestOrgId;\n\n for (const pattern of patterns) {\n const unsub = await fastify.events.subscribe(\n pattern,\n async (event: DomainEvent<unknown>) => {\n // Org-scoped filtering: only forward events for the user's org\n if (orgScoped) {\n const eventOrgId = (event.meta as Record<string, unknown>)\n ?.organizationId;\n // If caller has no org, drop any event that carries an orgId\n if (dropOrgEvents && eventOrgId) return;\n // If caller has an org, only forward events matching their org\n if (requestOrgId && eventOrgId && eventOrgId !== requestOrgId)\n return;\n }\n\n // Custom filter\n if (customFilter && !customFilter(event, request)) return;\n\n // Write SSE event\n const data = JSON.stringify({\n type: event.type,\n payload: event.payload,\n meta: { id: event.meta.id, timestamp: event.meta.timestamp },\n });\n const success = reply.raw.write(\n `event: ${event.type}\\ndata: ${data}\\n\\n`,\n );\n if (!success) {\n // TCP Backpressure / Slow Client Check:\n // Terminate connection if buffer is full to prevent unbounded memory leaks via L7 proxies\n request.raw.destroy(\n new Error(\n \"SSE connection terminated: slow client backpressure\",\n ),\n );\n cleanup();\n }\n },\n );\n unsubscribers.push(unsub);\n }\n\n // Heartbeat to keep connection alive\n const heartbeatTimer = setInterval(() => {\n const success = reply.raw.write(\": heartbeat\\n\\n\");\n if (!success) {\n request.raw.destroy(\n new Error(\"SSE connection terminated: heartbeat backpressure\"),\n );\n cleanup();\n }\n }, heartbeat);\n\n // Cleanup function\n const cleanup = () => {\n clearInterval(heartbeatTimer);\n for (const unsub of unsubscribers) {\n unsub();\n }\n // End the response to release the connection\n if (!reply.raw.writableEnded) {\n reply.raw.end();\n }\n activeConnections.delete(cleanup);\n };\n\n activeConnections.add(cleanup);\n\n // Cleanup on client disconnect\n request.raw.on(\"close\", cleanup);\n },\n };\n\n // Add auth preHandler if required — fail-closed: throw if decorator missing\n if (requireAuth) {\n if (!fastify.hasDecorator(\"authenticate\")) {\n throw new Error(\n \"[arc-sse] requireAuth is true but fastify.authenticate is not registered. \" +\n \"Register an auth plugin before SSE, or set requireAuth: false.\",\n );\n }\n routeOpts.preHandler = fastify.authenticate;\n }\n\n fastify.route(routeOpts);\n\n // Cleanup all connections on server close\n fastify.addHook(\"onClose\", async () => {\n for (const cleanup of activeConnections) {\n cleanup();\n }\n activeConnections.clear();\n });\n\n log.debug(\"Plugin registered\", { path, patterns, orgScoped });\n};\n\nexport default fp(ssePlugin, {\n name: \"arc-sse\",\n fastify: \"5.x\",\n dependencies: [\"arc-events\"],\n});\n\nexport { ssePlugin };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAM,MAAM,OAAO,MAAM;AAqBzB,MAAM,YAA4C,OAChD,SACA,OAAmB,EAAE,KAClB;CACH,MAAM,EACJ,OAAO,kBACP,cAAc,MACd,WAAW,CAAC,IAAI,EAChB,YAAY,KACZ,YAAY,OACZ,QAAQ,iBACN;AAGJ,KAAI,CAAC,QAAQ,aAAa,SAAS,EAAE;AACnC,MAAI,KACF,kHAED;AACD;;CAIF,MAAM,oCAAoB,IAAI,KAAiB;CAG/C,MAAM,YASF;EACF,QAAQ;EACR,KAAK;EACL,QAAQ;GACN,MAAM,CAAC,SAAS;GAChB,SAAS;GACT,aAAa;GACb,UAAU,EACR,KAAK;IACH,MAAM;IACN,aAAa;IACd,EACF;GACF;EACD,SAAS,OACP,SACA,UACkB;AAElB,SAAM,QAAQ;AAGd,SAAM,IAAI,UAAU,KAAK;IACvB,gBAAgB;IAChB,iBAAiB;IACjB,YAAY;IACZ,qBAAqB;IACtB,CAAC;AACF,SAAM,IAAI,cAAc;GAGxB,MAAM,gBAAgC,EAAE;GAIxC,MAAM,eAAe,SADO,QAAQ,SAAS,aACT;GAKpC,MAAM,gBAAgB,aAAa,CAAC;AAEpC,QAAK,MAAM,WAAW,UAAU;IAC9B,MAAM,QAAQ,MAAM,QAAQ,OAAO,UACjC,SACA,OAAO,UAAgC;AAErC,SAAI,WAAW;MACb,MAAM,aAAc,MAAM,MACtB;AAEJ,UAAI,iBAAiB,WAAY;AAEjC,UAAI,gBAAgB,cAAc,eAAe,aAC/C;;AAIJ,SAAI,gBAAgB,CAAC,aAAa,OAAO,QAAQ,CAAE;KAGnD,MAAM,OAAO,KAAK,UAAU;MAC1B,MAAM,MAAM;MACZ,SAAS,MAAM;MACf,MAAM;OAAE,IAAI,MAAM,KAAK;OAAI,WAAW,MAAM,KAAK;OAAW;MAC7D,CAAC;AAIF,SAAI,CAHY,MAAM,IAAI,MACxB,UAAU,MAAM,KAAK,UAAU,KAAK,MACrC,EACa;AAGZ,cAAQ,IAAI,wBACV,IAAI,MACF,sDACD,CACF;AACD,eAAS;;MAGd;AACD,kBAAc,KAAK,MAAM;;GAI3B,MAAM,iBAAiB,kBAAkB;AAEvC,QAAI,CADY,MAAM,IAAI,MAAM,kBAAkB,EACpC;AACZ,aAAQ,IAAI,wBACV,IAAI,MAAM,oDAAoD,CAC/D;AACD,cAAS;;MAEV,UAAU;GAGb,MAAM,gBAAgB;AACpB,kBAAc,eAAe;AAC7B,SAAK,MAAM,SAAS,cAClB,QAAO;AAGT,QAAI,CAAC,MAAM,IAAI,cACb,OAAM,IAAI,KAAK;AAEjB,sBAAkB,OAAO,QAAQ;;AAGnC,qBAAkB,IAAI,QAAQ;AAG9B,WAAQ,IAAI,GAAG,SAAS,QAAQ;;EAEnC;AAGD,KAAI,aAAa;AACf,MAAI,CAAC,QAAQ,aAAa,eAAe,CACvC,OAAM,IAAI,MACR,2IAED;AAEH,YAAU,aAAa,QAAQ;;AAGjC,SAAQ,MAAM,UAAU;AAGxB,SAAQ,QAAQ,WAAW,YAAY;AACrC,OAAK,MAAM,WAAW,kBACpB,UAAS;AAEX,oBAAkB,OAAO;GACzB;AAEF,KAAI,MAAM,qBAAqB;EAAE;EAAM;EAAU;EAAW,CAAC;;AAG/D,kBAAe,GAAG,WAAW;CAC3B,MAAM;CACN,SAAS;CACT,cAAc,CAAC,aAAa;CAC7B,CAAC"}