@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,85 @@
1
+ /**
2
+ * Default single-process lock backend backed by a `Map`.
3
+ *
4
+ * Correct for apps that run in a single Node.js process. For
5
+ * horizontally-scaled deployments, implement `LockBackend` against a
6
+ * shared store (Redis `SET NX PX`, Postgres advisory locks, etc.) —
7
+ * those drivers live in user-land per the project's "agnostic per
8
+ * package" rule.
9
+ *
10
+ * Expiry is evaluated **lazily** at `acquire` time — no background
11
+ * timer, no `setInterval`. This preserves Story 28.1's
12
+ * Rust-ticker-only philosophy: the only timers in the scheduler live
13
+ * in the Rust Tokio runtime.
14
+ *
15
+ * An opportunistic sweep runs at most once per `acquire` call to
16
+ * cap unbounded growth: when the map exceeds `SWEEP_THRESHOLD`
17
+ * entries, expired entries are pruned in O(N) without blocking
18
+ * the normal path.
19
+ *
20
+ * @implements Story 28.3
21
+ */
22
+
23
+ import { ReamError } from '../../errors/ReamError.js'
24
+ import type { LockBackend } from './LockBackend.js'
25
+
26
+ const SWEEP_THRESHOLD = 256
27
+
28
+ function assertValidTtl(ttlMs: number): void {
29
+ if (!Number.isFinite(ttlMs) || ttlMs <= 0) {
30
+ throw new ReamError(
31
+ 'SCHEDULE_INVALID_LOCK_TTL',
32
+ `Lock TTL must be a finite positive number, got ${ttlMs}`,
33
+ {
34
+ hint: 'Use a millisecond value greater than zero (typical range 1_000 – 600_000).',
35
+ },
36
+ )
37
+ }
38
+ }
39
+
40
+ export class MemoryLockBackend implements LockBackend {
41
+ #locks = new Map<string, number>()
42
+
43
+ async acquire(name: string, ttlMs: number): Promise<boolean> {
44
+ assertValidTtl(ttlMs)
45
+ const now = Date.now()
46
+
47
+ // Opportunistic sweep: when the map grows past the threshold,
48
+ // drop expired entries. Bounded by the current map size, runs at
49
+ // most once per acquire, never schedules async work.
50
+ if (this.#locks.size >= SWEEP_THRESHOLD) {
51
+ for (const [key, expiry] of this.#locks) {
52
+ if (expiry <= now) this.#locks.delete(key)
53
+ }
54
+ }
55
+
56
+ const existing = this.#locks.get(name)
57
+ if (existing !== undefined && existing > now) {
58
+ return false
59
+ }
60
+ this.#locks.set(name, now + ttlMs)
61
+ return true
62
+ }
63
+
64
+ async release(name: string): Promise<void> {
65
+ this.#locks.delete(name)
66
+ }
67
+
68
+ /**
69
+ * @internal Test-only helper: force an entry into the map with an
70
+ * arbitrary expiry. Used to simulate a crashed holder whose lock
71
+ * has already expired without advancing `Date.now()`. Not part of
72
+ * the public {@link LockBackend} contract — never call from
73
+ * production code.
74
+ */
75
+ __setExpiryForTesting(name: string, expiryMs: number): void {
76
+ this.#locks.set(name, expiryMs)
77
+ }
78
+
79
+ /** @internal Test-only helper — return the current map size. */
80
+ __sizeForTesting(): number {
81
+ return this.#locks.size
82
+ }
83
+ }
84
+
85
+ export default MemoryLockBackend
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Callback invoked when a scheduled task throws. Typically bridges
3
+ * to `ErrorBoundary.serviceError` — but the scheduler does not
4
+ * import `ErrorBoundary` directly; the user wires the adapter
5
+ * per the "agnostic per package" rule.
6
+ *
7
+ * The scheduler wraps the call in its own `try/catch`, so an
8
+ * `ErrorReporter` that itself throws cannot crash the Rust ticker.
9
+ *
10
+ * @implements Story 28.4
11
+ */
12
+
13
+ export type ErrorReporter = (err: unknown, context: { taskName: string }) => void
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Discriminated union of events emitted by the scheduler's task
3
+ * invocation wrapper.
4
+ *
5
+ * All payloads are JSON-serializable so downstream sinks (the event bus,
6
+ * structured logs, metrics backends) can forward them without
7
+ * touching live `Error` instances.
8
+ *
9
+ * @implements Story 28.4
10
+ */
11
+
12
+ export interface ScheduleTaskStartedEvent {
13
+ type: 'schedule.task.started'
14
+ taskName: string
15
+ /** ms-epoch instant the Rust ticker chose for this fire. */
16
+ scheduledForMs: number
17
+ /** ms-epoch at which the JS wrapper began running the user callback. */
18
+ startedAtMs: number
19
+ }
20
+
21
+ export interface ScheduleTaskCompletedEvent {
22
+ type: 'schedule.task.completed'
23
+ taskName: string
24
+ /** Wall-clock milliseconds spent running the callback. */
25
+ durationMs: number
26
+ }
27
+
28
+ export interface ScheduleTaskFailedEvent {
29
+ type: 'schedule.task.failed'
30
+ taskName: string
31
+ /** Plain-object projection of the thrown error (no live `Error`). */
32
+ error: { name: string; message: string; stack?: string }
33
+ /** Wall-clock milliseconds until the throw. */
34
+ durationMs: number
35
+ }
36
+
37
+ export interface ScheduleTaskSkippedEvent {
38
+ type: 'schedule.task.skipped'
39
+ taskName: string
40
+ /** Reason this tick did not execute the task body.
41
+ * - `'locked'` — distributed-lock backend reported the slot as
42
+ * already held by another instance.
43
+ * - `'acquire-failed'` — the lock backend itself threw/rejected
44
+ * (e.g. Redis connection drop); the scheduler treats the tick
45
+ * as skipped for observability rather than silently dropping.
46
+ * - `'already-running'` — an in-process invocation of the same
47
+ * task is already in flight (ticker + concurrent `runTaskNow`,
48
+ * or two simultaneous `runTaskNow` calls). The duplicate is
49
+ * dropped to prevent double-execution of non-idempotent tasks.
50
+ *
51
+ * Left open for future reasons (e.g. `'paused'`). Consumers that
52
+ * branch on `reason` should handle unknown values defensively
53
+ * (log + treat as skip) so adding a new variant is non-breaking. */
54
+ reason: 'locked' | 'acquire-failed' | 'already-running'
55
+ }
56
+
57
+ export type ScheduleEvent =
58
+ | ScheduleTaskStartedEvent
59
+ | ScheduleTaskCompletedEvent
60
+ | ScheduleTaskFailedEvent
61
+ | ScheduleTaskSkippedEvent
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Destination for scheduler task-invocation events.
3
+ *
4
+ * This interface is intentionally minimal so users can adapt to any
5
+ * event bus (the bus, a raw `EventEmitter`, a structured logger). The
6
+ * scheduler does NOT import the event bus directly — writing the
7
+ * bridge is the user's responsibility per the project's "agnostic
8
+ * per package" rule.
9
+ *
10
+ * The scheduler treats `emit` as fire-and-forget: it does not await
11
+ * the return value, and any sync throw is caught at the call site so
12
+ * a buggy adapter cannot crash the Rust ticker.
13
+ *
14
+ * @implements Story 28.4
15
+ */
16
+
17
+ import type { ScheduleEvent } from './ScheduleEvent.js'
18
+
19
+ export interface ScheduleEventSink {
20
+ emit(event: ScheduleEvent): void | Promise<void>
21
+ }
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Per-task run statistics. Populated by the scheduler's invocation
3
+ * wrapper and surfaced via `Scheduler.getStats(taskName)`.
4
+ *
5
+ * `nextRunMs` is NOT tracked here — it is read live from the Rust
6
+ * NAPI layer every time `Scheduler.getStats` is called. This tracker
7
+ * only owns counters that accumulate over time.
8
+ *
9
+ * @implements Story 28.4
10
+ */
11
+
12
+ export interface TaskStats {
13
+ /** ms-epoch of the most recent fire that the wrapper STARTED (lock-skipped fires do not update this). `null` if never started. */
14
+ lastRunMs: number | null
15
+ /** ms-epoch of the next scheduled fire as reported by the Rust core. `null` when the task is unknown or the core returns null. */
16
+ nextRunMs: number | null
17
+ /** Total terminal invocations: completed + failed + skipped. */
18
+ runCount: number
19
+ /** Completed (callback resolved without throwing). */
20
+ successCount: number
21
+ /** Failed (callback threw / rejected). */
22
+ errorCount: number
23
+ /** Skipped (lock backend reported the task already held by another instance). */
24
+ skippedCount: number
25
+ /**
26
+ * Rolling average wall-clock duration over completed + failed
27
+ * runs (skipped runs have no duration and are excluded). `0`
28
+ * until at least one duration has been recorded.
29
+ */
30
+ avgDurationMs: number
31
+ }
32
+
33
+ interface InternalStats {
34
+ lastRunMs: number | null
35
+ runCount: number
36
+ successCount: number
37
+ errorCount: number
38
+ skippedCount: number
39
+ totalDurationMs: number
40
+ durationRunCount: number
41
+ }
42
+
43
+ function zeroInternal(): InternalStats {
44
+ return {
45
+ lastRunMs: null,
46
+ runCount: 0,
47
+ successCount: 0,
48
+ errorCount: 0,
49
+ skippedCount: 0,
50
+ totalDurationMs: 0,
51
+ durationRunCount: 0,
52
+ }
53
+ }
54
+
55
+ /**
56
+ * O(1) in-memory counter map — one entry per task name seen. Never
57
+ * grows beyond the number of distinct task names the scheduler has
58
+ * seen; no per-run history retained.
59
+ */
60
+ export class StatsTracker {
61
+ #stats = new Map<string, InternalStats>()
62
+
63
+ #ensure(name: string): InternalStats {
64
+ let s = this.#stats.get(name)
65
+ if (!s) {
66
+ s = zeroInternal()
67
+ this.#stats.set(name, s)
68
+ }
69
+ return s
70
+ }
71
+
72
+ recordStarted(name: string, startedAtMs: number): void {
73
+ this.#ensure(name).lastRunMs = startedAtMs
74
+ }
75
+
76
+ recordCompleted(name: string, durationMs: number): void {
77
+ const s = this.#ensure(name)
78
+ s.runCount++
79
+ s.successCount++
80
+ // Guard against non-finite durations — a caller bug passing NaN or
81
+ // Infinity would permanently poison the rolling average. Still
82
+ // count the run; only skip the duration accumulation.
83
+ if (Number.isFinite(durationMs)) {
84
+ s.totalDurationMs += durationMs
85
+ s.durationRunCount++
86
+ }
87
+ }
88
+
89
+ recordFailed(name: string, durationMs: number): void {
90
+ const s = this.#ensure(name)
91
+ s.runCount++
92
+ s.errorCount++
93
+ if (Number.isFinite(durationMs)) {
94
+ s.totalDurationMs += durationMs
95
+ s.durationRunCount++
96
+ }
97
+ }
98
+
99
+ recordSkipped(name: string): void {
100
+ const s = this.#ensure(name)
101
+ s.runCount++
102
+ s.skippedCount++
103
+ }
104
+
105
+ /**
106
+ * Return a defensive snapshot. Unknown tasks yield a zeroed
107
+ * snapshot with `null` timestamps. `nextRunMs` is always `null`
108
+ * here — the caller (`Scheduler.getStats`) overlays the live
109
+ * value from the NAPI layer.
110
+ */
111
+ get(name: string): TaskStats {
112
+ const s = this.#stats.get(name)
113
+ if (!s) {
114
+ return {
115
+ lastRunMs: null,
116
+ nextRunMs: null,
117
+ runCount: 0,
118
+ successCount: 0,
119
+ errorCount: 0,
120
+ skippedCount: 0,
121
+ avgDurationMs: 0,
122
+ }
123
+ }
124
+ return {
125
+ lastRunMs: s.lastRunMs,
126
+ nextRunMs: null,
127
+ runCount: s.runCount,
128
+ successCount: s.successCount,
129
+ errorCount: s.errorCount,
130
+ skippedCount: s.skippedCount,
131
+ avgDurationMs: s.durationRunCount > 0 ? s.totalDurationMs / s.durationRunCount : 0,
132
+ }
133
+ }
134
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Cookie signing and encryption.
3
+ * Uses Rust NAPI via crypto facade when available.
4
+ */
5
+
6
+ import { createCipheriv, createDecipheriv, createHmac, randomBytes } from 'node:crypto'
7
+ import { hmacSign, hmacVerify } from './crypto.js'
8
+
9
+ export class CookieSigner {
10
+ #secret: string
11
+ #keyBuffer: Buffer
12
+
13
+ constructor(secret: string) {
14
+ this.#secret = secret
15
+ // Derive a 32-byte key for AES-256-GCM via HKDF-like derivation
16
+ this.#keyBuffer = Buffer.from(createHmac('sha256', secret).update('cookie-key').digest())
17
+ }
18
+
19
+ sign(value: string): string {
20
+ const sig = hmacSign(value, this.#secret)
21
+ return `${value}.${sig}`
22
+ }
23
+
24
+ unsign(signed: string): string | null {
25
+ const lastDot = signed.lastIndexOf('.')
26
+ if (lastDot === -1) return null
27
+ const value = signed.slice(0, lastDot)
28
+ const sig = signed.slice(lastDot + 1)
29
+ return hmacVerify(value, sig, this.#secret) ? value : null
30
+ }
31
+
32
+ encrypt(value: string): string {
33
+ const iv = randomBytes(12)
34
+ const cipher = createCipheriv('aes-256-gcm', this.#keyBuffer, iv)
35
+ const encrypted = Buffer.concat([cipher.update(value, 'utf8'), cipher.final()])
36
+ const tag = cipher.getAuthTag()
37
+ return `${iv.toString('base64url')}.${encrypted.toString('base64url')}.${tag.toString('base64url')}`
38
+ }
39
+
40
+ decrypt(encrypted: string): string | null {
41
+ const parts = encrypted.split('.')
42
+ if (parts.length !== 3) return null
43
+ try {
44
+ const iv = Buffer.from(parts[0], 'base64url')
45
+ const data = Buffer.from(parts[1], 'base64url')
46
+ const tag = Buffer.from(parts[2], 'base64url')
47
+ const decipher = createDecipheriv('aes-256-gcm', this.#keyBuffer, iv)
48
+ decipher.setAuthTag(tag)
49
+ return Buffer.concat([decipher.update(data), decipher.final()]).toString('utf8')
50
+ } catch {
51
+ return null
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Signed URLs — HMAC-SHA256 with expiration.
3
+ * Uses Rust NAPI via crypto facade when available.
4
+ */
5
+
6
+ import { constantTimeEq, hmacSign } from './crypto.js'
7
+
8
+ export interface SignedUrlConfig {
9
+ secret: string
10
+ }
11
+
12
+ export class SignedUrl {
13
+ #secret: string
14
+
15
+ constructor(config: SignedUrlConfig) {
16
+ this.#secret = config.secret
17
+ }
18
+
19
+ make(path: string, options?: { expiresIn?: string | number; purpose?: string }): string {
20
+ const url = new URL(path, 'http://localhost')
21
+ // Audit 2026-05-22: `expiresIn !== undefined` instead of truthy check.
22
+ // `expiresIn: 0` previously fell through the falsy branch and produced
23
+ // an URL with no `expires` param — a never-expiring signed URL when the
24
+ // caller explicitly asked for "expires immediately". The new check
25
+ // honours 0 (and any other numeric input) by stamping the expires param;
26
+ // verify() then rejects it as soon as the wall clock advances.
27
+ if (options?.expiresIn !== undefined) {
28
+ url.searchParams.set(
29
+ 'expires',
30
+ String(Math.floor(Date.now() / 1000) + parseExpiry(options.expiresIn)),
31
+ )
32
+ }
33
+ if (options?.purpose) {
34
+ url.searchParams.set('purpose', options.purpose)
35
+ }
36
+ url.searchParams.set('signature', hmacSign(url.pathname + url.search, this.#secret))
37
+ return url.pathname + url.search
38
+ }
39
+
40
+ verify(urlString: string, purpose?: string): boolean {
41
+ const url = new URL(urlString, 'http://localhost')
42
+ const providedSig = url.searchParams.get('signature')
43
+ if (!providedSig) return false
44
+ const expires = url.searchParams.get('expires')
45
+ if (expires && Math.floor(Date.now() / 1000) > parseInt(expires, 10)) return false
46
+ if (purpose && url.searchParams.get('purpose') !== purpose) return false
47
+
48
+ url.searchParams.delete('signature')
49
+ const expectedSig = hmacSign(url.pathname + url.search, this.#secret)
50
+ return constantTimeEq(providedSig, expectedSig)
51
+ }
52
+ }
53
+
54
+ function parseExpiry(value: string | number): number {
55
+ if (typeof value === 'number') return value
56
+ const match = value.match(/^(\d+)(s|m|h|d)$/)
57
+ if (!match) return 3600
58
+ const num = parseInt(match[1], 10)
59
+ switch (match[2]) {
60
+ case 's':
61
+ return num
62
+ case 'm':
63
+ return num * 60
64
+ case 'h':
65
+ return num * 3600
66
+ case 'd':
67
+ return num * 86400
68
+ default:
69
+ return 3600
70
+ }
71
+ }
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Crypto facade — resolves Rust NAPI bindings at load time.
3
+ * If the binary isn't available, falls back to Node.js crypto.
4
+ *
5
+ * Usage:
6
+ * import { hmacSign, hmacVerify, randomHex, constantTimeEq } from './crypto.js'
7
+ */
8
+
9
+ import { createHmac, randomBytes as nodeRandomBytes, timingSafeEqual } from 'node:crypto'
10
+
11
+ interface NapiCrypto {
12
+ hmacSign(data: string, secret: string): string
13
+ hmacVerify(data: string, signature: string, secret: string): boolean
14
+ randomBytesBase64(len: number): string
15
+ randomHex(len: number): string
16
+ constantTimeEq(a: string, b: string): boolean
17
+ }
18
+
19
+ let napi: NapiCrypto | null = null
20
+
21
+ try {
22
+ // Optional pre-install path: a NAPI loader may set `globalThis.__reamNapi`
23
+ // before this module loads. We validate the shape rather than declare a
24
+ // global `var`, so the loader contract stays runtime-only.
25
+ const preinstalled = readPreinstalledNapi()
26
+ if (preinstalled) napi = preinstalled
27
+ } catch {
28
+ /* binary not available */
29
+ }
30
+
31
+ /** @internal Set the NAPI bindings (called once by the NAPI loader). */
32
+ export function setNapi(bindings: NapiCrypto): void {
33
+ napi = bindings
34
+ }
35
+
36
+ /** Check if Rust NAPI crypto is available. */
37
+ export function hasNativeCrypto(): boolean {
38
+ return napi !== null
39
+ }
40
+
41
+ // ─── Exports ────────────────────────────────────────────────
42
+
43
+ export function hmacSign(data: string, secret: string): string {
44
+ if (napi) return napi.hmacSign(data, secret)
45
+ return createHmac('sha256', secret).update(data).digest('base64url')
46
+ }
47
+
48
+ export function hmacVerify(data: string, signature: string, secret: string): boolean {
49
+ if (napi) return napi.hmacVerify(data, signature, secret)
50
+ const expected = createHmac('sha256', secret).update(data).digest('base64url')
51
+ const a = Buffer.from(signature)
52
+ const b = Buffer.from(expected)
53
+ if (a.length !== b.length) return false
54
+ return timingSafeEqual(a, b)
55
+ }
56
+
57
+ export function randomBytesBase64(len: number): string {
58
+ if (napi) return napi.randomBytesBase64(len)
59
+ return nodeRandomBytes(len).toString('base64url')
60
+ }
61
+
62
+ export function randomHex(len: number): string {
63
+ if (napi) return napi.randomHex(len)
64
+ return nodeRandomBytes(len).toString('hex')
65
+ }
66
+
67
+ export function constantTimeEq(a: string, b: string): boolean {
68
+ if (napi) return napi.constantTimeEq(a, b)
69
+ const bufA = Buffer.from(a)
70
+ const bufB = Buffer.from(b)
71
+ if (bufA.length !== bufB.length) return false
72
+ return timingSafeEqual(bufA, bufB)
73
+ }
74
+
75
+ function readPreinstalledNapi(): NapiCrypto | null {
76
+ // `globalThis` is typed without an index signature, so we go through Reflect
77
+ // and validate the shape downstream — no global `var` declaration needed.
78
+ const candidate: unknown = Reflect.get(globalThis, '__reamNapi')
79
+ return isNapiCrypto(candidate) ? candidate : null
80
+ }
81
+
82
+ function isNapiCrypto(value: unknown): value is NapiCrypto {
83
+ if (typeof value !== 'object' || value === null) return false
84
+ return (
85
+ hasFn(value, 'hmacSign') &&
86
+ hasFn(value, 'hmacVerify') &&
87
+ hasFn(value, 'randomBytesBase64') &&
88
+ hasFn(value, 'randomHex') &&
89
+ hasFn(value, 'constantTimeEq')
90
+ )
91
+ }
92
+
93
+ function hasFn<K extends string>(
94
+ value: object,
95
+ key: K,
96
+ ): value is Record<K, (...args: unknown[]) => unknown> {
97
+ return key in value && typeof Reflect.get(value, key) === 'function'
98
+ }
@@ -0,0 +1,121 @@
1
+ import type { HttpKernelRequest, HttpKernelResponse } from '../HttpKernel.js'
2
+ import { loadNapi } from '../helpers/napi-loader.js'
3
+
4
+ /**
5
+ * Wire-level shield configuration handed off to the Rust filter at boot.
6
+ * Each flag toggles one rule on/off; they all default to true on the Rust
7
+ * side, so omitting `configureShield()` entirely leaves the server with no
8
+ * filter installed.
9
+ */
10
+ export interface RustShieldConfig {
11
+ pathTraversal: boolean
12
+ paramPollution: boolean
13
+ }
14
+
15
+ export interface RustRateLimitConfig {
16
+ max: number
17
+ windowSecs: number
18
+ }
19
+
20
+ export interface HyperServerLike {
21
+ onRequest(callback: (request: HttpKernelRequest) => Promise<HttpKernelResponse>): void
22
+ configureShield(config: RustShieldConfig): void
23
+ configureTrustedProxies(cidrs: string[]): void
24
+ configureRateLimit(config: RustRateLimitConfig | null): void
25
+ listen(): Promise<void>
26
+ port(): Promise<number>
27
+ close(): Promise<void>
28
+ /**
29
+ * Reserve a streaming-response slot. The handler must call this and
30
+ * pass the returned id back inside `HttpKernelResponse.streamId`
31
+ * BEFORE returning, so the hyper-side response builder can feed the
32
+ * body from the matching registry entry.
33
+ */
34
+ registerStream(streamId: string): Promise<boolean>
35
+ /**
36
+ * Push a UTF-8 chunk onto a registered stream. Returns `false` once
37
+ * the client has disconnected — callers stop pushing.
38
+ */
39
+ writeStream(streamId: string, chunk: string): Promise<boolean>
40
+ /**
41
+ * End a stream from the server side. Idempotent.
42
+ */
43
+ closeStream(streamId: string): Promise<boolean>
44
+ /**
45
+ * Install a one-shot callback fired the moment the matching stream
46
+ * receiver is dropped — i.e. the client disconnected OR
47
+ * `closeStream` was called. Used by the JS SDK to drop bookkeeping
48
+ * for subscriptions and SSE viewers.
49
+ */
50
+ onStreamDisconnect(streamId: string, callback: () => void): void
51
+ }
52
+
53
+ interface NativeModule {
54
+ HyperServer: new (port: number) => HyperServerLike
55
+ }
56
+
57
+ let native: NativeModule | undefined
58
+
59
+ function loadNative(): NativeModule {
60
+ if (native) return native
61
+ native = loadNapi<NativeModule>({
62
+ binaryName: 'index',
63
+ callerMetaUrl: import.meta.url,
64
+ errorCodePrefix: 'HYPER_SERVER',
65
+ })
66
+ return native
67
+ }
68
+
69
+ /** HyperServer — Rust-powered HTTP server. */
70
+ export class HyperServer implements HyperServerLike {
71
+ #inner: HyperServerLike
72
+
73
+ constructor(port: number) {
74
+ const mod = loadNative()
75
+ this.#inner = new mod.HyperServer(port)
76
+ }
77
+
78
+ onRequest(callback: (request: HttpKernelRequest) => Promise<HttpKernelResponse>): void {
79
+ this.#inner.onRequest(callback)
80
+ }
81
+
82
+ configureShield(config: RustShieldConfig): void {
83
+ this.#inner.configureShield(config)
84
+ }
85
+
86
+ configureTrustedProxies(cidrs: string[]): void {
87
+ this.#inner.configureTrustedProxies(cidrs)
88
+ }
89
+
90
+ configureRateLimit(config: RustRateLimitConfig | null): void {
91
+ this.#inner.configureRateLimit(config)
92
+ }
93
+
94
+ listen(): Promise<void> {
95
+ return this.#inner.listen()
96
+ }
97
+
98
+ port(): Promise<number> {
99
+ return this.#inner.port()
100
+ }
101
+
102
+ close(): Promise<void> {
103
+ return this.#inner.close()
104
+ }
105
+
106
+ registerStream(streamId: string): Promise<boolean> {
107
+ return this.#inner.registerStream(streamId)
108
+ }
109
+
110
+ writeStream(streamId: string, chunk: string): Promise<boolean> {
111
+ return this.#inner.writeStream(streamId, chunk)
112
+ }
113
+
114
+ closeStream(streamId: string): Promise<boolean> {
115
+ return this.#inner.closeStream(streamId)
116
+ }
117
+
118
+ onStreamDisconnect(streamId: string, callback: () => void): void {
119
+ this.#inner.onStreamDisconnect(streamId, callback)
120
+ }
121
+ }