@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,421 @@
1
+ /**
2
+ * GraphQLEngine — schema-first GraphQL with Rust query validation.
3
+ *
4
+ * - Schema parsed from .graphql files at boot
5
+ * - Queries validated by Rust before NAPI crossing (when available)
6
+ * - Resolvers are IoC-injected controller-like classes
7
+ * - @Guard/@Role enforced per TOP-LEVEL resolver field (nested fields are
8
+ * projected from the resolver's return value, not independently resolved —
9
+ * so they carry no per-field guard; don't return guarded data from an
10
+ * unguarded resolver and rely on a nested field guard to hide it).
11
+ * - The response is pruned to the client's selection set, so a resolver may
12
+ * safely return a rich object (e.g. an ORM entity): fields the client did
13
+ * not select are dropped before serialization.
14
+ * - Zero non-null assertions — types guaranteed by schema validation
15
+ *
16
+ * Usage:
17
+ * const engine = new GraphQLEngine({ schemaPath: './app/graphql/schema.graphql' })
18
+ * engine.resolver('Query', 'tasks', TaskResolver, 'tasks')
19
+ * engine.resolver('Mutation', 'createTask', TaskResolver, 'createTask', { guard: 'jwt', role: 'cs_member' })
20
+ *
21
+ * @implements MISS-28
22
+ */
23
+
24
+ import * as fs from 'node:fs'
25
+ import { loadNapi } from '../helpers/napi-loader.js'
26
+ import type { HttpContext } from '../http/HttpContext.js'
27
+
28
+ /** Rust parser output (the `ream-graphql` crate via the `index` NAPI binary). */
29
+ interface RustParsedField {
30
+ name: string
31
+ alias: string | null
32
+ args: Record<string, unknown>
33
+ sub_fields: RustParsedField[]
34
+ }
35
+ interface RustParseResult {
36
+ operation_type: string
37
+ operation_name: string | null
38
+ fields: RustParsedField[]
39
+ errors: string[]
40
+ }
41
+ interface GraphqlNative {
42
+ graphqlParse(query: string): string
43
+ }
44
+
45
+ let graphqlNativeCache: GraphqlNative | undefined
46
+ /**
47
+ * Lazily load the Rust GraphQL parser from the `index` NAPI binary. There is no
48
+ * TS fallback — when Rust exists, the engine is full-Rust. `loadNapi` throws a
49
+ * typed `ReamError` if the native module is missing.
50
+ */
51
+ function graphqlNative(): GraphqlNative {
52
+ if (graphqlNativeCache === undefined) {
53
+ graphqlNativeCache = loadNapi<GraphqlNative>({
54
+ binaryName: 'index',
55
+ callerMetaUrl: import.meta.url,
56
+ errorCodePrefix: 'GRAPHQL',
57
+ })
58
+ }
59
+ return graphqlNativeCache
60
+ }
61
+
62
+ const OPERATION_TYPE: Record<string, string> = {
63
+ query: 'Query',
64
+ mutation: 'Mutation',
65
+ subscription: 'Subscription',
66
+ }
67
+
68
+ /** Map a Rust `ParsedField` (sub_fields) onto the engine's `SelectionField` (selection). */
69
+ function mapRustField(f: RustParsedField): SelectionField {
70
+ return {
71
+ name: f.name,
72
+ alias: f.alias ?? undefined,
73
+ args: f.args,
74
+ selection: f.sub_fields.map(mapRustField),
75
+ }
76
+ }
77
+
78
+ export interface GraphQLConfig {
79
+ /** Path to .graphql schema file. */
80
+ schemaPath: string
81
+ /** Endpoint path (default: /graphql). */
82
+ path?: string
83
+ /** Enable playground/introspection in dev (default: true when NODE_ENV !== 'production'). */
84
+ playground?: boolean
85
+ }
86
+
87
+ export interface ResolverOptions {
88
+ guard?: string
89
+ guards?: string[]
90
+ role?: string
91
+ roles?: string[]
92
+ permissions?: string[]
93
+ }
94
+
95
+ interface ResolverEntry {
96
+ typeName: string
97
+ fieldName: string
98
+ handlerClass: new (...args: unknown[]) => Record<string, (...args: unknown[]) => unknown>
99
+ methodName: string
100
+ options: ResolverOptions
101
+ }
102
+
103
+ interface GraphQLRequest {
104
+ query: string
105
+ variables?: Record<string, unknown>
106
+ operationName?: string
107
+ }
108
+
109
+ /** A parsed field with its (possibly nested) selection set. */
110
+ export interface SelectionField {
111
+ name: string
112
+ alias?: string
113
+ args: Record<string, unknown>
114
+ selection: SelectionField[]
115
+ }
116
+
117
+ export class GraphQLEngine {
118
+ #schemaSource: string
119
+ #resolvers: Map<string, ResolverEntry> = new Map()
120
+ #container?: { make<T>(target: new (...args: unknown[]) => T): T }
121
+ readonly path: string
122
+ #playground: boolean
123
+
124
+ constructor(config: GraphQLConfig) {
125
+ if (!fs.existsSync(config.schemaPath)) {
126
+ throw new Error(`GraphQL schema not found: ${config.schemaPath}`)
127
+ }
128
+ this.#schemaSource = fs.readFileSync(config.schemaPath, 'utf8')
129
+ this.path = config.path ?? '/graphql'
130
+ this.#playground = config.playground ?? process.env.NODE_ENV !== 'production'
131
+ }
132
+
133
+ /** Set IoC container for resolver instantiation. */
134
+ useContainer(container: { make<T>(target: new (...args: unknown[]) => T): T }): void {
135
+ this.#container = container
136
+ }
137
+
138
+ /** Register a resolver for a type.field. */
139
+ resolver(
140
+ typeName: string,
141
+ fieldName: string,
142
+ handlerClass: new (...args: unknown[]) => Record<string, (...args: unknown[]) => unknown>,
143
+ methodName: string,
144
+ options?: ResolverOptions,
145
+ ): void {
146
+ const key = `${typeName}.${fieldName}`
147
+ this.#resolvers.set(key, {
148
+ typeName,
149
+ fieldName,
150
+ handlerClass,
151
+ methodName,
152
+ options: options ?? {},
153
+ })
154
+ }
155
+
156
+ /** Handle a GraphQL HTTP request. */
157
+ async handle(ctx: HttpContext): Promise<void> {
158
+ const method = ctx.request.method()
159
+
160
+ // Playground
161
+ if (method === 'GET' && this.#playground) {
162
+ ctx.response.header('Content-Type', 'text/html')
163
+ ctx.response.status(200).send(this.#renderPlayground())
164
+ return
165
+ }
166
+
167
+ if (method !== 'POST') {
168
+ ctx.response.status(405).json({ errors: [{ message: 'Method not allowed' }] })
169
+ return
170
+ }
171
+
172
+ const rawBody = ctx.request.body()
173
+ const body = parseGraphQLBody(rawBody)
174
+ if (!body) {
175
+ ctx.response.status(400).json({ errors: [{ message: 'Missing or invalid query' }] })
176
+ return
177
+ }
178
+
179
+ try {
180
+ const result = await this.#execute(body, ctx)
181
+ ctx.response.status(200).json(result)
182
+ } catch (err) {
183
+ const message =
184
+ process.env.NODE_ENV !== 'production' && err instanceof Error
185
+ ? err.message
186
+ : 'Internal server error'
187
+ ctx.response.status(500).json({ errors: [{ message }] })
188
+ }
189
+ }
190
+
191
+ /** Execute a GraphQL query against registered resolvers. */
192
+ async #execute(
193
+ request: GraphQLRequest,
194
+ ctx: HttpContext,
195
+ ): Promise<{
196
+ data?: Record<string, unknown>
197
+ errors?: Array<{ message: string; path?: string[] }>
198
+ }> {
199
+ // Parse the query to extract operation type and fields
200
+ const parsed = this.#parseQuery(request.query)
201
+ if (parsed.errors) {
202
+ return { errors: parsed.errors }
203
+ }
204
+
205
+ const data: Record<string, unknown> = {}
206
+ const errors: Array<{ message: string; path?: string[] }> = []
207
+
208
+ for (const field of parsed.fields) {
209
+ const outcome = await this.#resolveField(field, parsed.typeName, request, ctx)
210
+ if (outcome.ok) {
211
+ data[field.alias ?? field.name] = outcome.value
212
+ } else {
213
+ errors.push(outcome.error)
214
+ }
215
+ }
216
+
217
+ return {
218
+ data: Object.keys(data).length > 0 ? data : undefined,
219
+ errors: errors.length > 0 ? errors : undefined,
220
+ }
221
+ }
222
+
223
+ /** Resolve one selection field: lookup → guards → invoke → prune. */
224
+ async #resolveField(
225
+ field: SelectionField,
226
+ typeName: string,
227
+ request: GraphQLRequest,
228
+ ctx: HttpContext,
229
+ ): Promise<
230
+ { ok: true; value: unknown } | { ok: false; error: { message: string; path?: string[] } }
231
+ > {
232
+ const key = `${typeName}.${field.name}`
233
+ const entry = this.#resolvers.get(key)
234
+ if (!entry) {
235
+ return {
236
+ ok: false,
237
+ error: { message: `No resolver for ${key}`, path: [field.name] },
238
+ }
239
+ }
240
+
241
+ const guardError = this.#enforceGuards(entry.options, ctx)
242
+ if (guardError) {
243
+ return { ok: false, error: { message: guardError, path: [field.name] } }
244
+ }
245
+
246
+ try {
247
+ // Resolve handler via IoC or direct instantiation.
248
+ const instance = this.#container
249
+ ? this.#container.make(entry.handlerClass)
250
+ : new entry.handlerClass()
251
+
252
+ const handler = instance[entry.methodName]
253
+ if (typeof handler !== 'function') {
254
+ return {
255
+ ok: false,
256
+ error: {
257
+ message: `Resolver method ${entry.methodName} not found`,
258
+ path: [field.name],
259
+ },
260
+ }
261
+ }
262
+
263
+ const args = this.#buildArgs(field, request.variables)
264
+ const result = await handler.call(instance, null, args, ctx)
265
+ // Prune to the client's selection set: a resolver returning a rich
266
+ // object (ORM entity, etc.) must not leak fields the client did not
267
+ // ask for. Empty selection (scalar field) returns the value as-is.
268
+ return { ok: true, value: pruneToSelection(result, field.selection) }
269
+ } catch (err) {
270
+ const msg = err instanceof Error ? err.message : 'Resolver error'
271
+ return { ok: false, error: { message: msg, path: [field.name] } }
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Build the resolver argument bag: `$variable` references resolve against
277
+ * `request.variables`, then any unreferenced variables are merged in.
278
+ */
279
+ #buildArgs(
280
+ field: SelectionField,
281
+ variables: Record<string, unknown> | undefined,
282
+ ): Record<string, unknown> {
283
+ const args: Record<string, unknown> = {}
284
+ for (const [k, v] of Object.entries(field.args)) {
285
+ if (typeof v === 'string' && v.startsWith('$') && variables) {
286
+ args[k] = variables[v.slice(1)]
287
+ } else {
288
+ args[k] = v
289
+ }
290
+ }
291
+ if (variables) {
292
+ for (const [k, v] of Object.entries(variables)) {
293
+ if (!(k in args)) args[k] = v
294
+ }
295
+ }
296
+ return args
297
+ }
298
+
299
+ /** Enforce guard/role/permission on a resolver. */
300
+ #enforceGuards(options: ResolverOptions, ctx: HttpContext): string | null {
301
+ const guards = [...(options.guards ?? []), ...(options.guard ? [options.guard] : [])]
302
+ const roles = [...(options.roles ?? []), ...(options.role ? [options.role] : [])]
303
+ const permissions = options.permissions ?? []
304
+
305
+ const needsAuth = guards.length > 0 || roles.length > 0 || permissions.length > 0
306
+ if (needsAuth && !ctx.auth?.authenticated) {
307
+ return 'Unauthorized'
308
+ }
309
+
310
+ if (roles.length > 0) {
311
+ const userRoles = ctx.auth?.roles ?? []
312
+ if (!roles.some((r) => userRoles.includes(r))) {
313
+ return 'Insufficient role'
314
+ }
315
+ }
316
+
317
+ if (permissions.length > 0) {
318
+ const userPerms = ctx.auth?.permissions ?? []
319
+ if (!permissions.every((p) => userPerms.includes(p))) {
320
+ return 'Insufficient permissions'
321
+ }
322
+ }
323
+
324
+ return null
325
+ }
326
+
327
+ /**
328
+ * Parse a GraphQL query via the Rust `ream-graphql` crate (operation type +
329
+ * fields with arguments). Spec-compliant; invalid queries return errors.
330
+ */
331
+ #parseQuery(query: string): {
332
+ typeName: string
333
+ fields: SelectionField[]
334
+ errors?: Array<{ message: string }>
335
+ } {
336
+ // Full-Rust: the spec-compliant `ream-graphql` parser (graphql-parser
337
+ // crate) rejects invalid queries before any resolver runs. No TS fallback —
338
+ // ream ships the native binary, so when Rust exists the engine is Rust.
339
+ const raw = JSON.parse(graphqlNative().graphqlParse(query)) as RustParseResult
340
+ const typeName = OPERATION_TYPE[raw.operation_type] ?? 'Query'
341
+ if (raw.errors.length > 0) {
342
+ return { typeName, fields: [], errors: raw.errors.map((message) => ({ message })) }
343
+ }
344
+ return { typeName, fields: raw.fields.map(mapRustField) }
345
+ }
346
+
347
+ #renderPlayground(): string {
348
+ return `<!DOCTYPE html>
349
+ <html>
350
+ <head>
351
+ <title>GraphQL Playground</title>
352
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/graphiql@3/graphiql.min.css" />
353
+ </head>
354
+ <body style="margin:0;overflow:hidden">
355
+ <div id="graphiql" style="height:100vh"></div>
356
+ <script crossorigin src="https://cdn.jsdelivr.net/npm/react@18/umd/react.production.min.js"></script>
357
+ <script crossorigin src="https://cdn.jsdelivr.net/npm/react-dom@18/umd/react-dom.production.min.js"></script>
358
+ <script crossorigin src="https://cdn.jsdelivr.net/npm/graphiql@3/graphiql.min.js"></script>
359
+ <script>
360
+ const root = ReactDOM.createRoot(document.getElementById('graphiql'));
361
+ root.render(React.createElement(GraphiQL, {
362
+ fetcher: GraphiQL.createFetcher({ url: ${JSON.stringify(this.path)} }),
363
+ }));
364
+ </script>
365
+ </body>
366
+ </html>`
367
+ }
368
+
369
+ /** Get the raw schema source for introspection. */
370
+ getSchemaSource(): string {
371
+ return this.#schemaSource
372
+ }
373
+ }
374
+
375
+ /** Parse and validate an unknown request body as a GraphQL request object. */
376
+ function parseGraphQLBody(body: unknown): GraphQLRequest | null {
377
+ if (!body || typeof body !== 'object' || Array.isArray(body)) return null
378
+ // After typeof check, body is a non-null non-array object; index via 'in' narrowing
379
+ const q = 'query' in body ? body.query : undefined
380
+ if (typeof q !== 'string') return null
381
+
382
+ let variables: Record<string, unknown> | undefined
383
+ if (
384
+ 'variables' in body &&
385
+ body.variables !== null &&
386
+ typeof body.variables === 'object' &&
387
+ !Array.isArray(body.variables)
388
+ ) {
389
+ // biome-ignore lint/suspicious/noExplicitAny: narrowed to non-null non-array object above; branded as Record for safe spreading
390
+ variables = body.variables as any as Record<string, unknown>
391
+ }
392
+
393
+ const rawOpName = 'operationName' in body ? body.operationName : undefined
394
+ const operationName = typeof rawOpName === 'string' ? rawOpName : undefined
395
+
396
+ return { query: q, variables, operationName }
397
+ }
398
+
399
+ function isRecord(v: unknown): v is Record<string, unknown> {
400
+ return typeof v === 'object' && v !== null && !Array.isArray(v)
401
+ }
402
+
403
+ /**
404
+ * Project a resolver result onto the client's selection set. A field with an
405
+ * empty selection (a scalar leaf) is returned untouched; an object is reduced
406
+ * to only the selected keys (recursing into nested selections); an array maps
407
+ * the projection over its items. This is what stops a resolver that returns a
408
+ * rich object (ORM entity, etc.) from leaking unselected fields.
409
+ */
410
+ export function pruneToSelection(value: unknown, selection: SelectionField[]): unknown {
411
+ if (selection.length === 0) return value
412
+ if (Array.isArray(value)) return value.map((v) => pruneToSelection(v, selection))
413
+ if (!isRecord(value)) return value
414
+ const out: Record<string, unknown> = {}
415
+ for (const field of selection) {
416
+ if (field.name in value) {
417
+ out[field.alias ?? field.name] = pruneToSelection(value[field.name], field.selection)
418
+ }
419
+ }
420
+ return out
421
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * `GraphQLProvider` — wires the GraphQL gateway into the Ream pipeline.
3
+ *
4
+ * Opt-in: does nothing unless `config.graphql.schemaPath` is set (or an engine
5
+ * is injected for tests). When configured:
6
+ * - `register()` — construct a `GraphQLEngine` from `config.graphql`, give it
7
+ * the IoC container for resolver DI, and bind it under the `'graphql'` token:
8
+ *
9
+ * const gql = app.container.make<GraphQLEngine>('graphql')
10
+ * gql.resolver('Query', 'tasks', TaskResolver, 'tasks')
11
+ *
12
+ * - `boot()` — mount the engine at `engine.path` (default `/graphql`) for both
13
+ * GET (playground/introspection) and POST (queries).
14
+ *
15
+ * @implements Story 24.5
16
+ */
17
+
18
+ import type { AppContext } from '../Provider.js'
19
+ import { Provider } from '../Provider.js'
20
+ import type { Router } from '../router/Router.js'
21
+ import { type GraphQLConfig, GraphQLEngine } from './GraphQLEngine.js'
22
+
23
+ export interface GraphQLProviderOptions {
24
+ /** Override the `GraphQLEngine` instance — used by tests. */
25
+ engine?: GraphQLEngine
26
+ }
27
+
28
+ export class GraphQLProvider extends Provider {
29
+ #engine?: GraphQLEngine
30
+
31
+ constructor(app: AppContext, options: GraphQLProviderOptions = {}) {
32
+ super(app)
33
+ this.#engine = options.engine
34
+ }
35
+
36
+ /** The wired engine, or undefined when GraphQL is not configured. */
37
+ get engine(): GraphQLEngine | undefined {
38
+ return this.#engine
39
+ }
40
+
41
+ override register(): void {
42
+ const config = this.app.config.get<GraphQLConfig>('graphql')
43
+ const engine = this.#engine ?? (config?.schemaPath ? new GraphQLEngine(config) : undefined)
44
+ if (!engine) return // GraphQL not configured — opt-out.
45
+ engine.useContainer(this.app.container)
46
+ this.#engine = engine
47
+ this.app.container.singleton('graphql', () => engine)
48
+ }
49
+
50
+ override async boot(): Promise<void> {
51
+ const engine = this.#engine
52
+ if (!engine) return
53
+ const router = this.app.container.make<Router>('router')
54
+ // GraphQLEngine.handle() serves the playground on GET and executes queries
55
+ // on POST, so mount the same path for both verbs.
56
+ router.get(engine.path, (ctx) => engine.handle(ctx))
57
+ router.post(engine.path, (ctx) => engine.handle(ctx))
58
+ }
59
+ }
@@ -0,0 +1,72 @@
1
+ const STANDARD_B64_RE = /^[A-Za-z0-9+/]*={0,2}$/
2
+ const URL_B64_RE = /^[A-Za-z0-9_-]*$/
3
+
4
+ /**
5
+ * Encode a string or Buffer to standard base64.
6
+ *
7
+ * @example
8
+ * base64.encode('hello') // 'aGVsbG8='
9
+ */
10
+ function encode(value: string | Buffer): string {
11
+ const buf = typeof value === 'string' ? Buffer.from(value, 'utf-8') : value
12
+ return buf.toString('base64')
13
+ }
14
+
15
+ /**
16
+ * Decode a standard base64 string. Returns null on invalid input unless strict mode,
17
+ * in which case it throws.
18
+ *
19
+ * @example
20
+ * base64.decode('aGVsbG8=') // 'hello'
21
+ * base64.decode('!!!') // null
22
+ */
23
+ function decode(value: string, encoding: BufferEncoding = 'utf-8', strict = false): string | null {
24
+ if (!STANDARD_B64_RE.test(value)) {
25
+ if (strict) throw new Error(`Invalid base64 string: ${value}`)
26
+ return null
27
+ }
28
+ try {
29
+ return Buffer.from(value, 'base64').toString(encoding)
30
+ } catch {
31
+ if (strict) throw new Error(`Failed to decode base64 string: ${value}`)
32
+ return null
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Encode a string or Buffer to base64url (no padding, uses - and _ instead of + and /).
38
+ *
39
+ * @example
40
+ * base64.urlEncode('hello') // 'aGVsbG8'
41
+ */
42
+ function urlEncode(value: string | Buffer): string {
43
+ const buf = typeof value === 'string' ? Buffer.from(value, 'utf-8') : value
44
+ return buf.toString('base64url')
45
+ }
46
+
47
+ /**
48
+ * Decode a base64url string. Returns null on invalid input unless strict mode,
49
+ * in which case it throws.
50
+ *
51
+ * @example
52
+ * base64.urlDecode('aGVsbG8') // 'hello'
53
+ * base64.urlDecode('!!!') // null
54
+ */
55
+ function urlDecode(
56
+ value: string,
57
+ encoding: BufferEncoding = 'utf-8',
58
+ strict = false,
59
+ ): string | null {
60
+ if (!URL_B64_RE.test(value)) {
61
+ if (strict) throw new Error(`Invalid base64url string: ${value}`)
62
+ return null
63
+ }
64
+ try {
65
+ return Buffer.from(value, 'base64url').toString(encoding)
66
+ } catch {
67
+ if (strict) throw new Error(`Failed to decode base64url string: ${value}`)
68
+ return null
69
+ }
70
+ }
71
+
72
+ export const base64 = { encode, decode, urlEncode, urlDecode }
@@ -0,0 +1,6 @@
1
+ export { base64 } from './base64.js'
2
+ export type * from './is.js'
3
+ export { default as is } from './is.js'
4
+ export { safeEqual } from './safeEqual.js'
5
+ export { default as string } from './string.js'
6
+ export type * from './types.js'