@c9up/ream 0.1.3

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 (451) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +70 -0
  3. package/dist/Application.d.ts +71 -0
  4. package/dist/Application.d.ts.map +1 -0
  5. package/dist/Application.js +151 -0
  6. package/dist/Application.js.map +1 -0
  7. package/dist/Codemods.d.ts +16 -0
  8. package/dist/Codemods.d.ts.map +1 -0
  9. package/dist/Codemods.js +277 -0
  10. package/dist/Codemods.js.map +1 -0
  11. package/dist/ConfigLoader.d.ts +29 -0
  12. package/dist/ConfigLoader.d.ts.map +1 -0
  13. package/dist/ConfigLoader.js +43 -0
  14. package/dist/ConfigLoader.js.map +1 -0
  15. package/dist/ErrorBoundary.d.ts +51 -0
  16. package/dist/ErrorBoundary.d.ts.map +1 -0
  17. package/dist/ErrorBoundary.js +122 -0
  18. package/dist/ErrorBoundary.js.map +1 -0
  19. package/dist/GracefulShutdown.d.ts +28 -0
  20. package/dist/GracefulShutdown.d.ts.map +1 -0
  21. package/dist/GracefulShutdown.js +55 -0
  22. package/dist/GracefulShutdown.js.map +1 -0
  23. package/dist/HealthCheck.d.ts +42 -0
  24. package/dist/HealthCheck.d.ts.map +1 -0
  25. package/dist/HealthCheck.js +65 -0
  26. package/dist/HealthCheck.js.map +1 -0
  27. package/dist/HotReload.d.ts +28 -0
  28. package/dist/HotReload.d.ts.map +1 -0
  29. package/dist/HotReload.js +60 -0
  30. package/dist/HotReload.js.map +1 -0
  31. package/dist/HttpKernel.d.ts +62 -0
  32. package/dist/HttpKernel.d.ts.map +1 -0
  33. package/dist/HttpKernel.js +210 -0
  34. package/dist/HttpKernel.js.map +1 -0
  35. package/dist/Ignitor.d.ts +195 -0
  36. package/dist/Ignitor.d.ts.map +1 -0
  37. package/dist/Ignitor.js +505 -0
  38. package/dist/Ignitor.js.map +1 -0
  39. package/dist/Provider.d.ts +54 -0
  40. package/dist/Provider.d.ts.map +1 -0
  41. package/dist/Provider.js +37 -0
  42. package/dist/Provider.js.map +1 -0
  43. package/dist/bodyparser/BodyParserMiddleware.d.ts +38 -0
  44. package/dist/bodyparser/BodyParserMiddleware.d.ts.map +1 -0
  45. package/dist/bodyparser/BodyParserMiddleware.js +143 -0
  46. package/dist/bodyparser/BodyParserMiddleware.js.map +1 -0
  47. package/dist/bodyparser/MultipartFile.d.ts +77 -0
  48. package/dist/bodyparser/MultipartFile.d.ts.map +1 -0
  49. package/dist/bodyparser/MultipartFile.js +138 -0
  50. package/dist/bodyparser/MultipartFile.js.map +1 -0
  51. package/dist/bodyparser/parseSize.d.ts +6 -0
  52. package/dist/bodyparser/parseSize.d.ts.map +1 -0
  53. package/dist/bodyparser/parseSize.js +21 -0
  54. package/dist/bodyparser/parseSize.js.map +1 -0
  55. package/dist/bootstrap/hyper-server.d.ts +27 -0
  56. package/dist/bootstrap/hyper-server.d.ts.map +1 -0
  57. package/dist/bootstrap/hyper-server.js +63 -0
  58. package/dist/bootstrap/hyper-server.js.map +1 -0
  59. package/dist/console/CommandRunner.d.ts +18 -0
  60. package/dist/console/CommandRunner.d.ts.map +1 -0
  61. package/dist/console/CommandRunner.js +65 -0
  62. package/dist/console/CommandRunner.js.map +1 -0
  63. package/dist/container/Container.d.ts +60 -0
  64. package/dist/container/Container.d.ts.map +1 -0
  65. package/dist/container/Container.js +329 -0
  66. package/dist/container/Container.js.map +1 -0
  67. package/dist/container/types.d.ts +25 -0
  68. package/dist/container/types.d.ts.map +1 -0
  69. package/dist/container/types.js +6 -0
  70. package/dist/container/types.js.map +1 -0
  71. package/dist/decorators/Lazy.d.ts +19 -0
  72. package/dist/decorators/Lazy.d.ts.map +1 -0
  73. package/dist/decorators/Lazy.js +53 -0
  74. package/dist/decorators/Lazy.js.map +1 -0
  75. package/dist/decorators/Service.d.ts +48 -0
  76. package/dist/decorators/Service.d.ts.map +1 -0
  77. package/dist/decorators/Service.js +70 -0
  78. package/dist/decorators/Service.js.map +1 -0
  79. package/dist/errors/FuzzyMatcher.d.ts +41 -0
  80. package/dist/errors/FuzzyMatcher.d.ts.map +1 -0
  81. package/dist/errors/FuzzyMatcher.js +81 -0
  82. package/dist/errors/FuzzyMatcher.js.map +1 -0
  83. package/dist/errors/ModuleErrors.d.ts +41 -0
  84. package/dist/errors/ModuleErrors.d.ts.map +1 -0
  85. package/dist/errors/ModuleErrors.js +65 -0
  86. package/dist/errors/ModuleErrors.js.map +1 -0
  87. package/dist/errors/PipelineStageError.d.ts +31 -0
  88. package/dist/errors/PipelineStageError.d.ts.map +1 -0
  89. package/dist/errors/PipelineStageError.js +77 -0
  90. package/dist/errors/PipelineStageError.js.map +1 -0
  91. package/dist/errors/ReamError.d.ts +50 -0
  92. package/dist/errors/ReamError.d.ts.map +1 -0
  93. package/dist/errors/ReamError.js +108 -0
  94. package/dist/errors/ReamError.js.map +1 -0
  95. package/dist/events/Emitter.d.ts +124 -0
  96. package/dist/events/Emitter.d.ts.map +1 -0
  97. package/dist/events/Emitter.js +271 -0
  98. package/dist/events/Emitter.js.map +1 -0
  99. package/dist/events/EventsProvider.d.ts +28 -0
  100. package/dist/events/EventsProvider.d.ts.map +1 -0
  101. package/dist/events/EventsProvider.js +36 -0
  102. package/dist/events/EventsProvider.js.map +1 -0
  103. package/dist/events/config.d.ts +8 -0
  104. package/dist/events/config.d.ts.map +1 -0
  105. package/dist/events/config.js +4 -0
  106. package/dist/events/config.js.map +1 -0
  107. package/dist/events/configure.d.ts +10 -0
  108. package/dist/events/configure.d.ts.map +1 -0
  109. package/dist/events/configure.js +11 -0
  110. package/dist/events/configure.js.map +1 -0
  111. package/dist/events/helix/helpers.d.ts +62 -0
  112. package/dist/events/helix/helpers.d.ts.map +1 -0
  113. package/dist/events/helix/helpers.js +187 -0
  114. package/dist/events/helix/helpers.js.map +1 -0
  115. package/dist/events/index.d.ts +17 -0
  116. package/dist/events/index.d.ts.map +1 -0
  117. package/dist/events/index.js +15 -0
  118. package/dist/events/index.js.map +1 -0
  119. package/dist/events/native.d.ts +21 -0
  120. package/dist/events/native.d.ts.map +1 -0
  121. package/dist/events/native.js +17 -0
  122. package/dist/events/native.js.map +1 -0
  123. package/dist/events/services/main.d.ts +18 -0
  124. package/dist/events/services/main.d.ts.map +1 -0
  125. package/dist/events/services/main.js +31 -0
  126. package/dist/events/services/main.js.map +1 -0
  127. package/dist/events/testing/FakeBus.d.ts +66 -0
  128. package/dist/events/testing/FakeBus.d.ts.map +1 -0
  129. package/dist/events/testing/FakeBus.js +356 -0
  130. package/dist/events/testing/FakeBus.js.map +1 -0
  131. package/dist/graphql/GraphQLEngine.d.ts +69 -0
  132. package/dist/graphql/GraphQLEngine.d.ts.map +1 -0
  133. package/dist/graphql/GraphQLEngine.js +309 -0
  134. package/dist/graphql/GraphQLEngine.js.map +1 -0
  135. package/dist/graphql/GraphQLProvider.d.ts +32 -0
  136. package/dist/graphql/GraphQLProvider.d.ts.map +1 -0
  137. package/dist/graphql/GraphQLProvider.js +49 -0
  138. package/dist/graphql/GraphQLProvider.js.map +1 -0
  139. package/dist/helpers/base64.d.ts +40 -0
  140. package/dist/helpers/base64.d.ts.map +1 -0
  141. package/dist/helpers/base64.js +70 -0
  142. package/dist/helpers/base64.js.map +1 -0
  143. package/dist/helpers/index.d.ts +7 -0
  144. package/dist/helpers/index.d.ts.map +1 -0
  145. package/dist/helpers/index.js +5 -0
  146. package/dist/helpers/index.js.map +1 -0
  147. package/dist/helpers/is.d.ts +101 -0
  148. package/dist/helpers/is.d.ts.map +1 -0
  149. package/dist/helpers/is.js +151 -0
  150. package/dist/helpers/is.js.map +1 -0
  151. package/dist/helpers/napi-loader.d.ts +46 -0
  152. package/dist/helpers/napi-loader.d.ts.map +1 -0
  153. package/dist/helpers/napi-loader.js +69 -0
  154. package/dist/helpers/napi-loader.js.map +1 -0
  155. package/dist/helpers/safeEqual.d.ts +9 -0
  156. package/dist/helpers/safeEqual.d.ts.map +1 -0
  157. package/dist/helpers/safeEqual.js +16 -0
  158. package/dist/helpers/safeEqual.js.map +1 -0
  159. package/dist/helpers/string.d.ts +161 -0
  160. package/dist/helpers/string.d.ts.map +1 -0
  161. package/dist/helpers/string.js +429 -0
  162. package/dist/helpers/string.js.map +1 -0
  163. package/dist/helpers/types.d.ts +83 -0
  164. package/dist/helpers/types.d.ts.map +1 -0
  165. package/dist/helpers/types.js +6 -0
  166. package/dist/helpers/types.js.map +1 -0
  167. package/dist/http/Exception.d.ts +103 -0
  168. package/dist/http/Exception.d.ts.map +1 -0
  169. package/dist/http/Exception.js +228 -0
  170. package/dist/http/Exception.js.map +1 -0
  171. package/dist/http/HttpContext.d.ts +69 -0
  172. package/dist/http/HttpContext.d.ts.map +1 -0
  173. package/dist/http/HttpContext.js +55 -0
  174. package/dist/http/HttpContext.js.map +1 -0
  175. package/dist/http/RedirectBuilder.d.ts +31 -0
  176. package/dist/http/RedirectBuilder.d.ts.map +1 -0
  177. package/dist/http/RedirectBuilder.js +75 -0
  178. package/dist/http/RedirectBuilder.js.map +1 -0
  179. package/dist/http/Request.d.ts +160 -0
  180. package/dist/http/Request.d.ts.map +1 -0
  181. package/dist/http/Request.js +484 -0
  182. package/dist/http/Request.js.map +1 -0
  183. package/dist/http/Response.d.ts +114 -0
  184. package/dist/http/Response.d.ts.map +1 -0
  185. package/dist/http/Response.js +303 -0
  186. package/dist/http/Response.js.map +1 -0
  187. package/dist/http/SseStream.d.ts +89 -0
  188. package/dist/http/SseStream.d.ts.map +1 -0
  189. package/dist/http/SseStream.js +228 -0
  190. package/dist/http/SseStream.js.map +1 -0
  191. package/dist/http/urlDecode.d.ts +8 -0
  192. package/dist/http/urlDecode.d.ts.map +1 -0
  193. package/dist/http/urlDecode.js +18 -0
  194. package/dist/http/urlDecode.js.map +1 -0
  195. package/dist/index.d.ts +92 -0
  196. package/dist/index.d.ts.map +1 -0
  197. package/dist/index.js +67 -0
  198. package/dist/index.js.map +1 -0
  199. package/dist/middleware/Pipeline.d.ts +36 -0
  200. package/dist/middleware/Pipeline.d.ts.map +1 -0
  201. package/dist/middleware/Pipeline.js +104 -0
  202. package/dist/middleware/Pipeline.js.map +1 -0
  203. package/dist/openapi/OpenApiGenerator.d.ts +58 -0
  204. package/dist/openapi/OpenApiGenerator.d.ts.map +1 -0
  205. package/dist/openapi/OpenApiGenerator.js +192 -0
  206. package/dist/openapi/OpenApiGenerator.js.map +1 -0
  207. package/dist/openapi/OpenApiMiddleware.d.ts +24 -0
  208. package/dist/openapi/OpenApiMiddleware.d.ts.map +1 -0
  209. package/dist/openapi/OpenApiMiddleware.js +78 -0
  210. package/dist/openapi/OpenApiMiddleware.js.map +1 -0
  211. package/dist/openapi/OpenApiProvider.d.ts +36 -0
  212. package/dist/openapi/OpenApiProvider.d.ts.map +1 -0
  213. package/dist/openapi/OpenApiProvider.js +42 -0
  214. package/dist/openapi/OpenApiProvider.js.map +1 -0
  215. package/dist/resources/ApiResource.d.ts +45 -0
  216. package/dist/resources/ApiResource.d.ts.map +1 -0
  217. package/dist/resources/ApiResource.js +58 -0
  218. package/dist/resources/ApiResource.js.map +1 -0
  219. package/dist/router/Router.d.ts +205 -0
  220. package/dist/router/Router.d.ts.map +1 -0
  221. package/dist/router/Router.js +552 -0
  222. package/dist/router/Router.js.map +1 -0
  223. package/dist/rpc/RpcProvider.d.ts +34 -0
  224. package/dist/rpc/RpcProvider.d.ts.map +1 -0
  225. package/dist/rpc/RpcProvider.js +37 -0
  226. package/dist/rpc/RpcProvider.js.map +1 -0
  227. package/dist/rpc/RpcRouter.d.ts +61 -0
  228. package/dist/rpc/RpcRouter.d.ts.map +1 -0
  229. package/dist/rpc/RpcRouter.js +187 -0
  230. package/dist/rpc/RpcRouter.js.map +1 -0
  231. package/dist/scheduler/Schedule.d.ts +53 -0
  232. package/dist/scheduler/Schedule.d.ts.map +1 -0
  233. package/dist/scheduler/Schedule.js +76 -0
  234. package/dist/scheduler/Schedule.js.map +1 -0
  235. package/dist/scheduler/ScheduleProvider.d.ts +56 -0
  236. package/dist/scheduler/ScheduleProvider.d.ts.map +1 -0
  237. package/dist/scheduler/ScheduleProvider.js +145 -0
  238. package/dist/scheduler/ScheduleProvider.js.map +1 -0
  239. package/dist/scheduler/Scheduler.d.ts +209 -0
  240. package/dist/scheduler/Scheduler.d.ts.map +1 -0
  241. package/dist/scheduler/Scheduler.js +432 -0
  242. package/dist/scheduler/Scheduler.js.map +1 -0
  243. package/dist/scheduler/index.d.ts +14 -0
  244. package/dist/scheduler/index.d.ts.map +1 -0
  245. package/dist/scheduler/index.js +6 -0
  246. package/dist/scheduler/index.js.map +1 -0
  247. package/dist/scheduler/locks/LockBackend.d.ts +37 -0
  248. package/dist/scheduler/locks/LockBackend.d.ts.map +1 -0
  249. package/dist/scheduler/locks/LockBackend.js +13 -0
  250. package/dist/scheduler/locks/LockBackend.js.map +1 -0
  251. package/dist/scheduler/locks/MemoryLockBackend.d.ts +39 -0
  252. package/dist/scheduler/locks/MemoryLockBackend.d.ts.map +1 -0
  253. package/dist/scheduler/locks/MemoryLockBackend.js +71 -0
  254. package/dist/scheduler/locks/MemoryLockBackend.js.map +1 -0
  255. package/dist/scheduler/observability/ErrorReporter.d.ts +15 -0
  256. package/dist/scheduler/observability/ErrorReporter.d.ts.map +1 -0
  257. package/dist/scheduler/observability/ErrorReporter.js +13 -0
  258. package/dist/scheduler/observability/ErrorReporter.js.map +1 -0
  259. package/dist/scheduler/observability/ScheduleEvent.d.ts +57 -0
  260. package/dist/scheduler/observability/ScheduleEvent.d.ts.map +1 -0
  261. package/dist/scheduler/observability/ScheduleEvent.js +12 -0
  262. package/dist/scheduler/observability/ScheduleEvent.js.map +1 -0
  263. package/dist/scheduler/observability/ScheduleEventSink.d.ts +20 -0
  264. package/dist/scheduler/observability/ScheduleEventSink.d.ts.map +1 -0
  265. package/dist/scheduler/observability/ScheduleEventSink.js +17 -0
  266. package/dist/scheduler/observability/ScheduleEventSink.js.map +1 -0
  267. package/dist/scheduler/observability/StatsTracker.d.ts +50 -0
  268. package/dist/scheduler/observability/StatsTracker.d.ts.map +1 -0
  269. package/dist/scheduler/observability/StatsTracker.js +96 -0
  270. package/dist/scheduler/observability/StatsTracker.js.map +1 -0
  271. package/dist/security/CookieSigner.d.ts +13 -0
  272. package/dist/security/CookieSigner.d.ts.map +1 -0
  273. package/dist/security/CookieSigner.js +51 -0
  274. package/dist/security/CookieSigner.js.map +1 -0
  275. package/dist/security/SignedUrl.d.ts +17 -0
  276. package/dist/security/SignedUrl.d.ts.map +1 -0
  277. package/dist/security/SignedUrl.js +63 -0
  278. package/dist/security/SignedUrl.js.map +1 -0
  279. package/dist/security/crypto.d.ts +25 -0
  280. package/dist/security/crypto.d.ts.map +1 -0
  281. package/dist/security/crypto.js +82 -0
  282. package/dist/security/crypto.js.map +1 -0
  283. package/dist/server/HyperServer.d.ts +64 -0
  284. package/dist/server/HyperServer.d.ts.map +1 -0
  285. package/dist/server/HyperServer.js +54 -0
  286. package/dist/server/HyperServer.js.map +1 -0
  287. package/dist/server/Server.d.ts +68 -0
  288. package/dist/server/Server.d.ts.map +1 -0
  289. package/dist/server/Server.js +113 -0
  290. package/dist/server/Server.js.map +1 -0
  291. package/dist/services/app.d.ts +14 -0
  292. package/dist/services/app.d.ts.map +1 -0
  293. package/dist/services/app.js +27 -0
  294. package/dist/services/app.js.map +1 -0
  295. package/dist/services/router.d.ts +21 -0
  296. package/dist/services/router.d.ts.map +1 -0
  297. package/dist/services/router.js +36 -0
  298. package/dist/services/router.js.map +1 -0
  299. package/dist/services/server.d.ts +16 -0
  300. package/dist/services/server.d.ts.map +1 -0
  301. package/dist/services/server.js +32 -0
  302. package/dist/services/server.js.map +1 -0
  303. package/dist/session/Session.d.ts +88 -0
  304. package/dist/session/Session.d.ts.map +1 -0
  305. package/dist/session/Session.js +186 -0
  306. package/dist/session/Session.js.map +1 -0
  307. package/dist/session/SessionMiddleware.d.ts +16 -0
  308. package/dist/session/SessionMiddleware.d.ts.map +1 -0
  309. package/dist/session/SessionMiddleware.js +132 -0
  310. package/dist/session/SessionMiddleware.js.map +1 -0
  311. package/dist/session/drivers/CookieDriver.d.ts +17 -0
  312. package/dist/session/drivers/CookieDriver.d.ts.map +1 -0
  313. package/dist/session/drivers/CookieDriver.js +42 -0
  314. package/dist/session/drivers/CookieDriver.js.map +1 -0
  315. package/dist/session/drivers/MemoryDriver.d.ts +9 -0
  316. package/dist/session/drivers/MemoryDriver.d.ts.map +1 -0
  317. package/dist/session/drivers/MemoryDriver.js +24 -0
  318. package/dist/session/drivers/MemoryDriver.js.map +1 -0
  319. package/dist/storage/S3Driver.d.ts +27 -0
  320. package/dist/storage/S3Driver.d.ts.map +1 -0
  321. package/dist/storage/S3Driver.js +135 -0
  322. package/dist/storage/S3Driver.js.map +1 -0
  323. package/dist/storage/StaticMiddleware.d.ts +27 -0
  324. package/dist/storage/StaticMiddleware.d.ts.map +1 -0
  325. package/dist/storage/StaticMiddleware.js +153 -0
  326. package/dist/storage/StaticMiddleware.js.map +1 -0
  327. package/dist/storage/StaticProvider.d.ts +26 -0
  328. package/dist/storage/StaticProvider.d.ts.map +1 -0
  329. package/dist/storage/StaticProvider.js +31 -0
  330. package/dist/storage/StaticProvider.js.map +1 -0
  331. package/dist/storage/StorageManager.d.ts +31 -0
  332. package/dist/storage/StorageManager.d.ts.map +1 -0
  333. package/dist/storage/StorageManager.js +120 -0
  334. package/dist/storage/StorageManager.js.map +1 -0
  335. package/dist/testing/RequestBuilder.d.ts +67 -0
  336. package/dist/testing/RequestBuilder.d.ts.map +1 -0
  337. package/dist/testing/RequestBuilder.js +202 -0
  338. package/dist/testing/RequestBuilder.js.map +1 -0
  339. package/dist/testing/TestClient.d.ts +96 -0
  340. package/dist/testing/TestClient.d.ts.map +1 -0
  341. package/dist/testing/TestClient.js +263 -0
  342. package/dist/testing/TestClient.js.map +1 -0
  343. package/dist/types/helpers.d.ts +47 -0
  344. package/dist/types/helpers.d.ts.map +1 -0
  345. package/dist/types/helpers.js +5 -0
  346. package/dist/types/helpers.js.map +1 -0
  347. package/events.darwin-arm64.node +0 -0
  348. package/events.darwin-x64.node +0 -0
  349. package/events.linux-arm64-gnu.node +0 -0
  350. package/events.linux-x64-gnu.node +0 -0
  351. package/events.win32-x64-msvc.node +0 -0
  352. package/index.darwin-arm64.node +0 -0
  353. package/index.darwin-x64.node +0 -0
  354. package/index.linux-arm64-gnu.node +0 -0
  355. package/index.linux-x64-gnu.node +0 -0
  356. package/index.win32-x64-msvc.node +0 -0
  357. package/package.json +106 -0
  358. package/scheduler.darwin-arm64.node +0 -0
  359. package/scheduler.darwin-x64.node +0 -0
  360. package/scheduler.linux-arm64-gnu.node +0 -0
  361. package/scheduler.linux-x64-gnu.node +0 -0
  362. package/scheduler.win32-x64-msvc.node +0 -0
  363. package/scripts/copy-napi.mjs +113 -0
  364. package/src/Application.ts +177 -0
  365. package/src/Codemods.ts +343 -0
  366. package/src/ConfigLoader.ts +49 -0
  367. package/src/ErrorBoundary.ts +157 -0
  368. package/src/GracefulShutdown.ts +80 -0
  369. package/src/HealthCheck.ts +96 -0
  370. package/src/HotReload.ts +78 -0
  371. package/src/HttpKernel.ts +305 -0
  372. package/src/Ignitor.ts +656 -0
  373. package/src/Provider.ts +74 -0
  374. package/src/bodyparser/BodyParserMiddleware.ts +183 -0
  375. package/src/bodyparser/MultipartFile.ts +181 -0
  376. package/src/bodyparser/parseSize.ts +19 -0
  377. package/src/bootstrap/hyper-server.ts +78 -0
  378. package/src/console/CommandRunner.ts +82 -0
  379. package/src/container/Container.ts +383 -0
  380. package/src/container/types.ts +30 -0
  381. package/src/decorators/Lazy.ts +57 -0
  382. package/src/decorators/Service.ts +85 -0
  383. package/src/errors/FuzzyMatcher.ts +93 -0
  384. package/src/errors/ModuleErrors.ts +73 -0
  385. package/src/errors/PipelineStageError.ts +97 -0
  386. package/src/errors/ReamError.ts +138 -0
  387. package/src/events/Emitter.ts +333 -0
  388. package/src/events/EventsProvider.ts +58 -0
  389. package/src/events/config.ts +10 -0
  390. package/src/events/configure.ts +19 -0
  391. package/src/events/helix/helpers.ts +260 -0
  392. package/src/events/index.ts +22 -0
  393. package/src/events/native.ts +37 -0
  394. package/src/events/services/main.ts +39 -0
  395. package/src/events/testing/FakeBus.ts +420 -0
  396. package/src/graphql/GraphQLEngine.ts +421 -0
  397. package/src/graphql/GraphQLProvider.ts +59 -0
  398. package/src/helpers/base64.ts +72 -0
  399. package/src/helpers/index.ts +6 -0
  400. package/src/helpers/is.ts +162 -0
  401. package/src/helpers/napi-loader.ts +106 -0
  402. package/src/helpers/safeEqual.ts +15 -0
  403. package/src/helpers/string.ts +469 -0
  404. package/src/helpers/types.ts +100 -0
  405. package/src/http/Exception.ts +272 -0
  406. package/src/http/HttpContext.ts +108 -0
  407. package/src/http/RedirectBuilder.ts +89 -0
  408. package/src/http/Request.ts +540 -0
  409. package/src/http/Response.ts +351 -0
  410. package/src/http/SseStream.ts +250 -0
  411. package/src/http/urlDecode.ts +18 -0
  412. package/src/index.ts +263 -0
  413. package/src/middleware/Pipeline.ts +136 -0
  414. package/src/openapi/OpenApiGenerator.ts +254 -0
  415. package/src/openapi/OpenApiMiddleware.ts +101 -0
  416. package/src/openapi/OpenApiProvider.ts +67 -0
  417. package/src/resources/ApiResource.ts +79 -0
  418. package/src/router/Router.ts +733 -0
  419. package/src/rpc/RpcProvider.ts +54 -0
  420. package/src/rpc/RpcRouter.ts +243 -0
  421. package/src/scheduler/Schedule.ts +96 -0
  422. package/src/scheduler/ScheduleProvider.ts +177 -0
  423. package/src/scheduler/Scheduler.ts +601 -0
  424. package/src/scheduler/index.ts +24 -0
  425. package/src/scheduler/locks/LockBackend.ts +38 -0
  426. package/src/scheduler/locks/MemoryLockBackend.ts +85 -0
  427. package/src/scheduler/observability/ErrorReporter.ts +13 -0
  428. package/src/scheduler/observability/ScheduleEvent.ts +61 -0
  429. package/src/scheduler/observability/ScheduleEventSink.ts +21 -0
  430. package/src/scheduler/observability/StatsTracker.ts +134 -0
  431. package/src/security/CookieSigner.ts +54 -0
  432. package/src/security/SignedUrl.ts +71 -0
  433. package/src/security/crypto.ts +98 -0
  434. package/src/server/HyperServer.ts +121 -0
  435. package/src/server/Server.ts +147 -0
  436. package/src/services/app.ts +34 -0
  437. package/src/services/router.ts +44 -0
  438. package/src/services/server.ts +40 -0
  439. package/src/session/Session.ts +231 -0
  440. package/src/session/SessionMiddleware.ts +153 -0
  441. package/src/session/drivers/CookieDriver.ts +48 -0
  442. package/src/session/drivers/MemoryDriver.ts +29 -0
  443. package/src/storage/S3Driver.ts +171 -0
  444. package/src/storage/StaticMiddleware.ts +182 -0
  445. package/src/storage/StaticProvider.ts +40 -0
  446. package/src/storage/StorageManager.ts +142 -0
  447. package/src/testing/RequestBuilder.ts +275 -0
  448. package/src/testing/TestClient.ts +344 -0
  449. package/src/types/helpers.ts +52 -0
  450. package/swcrc.app.json +17 -0
  451. package/tsconfig.app.json +21 -0
@@ -0,0 +1,135 @@
1
+ /**
2
+ * S3Driver — S3-compatible cloud storage (AWS S3, Cloudflare R2, MinIO).
3
+ *
4
+ * Uses fetch API — no external SDK dependency.
5
+ * Implements the StorageDriver interface.
6
+ *
7
+ * @implements MISS-24
8
+ */
9
+ import { createHash, createHmac } from 'node:crypto';
10
+ /**
11
+ * URI-encode an S3 object key for use in BOTH the request URL and the
12
+ * SigV4 canonical path. Each `/`-delimited segment is percent-encoded
13
+ * (so the slashes that delimit the key hierarchy survive), which means
14
+ * spaces, `#`, `?`, `%` and non-ASCII bytes can't slip the requested
15
+ * path away from the signed path — the classic "key with a space gets
16
+ * a SignatureDoesNotMatch / 403, or `?`/`#` truncates the path" bug.
17
+ *
18
+ * S3 expects the canonical URI encoded ONCE (unlike the generic SigV4
19
+ * double-encode), and `encodeURIComponent` already escapes the RFC 3986
20
+ * sub-delims AWS cares about. We additionally escape `!`, `'`, `(`,
21
+ * `)`, `*` which `encodeURIComponent` leaves untouched but AWS expects
22
+ * percent-encoded.
23
+ */
24
+ function encodeS3Key(key) {
25
+ return key
26
+ .split('/')
27
+ .map((segment) => encodeURIComponent(segment).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`))
28
+ .join('/');
29
+ }
30
+ export class S3Driver {
31
+ #config;
32
+ #endpoint;
33
+ constructor(config) {
34
+ this.#config = config;
35
+ this.#endpoint = config.endpoint ?? `https://s3.${config.region ?? 'us-east-1'}.amazonaws.com`;
36
+ }
37
+ async put(filePath, content) {
38
+ const body = typeof content === 'string' ? Buffer.from(content) : content;
39
+ const key = encodeS3Key(filePath);
40
+ const url = `${this.#endpoint}/${this.#config.bucket}/${key}`;
41
+ const headers = this.#signRequest('PUT', key, body);
42
+ const res = await fetch(url, { method: 'PUT', headers, body: body });
43
+ if (!res.ok) {
44
+ throw new Error(`S3 PUT failed (${res.status}): ${await res.text()}`);
45
+ }
46
+ }
47
+ async get(filePath) {
48
+ const key = encodeS3Key(filePath);
49
+ const url = `${this.#endpoint}/${this.#config.bucket}/${key}`;
50
+ const headers = this.#signRequest('GET', key);
51
+ const res = await fetch(url, { method: 'GET', headers });
52
+ if (res.status === 404)
53
+ return null;
54
+ if (!res.ok)
55
+ throw new Error(`S3 GET failed (${res.status})`);
56
+ const arrayBuffer = await res.arrayBuffer();
57
+ return Buffer.from(arrayBuffer);
58
+ }
59
+ async delete(filePath) {
60
+ const key = encodeS3Key(filePath);
61
+ const url = `${this.#endpoint}/${this.#config.bucket}/${key}`;
62
+ const headers = this.#signRequest('DELETE', key);
63
+ const res = await fetch(url, { method: 'DELETE', headers });
64
+ return res.ok || res.status === 204;
65
+ }
66
+ async exists(filePath) {
67
+ const key = encodeS3Key(filePath);
68
+ const url = `${this.#endpoint}/${this.#config.bucket}/${key}`;
69
+ const headers = this.#signRequest('HEAD', key);
70
+ const res = await fetch(url, { method: 'HEAD', headers });
71
+ return res.ok;
72
+ }
73
+ url(filePath) {
74
+ const key = encodeS3Key(filePath);
75
+ if (this.#config.publicUrl) {
76
+ return `${this.#config.publicUrl}/${key}`;
77
+ }
78
+ return `${this.#endpoint}/${this.#config.bucket}/${key}`;
79
+ }
80
+ /**
81
+ * Sign a request with AWS Signature V4 (simplified).
82
+ * For production, consider using @aws-sdk/signature-v4 for full compliance.
83
+ */
84
+ #signRequest(method, key, body) {
85
+ const now = new Date();
86
+ const dateStamp = `${now.toISOString().replace(/[-:]/g, '').split('.')[0]}Z`;
87
+ const shortDate = dateStamp.slice(0, 8);
88
+ const region = this.#config.region ?? 'us-east-1';
89
+ const service = 's3';
90
+ const payloadHash = createHash('sha256')
91
+ .update(body ?? '')
92
+ .digest('hex');
93
+ const headers = {
94
+ host: new URL(this.#endpoint).host,
95
+ 'x-amz-date': dateStamp,
96
+ 'x-amz-content-sha256': payloadHash,
97
+ };
98
+ if (body) {
99
+ headers['content-length'] = String(body.length);
100
+ }
101
+ // Canonical request
102
+ const signedHeaders = Object.keys(headers).sort().join(';');
103
+ const canonicalHeaders = Object.keys(headers)
104
+ .sort()
105
+ .map((k) => `${k}:${headers[k]}\n`)
106
+ .join('');
107
+ const canonicalRequest = [
108
+ method,
109
+ `/${this.#config.bucket}/${key}`,
110
+ '',
111
+ canonicalHeaders,
112
+ signedHeaders,
113
+ payloadHash,
114
+ ].join('\n');
115
+ // String to sign
116
+ const scope = `${shortDate}/${region}/${service}/aws4_request`;
117
+ const stringToSign = [
118
+ 'AWS4-HMAC-SHA256',
119
+ dateStamp,
120
+ scope,
121
+ createHash('sha256').update(canonicalRequest).digest('hex'),
122
+ ].join('\n');
123
+ // Signing key
124
+ const kDate = createHmac('sha256', `AWS4${this.#config.secretAccessKey}`)
125
+ .update(shortDate)
126
+ .digest();
127
+ const kRegion = createHmac('sha256', kDate).update(region).digest();
128
+ const kService = createHmac('sha256', kRegion).update(service).digest();
129
+ const kSigning = createHmac('sha256', kService).update('aws4_request').digest();
130
+ const signature = createHmac('sha256', kSigning).update(stringToSign).digest('hex');
131
+ headers.authorization = `AWS4-HMAC-SHA256 Credential=${this.#config.accessKeyId}/${scope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
132
+ return headers;
133
+ }
134
+ }
135
+ //# sourceMappingURL=S3Driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"S3Driver.js","sourceRoot":"","sources":["../../src/storage/S3Driver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Static file serving middleware.
3
+ *
4
+ * Serves files from a directory with cache headers and ETag support.
5
+ *
6
+ * Usage:
7
+ * server.use(new StaticMiddleware({ root: 'public' }))
8
+ *
9
+ * @implements MISS-25
10
+ */
11
+ import type { HttpContext } from '../http/HttpContext.js';
12
+ export interface StaticConfig {
13
+ /** Root directory to serve files from. */
14
+ root: string;
15
+ /** URL prefix (default: /static). */
16
+ prefix?: string;
17
+ /** Max-age for Cache-Control header in seconds (default: 86400 = 1 day). */
18
+ maxAge?: number;
19
+ /** File extensions to serve (default: common web assets). */
20
+ extensions?: string[];
21
+ }
22
+ export declare class StaticMiddleware {
23
+ #private;
24
+ constructor(config: StaticConfig);
25
+ handle(ctx: HttpContext, next: () => Promise<void>): Promise<void>;
26
+ }
27
+ //# sourceMappingURL=StaticMiddleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StaticMiddleware.d.ts","sourceRoot":"","sources":["../../src/storage/StaticMiddleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAEzD,MAAM,WAAW,YAAY;IAC3B,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAA;IACZ,qCAAqC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;CACtB;AAsDD,qBAAa,gBAAgB;;gBAMf,MAAM,EAAE,YAAY;IAO1B,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAyFzE"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Static file serving middleware.
3
+ *
4
+ * Serves files from a directory with cache headers and ETag support.
5
+ *
6
+ * Usage:
7
+ * server.use(new StaticMiddleware({ root: 'public' }))
8
+ *
9
+ * @implements MISS-25
10
+ */
11
+ import { createHash } from 'node:crypto';
12
+ import * as fs from 'node:fs';
13
+ import * as path from 'node:path';
14
+ const DEFAULT_EXTENSIONS = [
15
+ '.html',
16
+ '.css',
17
+ '.js',
18
+ '.json',
19
+ '.xml',
20
+ '.txt',
21
+ '.png',
22
+ '.jpg',
23
+ '.jpeg',
24
+ '.gif',
25
+ '.svg',
26
+ '.ico',
27
+ '.webp',
28
+ '.woff',
29
+ '.woff2',
30
+ '.ttf',
31
+ '.eot',
32
+ '.mp4',
33
+ '.webm',
34
+ '.mp3',
35
+ '.ogg',
36
+ '.pdf',
37
+ '.zip',
38
+ ];
39
+ const MIME_TYPES = {
40
+ '.html': 'text/html',
41
+ '.css': 'text/css',
42
+ '.js': 'application/javascript',
43
+ '.json': 'application/json',
44
+ '.xml': 'application/xml',
45
+ '.txt': 'text/plain',
46
+ '.png': 'image/png',
47
+ '.jpg': 'image/jpeg',
48
+ '.jpeg': 'image/jpeg',
49
+ '.gif': 'image/gif',
50
+ '.svg': 'image/svg+xml',
51
+ '.ico': 'image/x-icon',
52
+ '.webp': 'image/webp',
53
+ '.woff': 'font/woff',
54
+ '.woff2': 'font/woff2',
55
+ '.ttf': 'font/ttf',
56
+ '.eot': 'application/vnd.ms-fontobject',
57
+ '.mp4': 'video/mp4',
58
+ '.webm': 'video/webm',
59
+ '.mp3': 'audio/mpeg',
60
+ '.ogg': 'audio/ogg',
61
+ '.pdf': 'application/pdf',
62
+ '.zip': 'application/zip',
63
+ };
64
+ export class StaticMiddleware {
65
+ #root;
66
+ #prefix;
67
+ #maxAge;
68
+ #extensions;
69
+ constructor(config) {
70
+ this.#root = path.resolve(config.root);
71
+ this.#prefix = config.prefix ?? '/static';
72
+ this.#maxAge = config.maxAge ?? 86400;
73
+ this.#extensions = new Set(config.extensions ?? DEFAULT_EXTENSIONS);
74
+ }
75
+ async handle(ctx, next) {
76
+ if (ctx.request.method() !== 'GET' && ctx.request.method() !== 'HEAD') {
77
+ return next();
78
+ }
79
+ const resolved = this.#resolveServableFile(ctx.request.path());
80
+ if (!resolved)
81
+ return next();
82
+ const { realFilePath, ext, stat } = resolved;
83
+ const etag = createHash('md5').update(`${stat.size}-${stat.mtimeMs}`).digest('hex');
84
+ // ETag check — 304 Not Modified
85
+ const ifNoneMatch = ctx.request.header('if-none-match');
86
+ if (ifNoneMatch === etag) {
87
+ ctx.response.status(304);
88
+ return;
89
+ }
90
+ const mime = MIME_TYPES[ext] ?? 'application/octet-stream';
91
+ ctx.response.header('Content-Type', mime);
92
+ ctx.response.header('Content-Length', String(stat.size));
93
+ ctx.response.header('Cache-Control', `public, max-age=${this.#maxAge}`);
94
+ ctx.response.header('ETag', etag);
95
+ if (ctx.request.method() === 'HEAD') {
96
+ ctx.response.status(200);
97
+ return;
98
+ }
99
+ // Send the raw Buffer — `content.toString()` would interpret PNG /
100
+ // PDF / ZIP bytes as UTF-8 and replace any byte the encoding can't
101
+ // round-trip (anything in the surrogate range, plus invalid
102
+ // sequences) with U+FFFD.
103
+ const content = fs.readFileSync(realFilePath);
104
+ ctx.response.status(200).sendBuffer(content);
105
+ }
106
+ /**
107
+ * Resolve a request path to a real, in-root, existing file, or `null` when it
108
+ * is not servable (wrong prefix/extension, outside the root, missing, or a
109
+ * symlink escaping the root). Returning `null` tells `handle` to call `next()`.
110
+ */
111
+ #resolveServableFile(reqPath) {
112
+ // Match only when the prefix is followed by `/` or end-of-path —
113
+ // otherwise `/staticx/foo.js` would be intercepted when the configured
114
+ // prefix is `/static`, hijacking unrelated routes.
115
+ if (!(reqPath === this.#prefix || reqPath.startsWith(`${this.#prefix}/`))) {
116
+ return null;
117
+ }
118
+ // Strip prefix and resolve file path
119
+ const relativePath = reqPath.slice(this.#prefix.length) || '/index.html';
120
+ const ext = path.extname(relativePath).toLowerCase();
121
+ if (!this.#extensions.has(ext))
122
+ return null;
123
+ const filePath = path.resolve(this.#root, relativePath.replace(/^\//, ''));
124
+ // Two containment checks. The first uses `path.sep` to reject sibling
125
+ // directories with a shared prefix (`/var/www-static-secret` slipping
126
+ // past a guard for `/var/www-static`). The second resolves symlinks
127
+ // via realpathSync so a symlink planted inside the root cannot point
128
+ // outside it. We do realpath AFTER the lexical check so a non-existent
129
+ // path returns `next()` rather than throwing.
130
+ const rootWithSep = this.#root.endsWith(path.sep) ? this.#root : this.#root + path.sep;
131
+ if (filePath !== this.#root && !filePath.startsWith(rootWithSep)) {
132
+ return null;
133
+ }
134
+ if (!fs.existsSync(filePath) || !fs.statSync(filePath).isFile()) {
135
+ return null;
136
+ }
137
+ let realFilePath;
138
+ let realRoot;
139
+ try {
140
+ realFilePath = fs.realpathSync(filePath);
141
+ realRoot = fs.realpathSync(this.#root);
142
+ }
143
+ catch {
144
+ return null;
145
+ }
146
+ const realRootWithSep = realRoot.endsWith(path.sep) ? realRoot : realRoot + path.sep;
147
+ if (realFilePath !== realRoot && !realFilePath.startsWith(realRootWithSep)) {
148
+ return null;
149
+ }
150
+ return { realFilePath, ext, stat: fs.statSync(realFilePath) };
151
+ }
152
+ }
153
+ //# sourceMappingURL=StaticMiddleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StaticMiddleware.js","sourceRoot":"","sources":["../../src/storage/StaticMiddleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * `StaticProvider` — serves static files from a directory.
3
+ *
4
+ * Opt-in: does nothing unless `config.static.root` is set (or a middleware is
5
+ * injected for tests). When configured, `boot()` mounts a global
6
+ * `StaticMiddleware` (path-traversal + symlink-escape guarded) that serves
7
+ * matching requests and falls through (`next()`) otherwise.
8
+ *
9
+ * // config/static.ts
10
+ * export default { root: 'public', prefix: '/static' }
11
+ *
12
+ * @implements MISS-25
13
+ */
14
+ import type { AppContext } from '../Provider.js';
15
+ import { Provider } from '../Provider.js';
16
+ import { StaticMiddleware } from './StaticMiddleware.js';
17
+ export interface StaticProviderOptions {
18
+ /** Override the `StaticMiddleware` instance — used by tests. */
19
+ middleware?: StaticMiddleware;
20
+ }
21
+ export declare class StaticProvider extends Provider {
22
+ #private;
23
+ constructor(app: AppContext, options?: StaticProviderOptions);
24
+ boot(): Promise<void>;
25
+ }
26
+ //# sourceMappingURL=StaticProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StaticProvider.d.ts","sourceRoot":"","sources":["../../src/storage/StaticProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAqB,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAE3E,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,UAAU,CAAC,EAAE,gBAAgB,CAAA;CAC9B;AAED,qBAAa,cAAe,SAAQ,QAAQ;;gBAG9B,GAAG,EAAE,UAAU,EAAE,OAAO,GAAE,qBAA0B;IAKjD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAOrC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * `StaticProvider` — serves static files from a directory.
3
+ *
4
+ * Opt-in: does nothing unless `config.static.root` is set (or a middleware is
5
+ * injected for tests). When configured, `boot()` mounts a global
6
+ * `StaticMiddleware` (path-traversal + symlink-escape guarded) that serves
7
+ * matching requests and falls through (`next()`) otherwise.
8
+ *
9
+ * // config/static.ts
10
+ * export default { root: 'public', prefix: '/static' }
11
+ *
12
+ * @implements MISS-25
13
+ */
14
+ import { Provider } from '../Provider.js';
15
+ import { StaticMiddleware } from './StaticMiddleware.js';
16
+ export class StaticProvider extends Provider {
17
+ #override;
18
+ constructor(app, options = {}) {
19
+ super(app);
20
+ this.#override = options.middleware;
21
+ }
22
+ async boot() {
23
+ const config = this.app.config.get('static');
24
+ const middleware = this.#override ?? (config?.root ? new StaticMiddleware(config) : undefined);
25
+ if (!middleware)
26
+ return; // not configured — opt-out
27
+ const server = this.app.container.make('server');
28
+ server.use([(ctx, next) => middleware.handle(ctx, next)]);
29
+ }
30
+ }
31
+ //# sourceMappingURL=StaticProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StaticProvider.js","sourceRoot":"","sources":["../../src/storage/StaticProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,OAAO,EAAqB,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAO3E,MAAM,OAAO,cAAe,SAAQ,QAAQ;IACjC,SAAS,CAAmB;IAErC,YAAY,GAAe,EAAE,UAAiC,EAAE;QAC9D,KAAK,CAAC,GAAG,CAAC,CAAA;QACV,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,UAAU,CAAA;IACrC,CAAC;IAEQ,KAAK,CAAC,IAAI;QACjB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAe,QAAQ,CAAC,CAAA;QAC1D,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;QAC9F,IAAI,CAAC,UAAU;YAAE,OAAM,CAAC,2BAA2B;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAS,QAAQ,CAAC,CAAA;QACxD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;IAC3D,CAAC;CACF"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Storage — file storage abstraction with driver pattern.
3
+ *
4
+ * @implements MISS-24
5
+ */
6
+ export interface StorageDriver {
7
+ put(filePath: string, content: Buffer | string): Promise<void>;
8
+ get(filePath: string): Promise<Buffer | null>;
9
+ delete(filePath: string): Promise<boolean>;
10
+ exists(filePath: string): Promise<boolean>;
11
+ url(filePath: string): string;
12
+ }
13
+ export declare class LocalDriver implements StorageDriver {
14
+ #private;
15
+ constructor(root: string);
16
+ put(filePath: string, content: Buffer | string): Promise<void>;
17
+ get(filePath: string): Promise<Buffer | null>;
18
+ delete(filePath: string): Promise<boolean>;
19
+ exists(filePath: string): Promise<boolean>;
20
+ url(filePath: string): string;
21
+ }
22
+ export declare class StorageManager {
23
+ #private;
24
+ constructor(driver: StorageDriver);
25
+ put(filePath: string, content: Buffer | string): Promise<void>;
26
+ get(filePath: string): Promise<Buffer | null>;
27
+ delete(filePath: string): Promise<boolean>;
28
+ exists(filePath: string): Promise<boolean>;
29
+ url(filePath: string): string;
30
+ }
31
+ //# sourceMappingURL=StorageManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StorageManager.d.ts","sourceRoot":"","sources":["../../src/storage/StorageManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAsDH,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC9D,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;IAC7C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1C,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;CAC9B;AAED,qBAAa,WAAY,YAAW,aAAa;;gBAGnC,IAAI,EAAE,MAAM;IAOlB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS9D,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAM7C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAO1C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYhD,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAG9B;AAED,qBAAa,cAAc;;gBAGb,MAAM,EAAE,aAAa;IAIjC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI9D,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAI7C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1C,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1C,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;CAG9B"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Storage — file storage abstraction with driver pattern.
3
+ *
4
+ * @implements MISS-24
5
+ */
6
+ import * as fs from 'node:fs';
7
+ import * as path from 'node:path';
8
+ /**
9
+ * Resolve `filePath` against `root` and reject any result that escapes
10
+ * the storage root. Without this guard a user-controlled path like
11
+ * `../secrets.env` would let put/get/delete/exists touch arbitrary
12
+ * files outside the configured storage root.
13
+ *
14
+ * The lexical check (`path.resolve` + `startsWith`) catches the
15
+ * `../` / absolute-path class. The realpath re-check catches the
16
+ * symlink-escape class: a symlink planted under the root (or anywhere
17
+ * else on the resolved path's chain) that points outside the root
18
+ * would pass the lexical gate but be caught here.
19
+ *
20
+ * We canonicalize the longest existing ancestor of `full` — `realpath`
21
+ * itself throws ENOENT on a target that doesn't exist yet (the `put`
22
+ * happy-path for new files). Symlinks anywhere ABOVE the leaf are
23
+ * still dereferenced, which is the only escape vector that matters:
24
+ * the driver creates the leaf itself, so no symlink can pre-exist
25
+ * there.
26
+ */
27
+ function assertWithinRoot(root, filePath) {
28
+ const full = path.resolve(root, filePath);
29
+ const rootAbs = path.resolve(root);
30
+ if (full !== rootAbs && !full.startsWith(rootAbs + path.sep)) {
31
+ throw new Error(`[ream-storage] path '${filePath}' escapes the storage root (E_PATH_TRAVERSAL)`);
32
+ }
33
+ const canonicalRoot = fs.existsSync(rootAbs) ? fs.realpathSync(rootAbs) : rootAbs;
34
+ const ancestor = longestExistingAncestor(full);
35
+ const canonicalAncestor = ancestor === full ? fs.realpathSync(full) : fs.realpathSync(ancestor);
36
+ // Re-attach the not-yet-existing leaf to the canonicalized ancestor.
37
+ const canonicalFull = canonicalAncestor + full.slice(ancestor.length);
38
+ if (canonicalFull !== canonicalRoot && !canonicalFull.startsWith(canonicalRoot + path.sep)) {
39
+ throw new Error(`[ream-storage] path '${filePath}' escapes the storage root via a symlink (E_PATH_TRAVERSAL)`);
40
+ }
41
+ return full;
42
+ }
43
+ /** Walk up `full` until we find a path that exists on disk. */
44
+ function longestExistingAncestor(full) {
45
+ let current = full;
46
+ while (!fs.existsSync(current)) {
47
+ const parent = path.dirname(current);
48
+ if (parent === current)
49
+ return current;
50
+ current = parent;
51
+ }
52
+ return current;
53
+ }
54
+ export class LocalDriver {
55
+ #root;
56
+ constructor(root) {
57
+ this.#root = root;
58
+ if (!fs.existsSync(root)) {
59
+ fs.mkdirSync(root, { recursive: true });
60
+ }
61
+ }
62
+ async put(filePath, content) {
63
+ const full = assertWithinRoot(this.#root, filePath);
64
+ const dir = path.dirname(full);
65
+ if (!fs.existsSync(dir)) {
66
+ fs.mkdirSync(dir, { recursive: true });
67
+ }
68
+ fs.writeFileSync(full, content);
69
+ }
70
+ async get(filePath) {
71
+ const full = assertWithinRoot(this.#root, filePath);
72
+ if (!fs.existsSync(full))
73
+ return null;
74
+ return fs.readFileSync(full);
75
+ }
76
+ async delete(filePath) {
77
+ const full = assertWithinRoot(this.#root, filePath);
78
+ if (!fs.existsSync(full))
79
+ return false;
80
+ fs.unlinkSync(full);
81
+ return true;
82
+ }
83
+ async exists(filePath) {
84
+ let full;
85
+ try {
86
+ full = assertWithinRoot(this.#root, filePath);
87
+ }
88
+ catch {
89
+ // exists() must NOT leak existence of out-of-root paths via the
90
+ // thrown error — quietly report "no" for any traversal attempt.
91
+ return false;
92
+ }
93
+ return fs.existsSync(full);
94
+ }
95
+ url(filePath) {
96
+ return `/storage/${filePath}`;
97
+ }
98
+ }
99
+ export class StorageManager {
100
+ #driver;
101
+ constructor(driver) {
102
+ this.#driver = driver;
103
+ }
104
+ put(filePath, content) {
105
+ return this.#driver.put(filePath, content);
106
+ }
107
+ get(filePath) {
108
+ return this.#driver.get(filePath);
109
+ }
110
+ delete(filePath) {
111
+ return this.#driver.delete(filePath);
112
+ }
113
+ exists(filePath) {
114
+ return this.#driver.exists(filePath);
115
+ }
116
+ url(filePath) {
117
+ return this.#driver.url(filePath);
118
+ }
119
+ }
120
+ //# sourceMappingURL=StorageManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StorageManager.js","sourceRoot":"","sources":["../../src/storage/StorageManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAA;AAC7B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AAEjC;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAS,gBAAgB,CAAC,IAAY,EAAE,QAAgB;IACtD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAClC,IAAI,IAAI,KAAK,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,wBAAwB,QAAQ,+CAA+C,CAAC,CAAA;IAClG,CAAC;IACD,MAAM,aAAa,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;IACjF,MAAM,QAAQ,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAA;IAC9C,MAAM,iBAAiB,GAAG,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA;IAC/F,qEAAqE;IACrE,MAAM,aAAa,GAAG,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;IACrE,IAAI,aAAa,KAAK,aAAa,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3F,MAAM,IAAI,KAAK,CACb,wBAAwB,QAAQ,6DAA6D,CAC9F,CAAA;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,+DAA+D;AAC/D,SAAS,uBAAuB,CAAC,IAAY;IAC3C,IAAI,OAAO,GAAG,IAAI,CAAA;IAClB,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QACpC,IAAI,MAAM,KAAK,OAAO;YAAE,OAAO,OAAO,CAAA;QACtC,OAAO,GAAG,MAAM,CAAA;IAClB,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAUD,MAAM,OAAO,WAAW;IACtB,KAAK,CAAQ;IAEb,YAAY,IAAY;QACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACjB,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACzC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,QAAgB,EAAE,OAAwB;QAClD,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QAC9B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACxC,CAAC;QACD,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IACjC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,QAAgB;QACxB,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;QACnD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;QACrC,OAAO,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;IAC9B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAAgB;QAC3B,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;QACnD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAA;QACtC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACnB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAAgB;QAC3B,IAAI,IAAY,CAAA;QAChB,IAAI,CAAC;YACH,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAA;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,gEAAgE;YAChE,gEAAgE;YAChE,OAAO,KAAK,CAAA;QACd,CAAC;QACD,OAAO,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;IAC5B,CAAC;IAED,GAAG,CAAC,QAAgB;QAClB,OAAO,YAAY,QAAQ,EAAE,CAAA;IAC/B,CAAC;CACF;AAED,MAAM,OAAO,cAAc;IACzB,OAAO,CAAe;IAEtB,YAAY,MAAqB;QAC/B,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;IACvB,CAAC;IAED,GAAG,CAAC,QAAgB,EAAE,OAAwB;QAC5C,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAC5C,CAAC;IAED,GAAG,CAAC,QAAgB;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACnC,CAAC;IAED,MAAM,CAAC,QAAgB;QACrB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IACtC,CAAC;IAED,MAAM,CAAC,QAAgB;QACrB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IACtC,CAAC;IAED,GAAG,CAAC,QAAgB;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IACnC,CAAC;CACF"}
@@ -0,0 +1,67 @@
1
+ import type { TestResponse } from './TestClient.js';
2
+ /**
3
+ * Fluent HTTP request builder with assertion methods.
4
+ *
5
+ * await client
6
+ * .fluent('GET', '/api/users/42')
7
+ * .withAuth(user)
8
+ * .expectStatus(200)
9
+ * .expectJson({ id: 42 })
10
+ *
11
+ * The builder chains: setters return `this`, assertion methods send the
12
+ * request on first call (memoised) and return a `Promise<this>` so further
13
+ * assertions can be awaited or chained via `await`.
14
+ */
15
+ export interface AuthSubject {
16
+ /** String or numeric user id — used by `withAuth` / `asUser` to sign the session. */
17
+ id: string | number;
18
+ /** Optional custom headers added to the request (e.g. tenant markers). */
19
+ extraHeaders?: Record<string, string>;
20
+ }
21
+ export interface AuthStrategy {
22
+ /** Compute the headers Warden expects for this user (Bearer token / session cookie / ...). */
23
+ headersFor(subject: AuthSubject): Record<string, string> | Promise<Record<string, string>>;
24
+ /** Compute cookies for session-based strategies. */
25
+ cookiesFor?(subject: AuthSubject): Record<string, string> | Promise<Record<string, string>>;
26
+ }
27
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
28
+ /**
29
+ * Internal low-level sender — matches what the TestClient exposes.
30
+ * Accepting it as an injected callable keeps RequestBuilder framework-agnostic.
31
+ */
32
+ export type HttpSender = (method: HttpMethod, path: string, init: {
33
+ headers: Record<string, string>;
34
+ body: Buffer;
35
+ }) => Promise<TestResponse>;
36
+ export declare class RequestBuilder {
37
+ #private;
38
+ constructor(sender: HttpSender, method: HttpMethod, path: string, authStrategy?: AuthStrategy | null);
39
+ headers(map: Record<string, string>): this;
40
+ header(name: string, value: string): this;
41
+ json(data: unknown): this;
42
+ body(data: Buffer | string, contentType?: string): this;
43
+ form(data: Record<string, string>): this;
44
+ cookies(map: Record<string, string>): this;
45
+ cookie(name: string, value: string): this;
46
+ /**
47
+ * Attach auth for a user. Uses the strategy passed to `client`'s `auth`
48
+ * option — Warden's session/JWT/API-key strategy decides the header/cookie
49
+ * shape. Without a strategy, throws at send time.
50
+ */
51
+ withAuth(subject: AuthSubject): this;
52
+ /** Shortcut for `withAuth({ id: userId })` — user is identified by id only. */
53
+ asUser(userId: string | number): this;
54
+ /** Fire the request (once) and return the raw response. Idempotent. */
55
+ send(): Promise<TestResponse>;
56
+ expectStatus(code: number): Promise<this>;
57
+ expectHeader(name: string, value: string | RegExp): Promise<this>;
58
+ expectCookie(name: string, value?: string | RegExp): Promise<this>;
59
+ expectJson(expected: unknown): Promise<this>;
60
+ }
61
+ /**
62
+ * Partial deep-match. For objects, every key in `expected` must match in
63
+ * `actual`. For arrays, every element in `expected` must match SOMEWHERE in
64
+ * `actual` (order-independent). Primitives compared by strict equality.
65
+ */
66
+ export declare function partialMatch(actual: unknown, expected: unknown): boolean;
67
+ //# sourceMappingURL=RequestBuilder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestBuilder.d.ts","sourceRoot":"","sources":["../../src/testing/RequestBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAEnD;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,WAAW;IAC1B,qFAAqF;IACrF,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IACnB,0EAA0E;IAC1E,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACtC;AAED,MAAM,WAAW,YAAY;IAC3B,8FAA8F;IAC9F,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC1F,oDAAoD;IACpD,UAAU,CAAC,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;CAC5F;AAUD,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;AAEpE;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,CACvB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IACJ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,IAAI,EAAE,MAAM,CAAA;CACb,KACE,OAAO,CAAC,YAAY,CAAC,CAAA;AAE1B,qBAAa,cAAc;;gBAYvB,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,YAAY,GAAE,YAAY,GAAG,IAAW;IAQ1C,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAO1C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAKzC,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAMzB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI;IAMvD,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IASxC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAK1C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAKzC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAKpC,+EAA+E;IAC/E,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAKrC,uEAAuE;IACvE,IAAI,IAAI,OAAO,CAAC,YAAY,CAAC;IAKvB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzC,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBjE,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBlE,UAAU,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAoDnD;AAWD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAcxE"}