@openstax/ts-utils 1.33.1 → 1.34.0

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 (504) hide show
  1. package/.cfnlintrc +2 -0
  2. package/.github/CODEOWNERS +1 -0
  3. package/.github/workflows/ci.yml +36 -0
  4. package/.github/workflows/lint.yml +55 -0
  5. package/.nvmrc +1 -0
  6. package/.syncignore +4 -0
  7. package/.syncpackrc +18 -0
  8. package/CONTRIBUTING.md +96 -0
  9. package/LICENSE +661 -0
  10. package/Procfile +1 -0
  11. package/README.md +62 -90
  12. package/app.json +23 -0
  13. package/cspell.json +32 -0
  14. package/deploy/constants.env +21 -0
  15. package/deploy/deploy.bash +157 -0
  16. package/deploy/deployment-alt-region.cfn.yml +70 -0
  17. package/deploy/deployment.cfn.yml +650 -0
  18. package/deploy/destroy-deployment.bash +23 -0
  19. package/deploy/shared.cfn.yml +94 -0
  20. package/docs/lambda-build.md +35 -0
  21. package/package.json +12 -228
  22. package/packages/frontend/README.md +46 -0
  23. package/packages/frontend/package.json +101 -0
  24. package/packages/frontend/public/favicon.ico +0 -0
  25. package/packages/frontend/public/index.html +107 -0
  26. package/packages/frontend/public/maintenance.html +59 -0
  27. package/packages/frontend/public/manifest.json +15 -0
  28. package/packages/frontend/public/robots.txt +3 -0
  29. package/packages/frontend/script/make-certificate.bash +49 -0
  30. package/packages/frontend/script/server/cli.js +11 -0
  31. package/packages/frontend/script/server/index.js +47 -0
  32. package/packages/frontend/script/start.bash +22 -0
  33. package/packages/frontend/script/trust-localhost.bash +7 -0
  34. package/packages/frontend/src/auth/authProvider.ts +10 -0
  35. package/packages/frontend/src/auth/useAuth.ts +33 -0
  36. package/packages/frontend/src/components/Pagination.tsx +26 -0
  37. package/packages/frontend/src/configProvider/index.ts +53 -0
  38. package/packages/frontend/src/configProvider/use.ts +41 -0
  39. package/packages/frontend/src/core/context/services.spec.tsx +39 -0
  40. package/packages/frontend/src/core/context/services.tsx +16 -0
  41. package/packages/frontend/src/core/index.spec.ts +7 -0
  42. package/packages/frontend/src/core/index.ts +20 -0
  43. package/packages/frontend/src/core/services.tsx +14 -0
  44. package/packages/frontend/src/core/types.ts +3 -0
  45. package/packages/frontend/src/example/api.ts +28 -0
  46. package/packages/frontend/src/example/components/Layout.tsx +23 -0
  47. package/packages/frontend/src/example/screens/Home.spec.tsx +68 -0
  48. package/packages/frontend/src/example/screens/Home.tsx +78 -0
  49. package/packages/frontend/src/example/screens/ThingList.spec.tsx +60 -0
  50. package/packages/frontend/src/example/screens/ThingList.tsx +75 -0
  51. package/packages/frontend/src/example/screens/ThingView.spec.tsx +71 -0
  52. package/packages/frontend/src/example/screens/ThingView.tsx +47 -0
  53. package/packages/frontend/src/example/screens/index.ts +9 -0
  54. package/packages/frontend/src/index.css +159 -0
  55. package/packages/frontend/src/index.tsx +67 -0
  56. package/packages/frontend/src/react-app-env.d.ts +1 -0
  57. package/packages/frontend/src/routing/components/RouteLink.spec.tsx +55 -0
  58. package/packages/frontend/src/routing/components/RouteLink.tsx +35 -0
  59. package/packages/frontend/src/routing/middleware.ts +6 -0
  60. package/packages/frontend/src/routing/useQuery.ts +14 -0
  61. package/packages/frontend/src/setupProxy.js +19 -0
  62. package/packages/frontend/src/setupTests.ts +9 -0
  63. package/packages/frontend/src/tests/testServices.tsx +23 -0
  64. package/packages/frontend/tsconfig.json +27 -0
  65. package/packages/lambda/.eslintrc.js +64 -0
  66. package/packages/lambda/jest-global-setup.js +3 -0
  67. package/packages/lambda/jest-setup-after-env.js +1 -0
  68. package/packages/lambda/jest.config.js +31 -0
  69. package/packages/lambda/jest.resolver.js +17 -0
  70. package/packages/lambda/package.json +68 -0
  71. package/packages/lambda/script/build.bash +19 -0
  72. package/packages/lambda/script/bundle-functions.bash +10 -0
  73. package/packages/lambda/script/lambdaLocalProxy.js +16 -0
  74. package/packages/lambda/script/lambdaLocalProxy.spec.ts +147 -0
  75. package/packages/lambda/script/utils/getRouteData.ts +7 -0
  76. package/packages/lambda/script/utils/routeDataLoader.js +8 -0
  77. package/packages/lambda/script/utils/routeDataLoader.spec.ts +8 -0
  78. package/packages/lambda/src/functions/serviceApi/core/index.ts +7 -0
  79. package/packages/lambda/src/functions/serviceApi/core/request.spec.ts +38 -0
  80. package/packages/lambda/src/functions/serviceApi/core/request.ts +42 -0
  81. package/packages/lambda/src/functions/serviceApi/core/routes.spec.ts +7 -0
  82. package/packages/lambda/src/functions/serviceApi/core/routes.ts +10 -0
  83. package/packages/lambda/src/functions/serviceApi/core/services.ts +9 -0
  84. package/packages/lambda/src/functions/serviceApi/core/types.ts +13 -0
  85. package/packages/lambda/src/functions/serviceApi/entry/lambda/https-xray.ts +4 -0
  86. package/packages/lambda/src/functions/serviceApi/entry/lambda/index.spec.ts +48 -0
  87. package/packages/lambda/src/functions/serviceApi/entry/lambda/index.ts +58 -0
  88. package/packages/lambda/src/functions/serviceApi/entry/lambda/services.ts +36 -0
  89. package/packages/lambda/src/functions/serviceApi/entry/local.ts +71 -0
  90. package/packages/lambda/src/functions/serviceApi/versions/v0/example/documentSearchMiddleware.spec.ts +16 -0
  91. package/packages/lambda/src/functions/serviceApi/versions/v0/example/documentSearchMiddleware.ts +41 -0
  92. package/packages/lambda/src/functions/serviceApi/versions/v0/example/documentStoreMiddleware.spec.ts +78 -0
  93. package/packages/lambda/src/functions/serviceApi/versions/v0/example/documentStoreMiddleware.ts +70 -0
  94. package/packages/lambda/src/functions/serviceApi/versions/v0/example/routes.spec.ts +306 -0
  95. package/packages/lambda/src/functions/serviceApi/versions/v0/example/routes.ts +176 -0
  96. package/packages/lambda/src/functions/serviceApi/versions/v0/index.spec.ts +263 -0
  97. package/packages/lambda/src/functions/serviceApi/versions/v0/index.ts +134 -0
  98. package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/authMiddleware.spec.ts +23 -0
  99. package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/authMiddleware.ts +32 -0
  100. package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/configMiddleware.spec.ts +10 -0
  101. package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/configMiddleware.ts +7 -0
  102. package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/frontendFileServerMiddleware.spec.ts +13 -0
  103. package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/frontendFileServerMiddleware.ts +23 -0
  104. package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/paginationMiddleware.spec.ts +9 -0
  105. package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/paginationMiddleware.ts +9 -0
  106. package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/searchMiddleware.spec.ts +12 -0
  107. package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/searchMiddleware.ts +21 -0
  108. package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/userRoleValidatorMiddleware.spec.ts +21 -0
  109. package/packages/lambda/src/functions/serviceApi/versions/v0/middleware/userRoleValidatorMiddleware.ts +18 -0
  110. package/packages/lambda/tsconfig.json +30 -0
  111. package/packages/lambda/webpack.config.js +97 -0
  112. package/packages/utils/.eslintrc.js +64 -0
  113. package/packages/utils/README.md +118 -0
  114. package/packages/utils/jest-global-setup.js +3 -0
  115. package/packages/utils/jest.config.js +25 -0
  116. package/packages/utils/jest.resolver.js +17 -0
  117. package/packages/utils/package.json +238 -0
  118. package/packages/utils/src/assertions/index.spec.ts +126 -0
  119. package/{dist/esm/assertions/index.js → packages/utils/src/assertions/index.ts} +64 -49
  120. package/packages/utils/src/aws/ssmService.ts +7 -0
  121. package/packages/utils/src/config/awsParameterConfig.ts +24 -0
  122. package/packages/utils/src/config/envConfig.ts +58 -0
  123. package/packages/utils/src/config/index.spec.ts +165 -0
  124. package/{dist/esm/config/index.d.ts → packages/utils/src/config/index.ts} +29 -13
  125. package/packages/utils/src/config/lambdaParameterConfig.ts +49 -0
  126. package/{dist/esm/config/replaceConfig.js → packages/utils/src/config/replaceConfig.ts} +16 -6
  127. package/packages/utils/src/config/resolveConfigValue.ts +10 -0
  128. package/packages/utils/src/errors/index.spec.ts +35 -0
  129. package/{dist/esm/errors/index.js → packages/utils/src/errors/index.ts} +57 -41
  130. package/packages/utils/src/fetch/fetchStatusRetry.spec.ts +197 -0
  131. package/packages/utils/src/fetch/fetchStatusRetry.ts +33 -0
  132. package/packages/utils/src/fetch/index.spec.ts +34 -0
  133. package/packages/utils/src/fetch/index.ts +87 -0
  134. package/packages/utils/src/guards/index.spec.ts +58 -0
  135. package/{dist/esm/guards/index.d.ts → packages/utils/src/guards/index.ts} +10 -7
  136. package/packages/utils/src/index.spec.ts +471 -0
  137. package/packages/utils/src/middleware/apiErrorHandler.spec.ts +65 -0
  138. package/packages/utils/src/middleware/apiErrorHandler.ts +67 -0
  139. package/packages/utils/src/middleware/apiSlowResponseMiddleware.spec.ts +184 -0
  140. package/packages/utils/src/middleware/apiSlowResponseMiddleware.ts +71 -0
  141. package/packages/utils/src/middleware/index.spec.ts +99 -0
  142. package/{dist/cjs/middleware/index.d.ts → packages/utils/src/middleware/index.ts} +53 -5
  143. package/packages/utils/src/middleware/lambdaCorsResponseMiddleware.spec.ts +103 -0
  144. package/packages/utils/src/middleware/lambdaCorsResponseMiddleware.ts +52 -0
  145. package/packages/utils/src/middleware/throwNotFoundMiddleware.spec.ts +20 -0
  146. package/packages/utils/src/middleware/throwNotFoundMiddleware.ts +11 -0
  147. package/packages/utils/src/misc/hashValue.ts +18 -0
  148. package/packages/utils/src/misc/helpers.ts +259 -0
  149. package/packages/utils/src/misc/merge.ts +48 -0
  150. package/{dist/esm/misc/partitionSequence.js → packages/utils/src/misc/partitionSequence.ts} +23 -15
  151. package/packages/utils/src/pagination/index.spec.ts +150 -0
  152. package/packages/utils/src/pagination/index.ts +117 -0
  153. package/{dist/esm/routing/helpers.js → packages/utils/src/routing/helpers.ts} +42 -30
  154. package/packages/utils/src/routing/index.spec.ts +553 -0
  155. package/packages/utils/src/routing/index.ts +424 -0
  156. package/packages/utils/src/routing/validators/zod.spec.ts +16 -0
  157. package/packages/utils/src/routing/validators/zod.ts +14 -0
  158. package/packages/utils/src/services/accountsGateway/README.md +3 -0
  159. package/packages/utils/src/services/accountsGateway/index.spec.ts +518 -0
  160. package/packages/utils/src/services/accountsGateway/index.ts +251 -0
  161. package/packages/utils/src/services/apiGateway/README.md +93 -0
  162. package/packages/utils/src/services/apiGateway/index.spec.ts +254 -0
  163. package/packages/utils/src/services/apiGateway/index.ts +189 -0
  164. package/packages/utils/src/services/authProvider/README.md +21 -0
  165. package/packages/utils/src/services/authProvider/browser.spec.ts +391 -0
  166. package/packages/utils/src/services/authProvider/browser.ts +209 -0
  167. package/packages/utils/src/services/authProvider/decryption.spec.ts +337 -0
  168. package/packages/utils/src/services/authProvider/decryption.ts +98 -0
  169. package/packages/utils/src/services/authProvider/index.ts +93 -0
  170. package/packages/utils/src/services/authProvider/stub.spec.ts +29 -0
  171. package/packages/utils/src/services/authProvider/subrequest.spec.ts +105 -0
  172. package/packages/utils/src/services/authProvider/subrequest.ts +68 -0
  173. package/packages/utils/src/services/authProvider/utils/decryptAndVerify.spec.ts +128 -0
  174. package/packages/utils/src/services/authProvider/utils/decryptAndVerify.ts +106 -0
  175. package/packages/utils/src/services/authProvider/utils/embeddedAuthProvider.spec.ts +26 -0
  176. package/packages/utils/src/services/authProvider/utils/embeddedAuthProvider.ts +57 -0
  177. package/packages/utils/src/services/authProvider/utils/userRoleValidator.spec.ts +135 -0
  178. package/packages/utils/src/services/authProvider/utils/userRoleValidator.ts +49 -0
  179. package/packages/utils/src/services/authProvider/utils/userSubrequest.spec.ts +26 -0
  180. package/packages/utils/src/services/authProvider/utils/userSubrequest.ts +10 -0
  181. package/packages/utils/src/services/documentStore/dynamoEncoding.ts +57 -0
  182. package/packages/utils/src/services/documentStore/fileSystemAssert.spec.ts +43 -0
  183. package/packages/utils/src/services/documentStore/fileSystemAssert.ts +10 -0
  184. package/{dist/cjs/services/documentStore/index.d.ts → packages/utils/src/services/documentStore/index.ts} +8 -8
  185. package/packages/utils/src/services/documentStore/unversioned/README.md +13 -0
  186. package/packages/utils/src/services/documentStore/unversioned/dynamodb.spec.ts +859 -0
  187. package/packages/utils/src/services/documentStore/unversioned/dynamodb.ts +243 -0
  188. package/packages/utils/src/services/documentStore/unversioned/file-system.spec.ts +629 -0
  189. package/packages/utils/src/services/documentStore/unversioned/file-system.ts +194 -0
  190. package/{dist/cjs/services/documentStore/unversioned/index.d.ts → packages/utils/src/services/documentStore/unversioned/index.ts} +2 -0
  191. package/packages/utils/src/services/documentStore/versioned/README.md +13 -0
  192. package/packages/utils/src/services/documentStore/versioned/dynamodb.spec.ts +376 -0
  193. package/packages/utils/src/services/documentStore/versioned/dynamodb.ts +167 -0
  194. package/packages/utils/src/services/documentStore/versioned/file-system.spec.ts +262 -0
  195. package/packages/utils/src/services/documentStore/versioned/file-system.ts +90 -0
  196. package/packages/utils/src/services/documentStore/versioned/index.ts +25 -0
  197. package/packages/utils/src/services/exercisesGateway/README.md +5 -0
  198. package/packages/utils/src/services/exercisesGateway/index.spec.ts +326 -0
  199. package/packages/utils/src/services/exercisesGateway/index.ts +163 -0
  200. package/packages/utils/src/services/fileServer/index.spec.ts +88 -0
  201. package/packages/utils/src/services/fileServer/index.ts +43 -0
  202. package/packages/utils/src/services/fileServer/localFileServer.spec.ts +182 -0
  203. package/packages/utils/src/services/fileServer/localFileServer.ts +159 -0
  204. package/packages/utils/src/services/fileServer/s3FileServer.spec.ts +266 -0
  205. package/packages/utils/src/services/fileServer/s3FileServer.ts +155 -0
  206. package/packages/utils/src/services/launchParams/index.spec.ts +366 -0
  207. package/packages/utils/src/services/launchParams/signer.ts +73 -0
  208. package/packages/utils/src/services/launchParams/verifier.ts +120 -0
  209. package/packages/utils/src/services/logger/console.spec.ts +29 -0
  210. package/{dist/esm/services/logger/console.js → packages/utils/src/services/logger/console.ts} +5 -2
  211. package/packages/utils/src/services/logger/index.spec.ts +65 -0
  212. package/{dist/esm/services/logger/index.d.ts → packages/utils/src/services/logger/index.ts} +23 -9
  213. package/packages/utils/src/services/lrsGateway/README.md +5 -0
  214. package/packages/utils/src/services/lrsGateway/addStatementDefaultFields.ts +22 -0
  215. package/packages/utils/src/services/lrsGateway/attempt-utils.spec.ts +847 -0
  216. package/packages/utils/src/services/lrsGateway/attempt-utils.ts +358 -0
  217. package/packages/utils/src/services/lrsGateway/file-system.spec.ts +363 -0
  218. package/packages/utils/src/services/lrsGateway/file-system.ts +165 -0
  219. package/packages/utils/src/services/lrsGateway/index.spec.ts +194 -0
  220. package/packages/utils/src/services/lrsGateway/index.ts +257 -0
  221. package/packages/utils/src/services/lrsGateway/xapiUtils.spec.ts +887 -0
  222. package/packages/utils/src/services/lrsGateway/xapiUtils.ts +262 -0
  223. package/packages/utils/src/services/postgresConnection/index.spec.ts +170 -0
  224. package/packages/utils/src/services/postgresConnection/index.ts +84 -0
  225. package/packages/utils/src/services/searchProvider/README.md +3 -0
  226. package/packages/utils/src/services/searchProvider/index.ts +59 -0
  227. package/packages/utils/src/services/searchProvider/memorySearchTheBadWay.spec.ts +526 -0
  228. package/packages/utils/src/services/searchProvider/memorySearchTheBadWay.ts +223 -0
  229. package/packages/utils/src/services/searchProvider/openSearch.spec.ts +926 -0
  230. package/packages/utils/src/services/searchProvider/openSearch.ts +195 -0
  231. package/{dist/esm/types.d.ts → packages/utils/src/types.ts} +34 -6
  232. package/packages/utils/tsconfig.json +31 -0
  233. package/packages/utils/tsconfig.without-specs.cjs.json +7 -0
  234. package/packages/utils/tsconfig.without-specs.esm.json +7 -0
  235. package/packages/utils/tsconfig.without-specs.json +6 -0
  236. package/scripts/build.bash +24 -0
  237. package/scripts/ci.bash +10 -0
  238. package/scripts/start.bash +29 -0
  239. package/dist/cjs/assertions/index.d.ts +0 -89
  240. package/dist/cjs/assertions/index.js +0 -157
  241. package/dist/cjs/aws/ssmService.d.ts +0 -5
  242. package/dist/cjs/aws/ssmService.js +0 -9
  243. package/dist/cjs/config/awsParameterConfig.d.ts +0 -10
  244. package/dist/cjs/config/awsParameterConfig.js +0 -26
  245. package/dist/cjs/config/envConfig.d.ts +0 -24
  246. package/dist/cjs/config/envConfig.js +0 -57
  247. package/dist/cjs/config/index.d.ts +0 -48
  248. package/dist/cjs/config/index.js +0 -35
  249. package/dist/cjs/config/lambdaParameterConfig.d.ts +0 -12
  250. package/dist/cjs/config/lambdaParameterConfig.js +0 -45
  251. package/dist/cjs/config/replaceConfig.d.ts +0 -14
  252. package/dist/cjs/config/replaceConfig.js +0 -22
  253. package/dist/cjs/config/resolveConfigValue.d.ts +0 -5
  254. package/dist/cjs/config/resolveConfigValue.js +0 -12
  255. package/dist/cjs/errors/index.d.ts +0 -88
  256. package/dist/cjs/errors/index.js +0 -123
  257. package/dist/cjs/fetch/fetchStatusRetry.d.ts +0 -8
  258. package/dist/cjs/fetch/fetchStatusRetry.js +0 -27
  259. package/dist/cjs/fetch/index.d.ts +0 -64
  260. package/dist/cjs/fetch/index.js +0 -55
  261. package/dist/cjs/guards/index.d.ts +0 -38
  262. package/dist/cjs/guards/index.js +0 -44
  263. package/dist/cjs/index.js +0 -20
  264. package/dist/cjs/middleware/apiErrorHandler.d.ts +0 -24
  265. package/dist/cjs/middleware/apiErrorHandler.js +0 -42
  266. package/dist/cjs/middleware/apiSlowResponseMiddleware.d.ts +0 -23
  267. package/dist/cjs/middleware/apiSlowResponseMiddleware.js +0 -54
  268. package/dist/cjs/middleware/index.js +0 -48
  269. package/dist/cjs/middleware/lambdaCorsResponseMiddleware.d.ts +0 -20
  270. package/dist/cjs/middleware/lambdaCorsResponseMiddleware.js +0 -44
  271. package/dist/cjs/middleware/throwNotFoundMiddleware.d.ts +0 -4
  272. package/dist/cjs/middleware/throwNotFoundMiddleware.js +0 -14
  273. package/dist/cjs/misc/hashValue.d.ts +0 -10
  274. package/dist/cjs/misc/hashValue.js +0 -17
  275. package/dist/cjs/misc/helpers.d.ts +0 -124
  276. package/dist/cjs/misc/helpers.js +0 -214
  277. package/dist/cjs/misc/merge.d.ts +0 -21
  278. package/dist/cjs/misc/merge.js +0 -45
  279. package/dist/cjs/misc/partitionSequence.d.ts +0 -35
  280. package/dist/cjs/misc/partitionSequence.js +0 -55
  281. package/dist/cjs/pagination/index.d.ts +0 -91
  282. package/dist/cjs/pagination/index.js +0 -83
  283. package/dist/cjs/routing/helpers.d.ts +0 -57
  284. package/dist/cjs/routing/helpers.js +0 -90
  285. package/dist/cjs/routing/index.d.ts +0 -290
  286. package/dist/cjs/routing/index.js +0 -295
  287. package/dist/cjs/routing/validators/zod.d.ts +0 -4
  288. package/dist/cjs/routing/validators/zod.js +0 -14
  289. package/dist/cjs/services/accountsGateway/index.d.ts +0 -92
  290. package/dist/cjs/services/accountsGateway/index.js +0 -138
  291. package/dist/cjs/services/apiGateway/index.d.ts +0 -68
  292. package/dist/cjs/services/apiGateway/index.js +0 -118
  293. package/dist/cjs/services/authProvider/browser.d.ts +0 -40
  294. package/dist/cjs/services/authProvider/browser.js +0 -155
  295. package/dist/cjs/services/authProvider/decryption.d.ts +0 -19
  296. package/dist/cjs/services/authProvider/decryption.js +0 -73
  297. package/dist/cjs/services/authProvider/index.d.ts +0 -63
  298. package/dist/cjs/services/authProvider/index.js +0 -34
  299. package/dist/cjs/services/authProvider/subrequest.d.ts +0 -13
  300. package/dist/cjs/services/authProvider/subrequest.js +0 -49
  301. package/dist/cjs/services/authProvider/utils/decryptAndVerify.d.ts +0 -28
  302. package/dist/cjs/services/authProvider/utils/decryptAndVerify.js +0 -91
  303. package/dist/cjs/services/authProvider/utils/embeddedAuthProvider.d.ts +0 -26
  304. package/dist/cjs/services/authProvider/utils/embeddedAuthProvider.js +0 -47
  305. package/dist/cjs/services/authProvider/utils/userRoleValidator.d.ts +0 -13
  306. package/dist/cjs/services/authProvider/utils/userRoleValidator.js +0 -37
  307. package/dist/cjs/services/authProvider/utils/userSubrequest.d.ts +0 -3
  308. package/dist/cjs/services/authProvider/utils/userSubrequest.js +0 -13
  309. package/dist/cjs/services/documentStore/dynamoEncoding.d.ts +0 -10
  310. package/dist/cjs/services/documentStore/dynamoEncoding.js +0 -52
  311. package/dist/cjs/services/documentStore/fileSystemAssert.d.ts +0 -1
  312. package/dist/cjs/services/documentStore/fileSystemAssert.js +0 -14
  313. package/dist/cjs/services/documentStore/index.js +0 -2
  314. package/dist/cjs/services/documentStore/unversioned/dynamodb.d.ts +0 -31
  315. package/dist/cjs/services/documentStore/unversioned/dynamodb.js +0 -233
  316. package/dist/cjs/services/documentStore/unversioned/file-system.d.ts +0 -32
  317. package/dist/cjs/services/documentStore/unversioned/file-system.js +0 -214
  318. package/dist/cjs/services/documentStore/unversioned/index.js +0 -2
  319. package/dist/cjs/services/documentStore/versioned/dynamodb.d.ts +0 -25
  320. package/dist/cjs/services/documentStore/versioned/dynamodb.js +0 -143
  321. package/dist/cjs/services/documentStore/versioned/file-system.d.ts +0 -25
  322. package/dist/cjs/services/documentStore/versioned/file-system.js +0 -73
  323. package/dist/cjs/services/documentStore/versioned/index.d.ts +0 -17
  324. package/dist/cjs/services/documentStore/versioned/index.js +0 -2
  325. package/dist/cjs/services/exercisesGateway/index.d.ts +0 -67
  326. package/dist/cjs/services/exercisesGateway/index.js +0 -107
  327. package/dist/cjs/services/fileServer/index.d.ts +0 -30
  328. package/dist/cjs/services/fileServer/index.js +0 -19
  329. package/dist/cjs/services/fileServer/localFileServer.d.ts +0 -13
  330. package/dist/cjs/services/fileServer/localFileServer.js +0 -132
  331. package/dist/cjs/services/fileServer/s3FileServer.d.ts +0 -14
  332. package/dist/cjs/services/fileServer/s3FileServer.js +0 -132
  333. package/dist/cjs/services/launchParams/index.js +0 -7
  334. package/dist/cjs/services/launchParams/signer.d.ts +0 -23
  335. package/dist/cjs/services/launchParams/signer.js +0 -58
  336. package/dist/cjs/services/launchParams/verifier.d.ts +0 -21
  337. package/dist/cjs/services/launchParams/verifier.js +0 -129
  338. package/dist/cjs/services/logger/console.d.ts +0 -4
  339. package/dist/cjs/services/logger/console.js +0 -12
  340. package/dist/cjs/services/logger/index.d.ts +0 -39
  341. package/dist/cjs/services/logger/index.js +0 -31
  342. package/dist/cjs/services/lrsGateway/addStatementDefaultFields.d.ts +0 -5
  343. package/dist/cjs/services/lrsGateway/addStatementDefaultFields.js +0 -21
  344. package/dist/cjs/services/lrsGateway/attempt-utils.d.ts +0 -70
  345. package/dist/cjs/services/lrsGateway/attempt-utils.js +0 -258
  346. package/dist/cjs/services/lrsGateway/file-system.d.ts +0 -15
  347. package/dist/cjs/services/lrsGateway/file-system.js +0 -150
  348. package/dist/cjs/services/lrsGateway/index.d.ts +0 -122
  349. package/dist/cjs/services/lrsGateway/index.js +0 -148
  350. package/dist/cjs/services/lrsGateway/xapiUtils.d.ts +0 -68
  351. package/dist/cjs/services/lrsGateway/xapiUtils.js +0 -109
  352. package/dist/cjs/services/postgresConnection/index.d.ts +0 -28
  353. package/dist/cjs/services/postgresConnection/index.js +0 -65
  354. package/dist/cjs/services/searchProvider/index.d.ts +0 -67
  355. package/dist/cjs/services/searchProvider/index.js +0 -2
  356. package/dist/cjs/services/searchProvider/memorySearchTheBadWay.d.ts +0 -20
  357. package/dist/cjs/services/searchProvider/memorySearchTheBadWay.js +0 -191
  358. package/dist/cjs/services/searchProvider/openSearch.d.ts +0 -28
  359. package/dist/cjs/services/searchProvider/openSearch.js +0 -154
  360. package/dist/cjs/tsconfig.without-specs.cjs.tsbuildinfo +0 -1
  361. package/dist/cjs/types.d.ts +0 -31
  362. package/dist/cjs/types.js +0 -2
  363. package/dist/esm/assertions/index.d.ts +0 -89
  364. package/dist/esm/aws/ssmService.d.ts +0 -5
  365. package/dist/esm/aws/ssmService.js +0 -6
  366. package/dist/esm/config/awsParameterConfig.d.ts +0 -10
  367. package/dist/esm/config/awsParameterConfig.js +0 -22
  368. package/dist/esm/config/envConfig.d.ts +0 -24
  369. package/dist/esm/config/envConfig.js +0 -53
  370. package/dist/esm/config/index.js +0 -17
  371. package/dist/esm/config/lambdaParameterConfig.d.ts +0 -12
  372. package/dist/esm/config/lambdaParameterConfig.js +0 -38
  373. package/dist/esm/config/replaceConfig.d.ts +0 -14
  374. package/dist/esm/config/resolveConfigValue.d.ts +0 -5
  375. package/dist/esm/config/resolveConfigValue.js +0 -8
  376. package/dist/esm/errors/index.d.ts +0 -88
  377. package/dist/esm/fetch/fetchStatusRetry.d.ts +0 -8
  378. package/dist/esm/fetch/fetchStatusRetry.js +0 -23
  379. package/dist/esm/fetch/index.d.ts +0 -64
  380. package/dist/esm/fetch/index.js +0 -46
  381. package/dist/esm/guards/index.js +0 -36
  382. package/dist/esm/index.d.ts +0 -4
  383. package/dist/esm/index.js +0 -4
  384. package/dist/esm/middleware/apiErrorHandler.d.ts +0 -24
  385. package/dist/esm/middleware/apiErrorHandler.js +0 -38
  386. package/dist/esm/middleware/apiSlowResponseMiddleware.d.ts +0 -23
  387. package/dist/esm/middleware/apiSlowResponseMiddleware.js +0 -50
  388. package/dist/esm/middleware/index.d.ts +0 -47
  389. package/dist/esm/middleware/index.js +0 -44
  390. package/dist/esm/middleware/lambdaCorsResponseMiddleware.d.ts +0 -20
  391. package/dist/esm/middleware/lambdaCorsResponseMiddleware.js +0 -40
  392. package/dist/esm/middleware/throwNotFoundMiddleware.d.ts +0 -4
  393. package/dist/esm/middleware/throwNotFoundMiddleware.js +0 -10
  394. package/dist/esm/misc/hashValue.d.ts +0 -10
  395. package/dist/esm/misc/hashValue.js +0 -13
  396. package/dist/esm/misc/helpers.d.ts +0 -124
  397. package/dist/esm/misc/helpers.js +0 -199
  398. package/dist/esm/misc/merge.d.ts +0 -21
  399. package/dist/esm/misc/merge.js +0 -40
  400. package/dist/esm/misc/partitionSequence.d.ts +0 -35
  401. package/dist/esm/pagination/index.d.ts +0 -91
  402. package/dist/esm/pagination/index.js +0 -77
  403. package/dist/esm/routing/helpers.d.ts +0 -57
  404. package/dist/esm/routing/index.d.ts +0 -290
  405. package/dist/esm/routing/index.js +0 -246
  406. package/dist/esm/routing/validators/zod.d.ts +0 -4
  407. package/dist/esm/routing/validators/zod.js +0 -10
  408. package/dist/esm/services/accountsGateway/index.d.ts +0 -92
  409. package/dist/esm/services/accountsGateway/index.js +0 -131
  410. package/dist/esm/services/apiGateway/index.d.ts +0 -68
  411. package/dist/esm/services/apiGateway/index.js +0 -77
  412. package/dist/esm/services/authProvider/browser.d.ts +0 -40
  413. package/dist/esm/services/authProvider/browser.js +0 -151
  414. package/dist/esm/services/authProvider/decryption.d.ts +0 -19
  415. package/dist/esm/services/authProvider/decryption.js +0 -69
  416. package/dist/esm/services/authProvider/index.d.ts +0 -63
  417. package/dist/esm/services/authProvider/index.js +0 -26
  418. package/dist/esm/services/authProvider/subrequest.d.ts +0 -13
  419. package/dist/esm/services/authProvider/subrequest.js +0 -45
  420. package/dist/esm/services/authProvider/utils/decryptAndVerify.d.ts +0 -28
  421. package/dist/esm/services/authProvider/utils/decryptAndVerify.js +0 -85
  422. package/dist/esm/services/authProvider/utils/embeddedAuthProvider.d.ts +0 -26
  423. package/dist/esm/services/authProvider/utils/embeddedAuthProvider.js +0 -40
  424. package/dist/esm/services/authProvider/utils/userRoleValidator.d.ts +0 -13
  425. package/dist/esm/services/authProvider/utils/userRoleValidator.js +0 -33
  426. package/dist/esm/services/authProvider/utils/userSubrequest.d.ts +0 -3
  427. package/dist/esm/services/authProvider/utils/userSubrequest.js +0 -6
  428. package/dist/esm/services/documentStore/dynamoEncoding.d.ts +0 -10
  429. package/dist/esm/services/documentStore/dynamoEncoding.js +0 -45
  430. package/dist/esm/services/documentStore/fileSystemAssert.d.ts +0 -1
  431. package/dist/esm/services/documentStore/fileSystemAssert.js +0 -10
  432. package/dist/esm/services/documentStore/index.d.ts +0 -14
  433. package/dist/esm/services/documentStore/index.js +0 -1
  434. package/dist/esm/services/documentStore/unversioned/dynamodb.d.ts +0 -31
  435. package/dist/esm/services/documentStore/unversioned/dynamodb.js +0 -226
  436. package/dist/esm/services/documentStore/unversioned/file-system.d.ts +0 -32
  437. package/dist/esm/services/documentStore/unversioned/file-system.js +0 -174
  438. package/dist/esm/services/documentStore/unversioned/index.d.ts +0 -2
  439. package/dist/esm/services/documentStore/unversioned/index.js +0 -1
  440. package/dist/esm/services/documentStore/versioned/dynamodb.d.ts +0 -25
  441. package/dist/esm/services/documentStore/versioned/dynamodb.js +0 -139
  442. package/dist/esm/services/documentStore/versioned/file-system.d.ts +0 -25
  443. package/dist/esm/services/documentStore/versioned/file-system.js +0 -69
  444. package/dist/esm/services/documentStore/versioned/index.d.ts +0 -17
  445. package/dist/esm/services/documentStore/versioned/index.js +0 -1
  446. package/dist/esm/services/exercisesGateway/index.d.ts +0 -67
  447. package/dist/esm/services/exercisesGateway/index.js +0 -70
  448. package/dist/esm/services/fileServer/index.d.ts +0 -30
  449. package/dist/esm/services/fileServer/index.js +0 -13
  450. package/dist/esm/services/fileServer/localFileServer.d.ts +0 -13
  451. package/dist/esm/services/fileServer/localFileServer.js +0 -125
  452. package/dist/esm/services/fileServer/s3FileServer.d.ts +0 -14
  453. package/dist/esm/services/fileServer/s3FileServer.js +0 -125
  454. package/dist/esm/services/launchParams/index.d.ts +0 -2
  455. package/dist/esm/services/launchParams/index.js +0 -2
  456. package/dist/esm/services/launchParams/signer.d.ts +0 -23
  457. package/dist/esm/services/launchParams/signer.js +0 -51
  458. package/dist/esm/services/launchParams/verifier.d.ts +0 -21
  459. package/dist/esm/services/launchParams/verifier.js +0 -92
  460. package/dist/esm/services/logger/console.d.ts +0 -4
  461. package/dist/esm/services/logger/index.js +0 -27
  462. package/dist/esm/services/lrsGateway/addStatementDefaultFields.d.ts +0 -5
  463. package/dist/esm/services/lrsGateway/addStatementDefaultFields.js +0 -14
  464. package/dist/esm/services/lrsGateway/attempt-utils.d.ts +0 -70
  465. package/dist/esm/services/lrsGateway/attempt-utils.js +0 -236
  466. package/dist/esm/services/lrsGateway/file-system.d.ts +0 -15
  467. package/dist/esm/services/lrsGateway/file-system.js +0 -110
  468. package/dist/esm/services/lrsGateway/index.d.ts +0 -122
  469. package/dist/esm/services/lrsGateway/index.js +0 -111
  470. package/dist/esm/services/lrsGateway/xapiUtils.d.ts +0 -68
  471. package/dist/esm/services/lrsGateway/xapiUtils.js +0 -99
  472. package/dist/esm/services/postgresConnection/index.d.ts +0 -28
  473. package/dist/esm/services/postgresConnection/index.js +0 -58
  474. package/dist/esm/services/searchProvider/index.d.ts +0 -67
  475. package/dist/esm/services/searchProvider/index.js +0 -1
  476. package/dist/esm/services/searchProvider/memorySearchTheBadWay.d.ts +0 -20
  477. package/dist/esm/services/searchProvider/memorySearchTheBadWay.js +0 -187
  478. package/dist/esm/services/searchProvider/openSearch.d.ts +0 -28
  479. package/dist/esm/services/searchProvider/openSearch.js +0 -150
  480. package/dist/esm/tsconfig.without-specs.esm.tsbuildinfo +0 -1
  481. package/dist/esm/types.js +0 -1
  482. package/script/bin/.init-params-script.bash.swp +0 -0
  483. /package/{script → packages/utils/script}/bin/copy-from-template.bash +0 -0
  484. /package/{script → packages/utils/script}/bin/delete-stack.bash +0 -0
  485. /package/{script → packages/utils/script}/bin/deploy.bash +0 -0
  486. /package/{script → packages/utils/script}/bin/destroy-deployment.bash +0 -0
  487. /package/{script → packages/utils/script}/bin/empty-bucket.bash +0 -0
  488. /package/{script → packages/utils/script}/bin/get-arg.bash +0 -0
  489. /package/{script → packages/utils/script}/bin/get-deployed-environments.bash +0 -0
  490. /package/{script → packages/utils/script}/bin/get-env-param.bash +0 -0
  491. /package/{script → packages/utils/script}/bin/get-kwarg.bash +0 -0
  492. /package/{script → packages/utils/script}/bin/get-stack-param.bash +0 -0
  493. /package/{script → packages/utils/script}/bin/has-flag.bash +0 -0
  494. /package/{script → packages/utils/script}/bin/init-constants-script.bash +0 -0
  495. /package/{script → packages/utils/script}/bin/init-params-script.bash +0 -0
  496. /package/{script → packages/utils/script}/bin/stack-exists.bash +0 -0
  497. /package/{script → packages/utils/script}/bin/update-utils.bash +0 -0
  498. /package/{script → packages/utils/script}/bin/upload-pager-duty-endpoints.bash +0 -0
  499. /package/{script → packages/utils/script}/bin/upload-params.bash +0 -0
  500. /package/{script → packages/utils/script}/bin/which.bash +0 -0
  501. /package/{script → packages/utils/script}/bin-entry.bash +0 -0
  502. /package/{script → packages/utils/script}/build.bash +0 -0
  503. /package/{dist/cjs/index.d.ts → packages/utils/src/index.ts} +0 -0
  504. /package/{dist/cjs/services/launchParams/index.d.ts → packages/utils/src/services/launchParams/index.ts} +0 -0
@@ -0,0 +1,184 @@
1
+ import { NotFoundError } from '../errors';
2
+ import { ApiResponse, apiTextResponse } from '../routing';
3
+ import { createCoreLogger, Level, LogEvent, Logger } from '../services/logger';
4
+ import { createSlowResponseMiddleware } from './apiSlowResponseMiddleware';
5
+
6
+ const insideOutPromise = <T>() => {
7
+ let resolve: (value: T | PromiseLike<T>) => void = () => null;
8
+ let reject: (reason?: any) => void = () => null;
9
+
10
+ const promise = new Promise<T>((res, rej) => {
11
+ resolve = res;
12
+ reject = rej;
13
+ });
14
+
15
+ return {resolve, reject, promise};
16
+ };
17
+
18
+ describe('createSlowResponseMiddleware', () => {
19
+ let logger: Logger;
20
+ let logFn: jest.SpyInstance;
21
+ let timeoutSpy: jest.SpyInstance;
22
+ let clearTimeoutSpy: jest.SpyInstance;
23
+ let nowSpy: jest.SpyInstance;
24
+
25
+ beforeEach(() => {
26
+ logFn = jest.fn();
27
+ logger = createCoreLogger(logFn as any as LogEvent);
28
+ timeoutSpy = jest.spyOn(global, 'setTimeout').mockImplementation(() => 7 as any);
29
+ clearTimeoutSpy = jest.spyOn(global, 'clearTimeout').mockImplementation(() => null);
30
+ nowSpy = jest.spyOn(Date, 'now');
31
+ });
32
+
33
+ afterEach(() => {
34
+ timeoutSpy.mockReset();
35
+ clearTimeoutSpy.mockReset();
36
+ nowSpy.mockReset();
37
+ });
38
+
39
+ it('does nothing when response is undefined', () => {
40
+ expect(createSlowResponseMiddleware({
41
+ logResponseSlowerThan: '1000',
42
+ timeoutResponseAfter: '5000'
43
+ })()(undefined, {logger})).toBeUndefined();
44
+ expect(logFn).not.toHaveBeenCalled();
45
+ expect(timeoutSpy).not.toHaveBeenCalled();
46
+ expect(clearTimeoutSpy).not.toHaveBeenCalled();
47
+ });
48
+
49
+ it('works without a timeout', () => {
50
+ expect(createSlowResponseMiddleware({
51
+ logResponseSlowerThan: '1000',
52
+ timeoutResponseAfter: ''
53
+ })()(undefined, {logger})).toBeUndefined();
54
+ expect(logFn).not.toHaveBeenCalled();
55
+ expect(timeoutSpy).not.toHaveBeenCalled();
56
+ expect(clearTimeoutSpy).not.toHaveBeenCalled();
57
+ });
58
+
59
+ it('returns response with no timeout', async() => {
60
+ const {resolve, promise} = insideOutPromise<ApiResponse<number, string>>();
61
+
62
+ const result = createSlowResponseMiddleware({
63
+ logResponseSlowerThan: '1000',
64
+ timeoutResponseAfter: ''
65
+ })()(promise, {logger});
66
+
67
+ const response = apiTextResponse(200, 'done');
68
+ resolve(response);
69
+
70
+ expect(await result).toBe(response);
71
+ expect(logFn).not.toHaveBeenCalled();
72
+ expect(timeoutSpy).not.toHaveBeenCalled();
73
+ expect(clearTimeoutSpy).not.toHaveBeenCalled();
74
+ });
75
+
76
+ it('logs slow response with no timeout', async() => {
77
+ const {resolve, promise} = insideOutPromise<ApiResponse<number, string>>();
78
+ nowSpy.mockReturnValue(10000);
79
+
80
+ const result = createSlowResponseMiddleware({
81
+ logResponseSlowerThan: '1000',
82
+ timeoutResponseAfter: ''
83
+ })()(promise, {logger});
84
+
85
+ nowSpy.mockReturnValue(12000);
86
+ const response = apiTextResponse(200, 'done');
87
+ resolve(response);
88
+
89
+ expect(await result).toBe(response);
90
+ expect(logFn).toHaveBeenCalledWith(Level.Warn, {context: {}, message: 'slow response', time: 2000});
91
+ expect(timeoutSpy).not.toHaveBeenCalled();
92
+ expect(clearTimeoutSpy).not.toHaveBeenCalled();
93
+ });
94
+
95
+ it('logs slow response with timeout', async() => {
96
+ const {resolve, promise} = insideOutPromise<ApiResponse<number, string>>();
97
+ nowSpy.mockReturnValue(10000);
98
+ timeoutSpy.mockReturnValue(10);
99
+
100
+ const result = createSlowResponseMiddleware({
101
+ logResponseSlowerThan: '1000',
102
+ timeoutResponseAfter: '5000'
103
+ })()(promise, {logger});
104
+
105
+ nowSpy.mockReturnValue(12000);
106
+ const response = apiTextResponse(200, 'done');
107
+ resolve(response);
108
+
109
+ expect(await result).toBe(response);
110
+ expect(logFn).toHaveBeenCalledWith(Level.Warn, {context: {}, message: 'slow response', time: 2000});
111
+ expect(timeoutSpy).toHaveBeenCalledTimes(1);
112
+ expect(timeoutSpy).toHaveBeenCalledWith(expect.anything(), 5000);
113
+ expect(clearTimeoutSpy).toHaveBeenCalledTimes(1);
114
+ expect(clearTimeoutSpy).toHaveBeenCalledWith(10);
115
+ });
116
+
117
+ it('returns timeout', async() => {
118
+ const {promise} = insideOutPromise<ApiResponse<number, string>>();
119
+
120
+ const result = createSlowResponseMiddleware({
121
+ logResponseSlowerThan: '1000',
122
+ timeoutResponseAfter: '5000'
123
+ })()(promise, {logger});
124
+
125
+
126
+ // clear config loading
127
+ await new Promise(setImmediate);
128
+
129
+ expect(timeoutSpy).toHaveBeenCalledTimes(1);
130
+ expect(timeoutSpy).toHaveBeenCalledWith(expect.anything(), 5000);
131
+
132
+ expect(clearTimeoutSpy).not.toHaveBeenCalled();
133
+ timeoutSpy.mock.calls[0][0]();
134
+
135
+ expect(await result).toEqual(apiTextResponse(504, '504 Gateway Timeout'));
136
+ expect(logFn).toHaveBeenCalledWith(Level.Error, {context: {}, message: 'request processing timed out'});
137
+ });
138
+
139
+ it('does not log a timeout when the response promise resolves in time', async() => {
140
+ const {resolve, promise} = insideOutPromise<ApiResponse<number, string>>();
141
+
142
+ const result = createSlowResponseMiddleware({
143
+ logResponseSlowerThan: '1000',
144
+ timeoutResponseAfter: '5000'
145
+ })()(promise, {logger});
146
+
147
+ // clear config loading
148
+ await new Promise(setImmediate);
149
+
150
+ const response = apiTextResponse(200, 'done');
151
+ resolve(response);
152
+
153
+ expect(timeoutSpy).toHaveBeenCalledTimes(1);
154
+ expect(timeoutSpy).toHaveBeenCalledWith(expect.anything(), 5000);
155
+
156
+ expect(await result).toEqual(response);
157
+
158
+ expect(clearTimeoutSpy).toHaveBeenCalledWith(7);
159
+ expect(logFn).not.toHaveBeenCalled();
160
+ });
161
+
162
+ it('does not log a timeout when the response promise rejects in time', async() => {
163
+ const {reject, promise} = insideOutPromise<ApiResponse<number, string>>();
164
+
165
+ const result = createSlowResponseMiddleware({
166
+ logResponseSlowerThan: '1000',
167
+ timeoutResponseAfter: '5000'
168
+ })()(promise, {logger});
169
+
170
+ // clear config loading
171
+ await new Promise(setImmediate);
172
+
173
+ const error = new NotFoundError();
174
+ reject(error);
175
+
176
+ expect(timeoutSpy).toHaveBeenCalledTimes(1);
177
+ expect(timeoutSpy).toHaveBeenCalledWith(expect.anything(), 5000);
178
+
179
+ await expect(result).rejects.toThrow(error);
180
+
181
+ expect(clearTimeoutSpy).toHaveBeenCalledWith(7);
182
+ expect(logFn).not.toHaveBeenCalled();
183
+ });
184
+ });
@@ -0,0 +1,71 @@
1
+ import type { ConfigProviderForConfig } from '../config';
2
+ import { resolveConfigValue } from '../config/resolveConfigValue';
3
+ import { once } from '../misc/helpers';
4
+ import type { ApiResponse } from '../routing';
5
+ import { apiTextResponse } from '../routing';
6
+ import type { Logger } from '../services/logger';
7
+ import { Level } from '../services/logger';
8
+
9
+ type Config = {
10
+ logResponseSlowerThan: string;
11
+ timeoutResponseAfter: string;
12
+ };
13
+
14
+ /**
15
+ * Creates response middleware that logs slow responses and times out responses that take too long. lambda functions have a timeout setting, but when a lambda times out there is no way to log anything helpful before it exists. this middleware allows the logger context to show up for timeout requests. just make sure that the `timeoutResponseAfter` is set to something slightly shorter than the lambda timeout so that it has time to run.
16
+ *
17
+ * @param config
18
+ * @param config.logResponseSlowerThan the config that specifies the threshold for a slow response
19
+ * @param config.timeoutResponseAfter the config that specifies the timeout for a response
20
+ * @example
21
+ * createSlowResponseMiddleware({
22
+ * logResponseSlowerThan: envConfig('LOG_SLOW_RESPONSE', 'runtime', '1000'),
23
+ * timeoutResponseAfter: envConfig('RESPONSE_TIMEOUT', 'runtime', '28000'),
24
+ * });
25
+ */
26
+ export const createSlowResponseMiddleware = (config: ConfigProviderForConfig<Config>) => {
27
+ const getSlowThreshold = once(() => resolveConfigValue(config.logResponseSlowerThan).then(result => parseInt(result, 10)));
28
+ const getTimeoutAfter = once(() => resolveConfigValue(config.timeoutResponseAfter).then(result => parseInt(result, 10)));
29
+
30
+ return () => (
31
+ response: Promise<ApiResponse<number, any>> | undefined, {logger}: {logger: Logger}
32
+ ): Promise<ApiResponse<number, string>> | undefined => {
33
+ const start = Date.now();
34
+
35
+ if (!response) {
36
+ return response;
37
+ }
38
+
39
+ return Promise.all([getSlowThreshold(), getTimeoutAfter()]).then(([slowThreshold, timeoutAfter]) => {
40
+
41
+ let timeout: ReturnType<typeof setTimeout> | undefined = undefined;
42
+
43
+ const timeoutPromise = isNaN(timeoutAfter)
44
+ ? undefined
45
+ : new Promise<ApiResponse<number, string>>(resolve => timeout = setTimeout(() => {
46
+ logger.logEvent(Level.Error, {
47
+ message: 'request processing timed out',
48
+ });
49
+ resolve(apiTextResponse(504, '504 Gateway Timeout'));
50
+ }, timeoutAfter))
51
+ ;
52
+
53
+ const requestPromise = response.finally(() => {
54
+ const time = Date.now() - start;
55
+
56
+ if (timeout !== undefined) {
57
+ clearTimeout(timeout);
58
+ }
59
+
60
+ if (time > slowThreshold) {
61
+ logger.logEvent(Level.Warn, {
62
+ message: 'slow response',
63
+ time,
64
+ });
65
+ }
66
+ });
67
+
68
+ return timeoutPromise ? Promise.race([timeoutPromise, requestPromise]) : requestPromise;
69
+ });
70
+ };
71
+ };
@@ -0,0 +1,99 @@
1
+ import { makeComposeMiddleware } from '.';
2
+
3
+ describe('composeMiddleware', () => {
4
+ it('composes middleware', () => {
5
+ const provider1 = () => <M extends {thing1: string}>(middleware: M) => ({...middleware, thing2: `${middleware.thing1}-copy`});
6
+ const provider2 = () => <M extends {thing2: string}>({thing2, ...middleware}: M) => ({...middleware, thing2: thing2.length, thing3: `${thing2}-copy`});
7
+
8
+ const composeMiddleware = makeComposeMiddleware<{}, {thing1: string; thing7: string}>();
9
+
10
+ const middleware = composeMiddleware(
11
+ provider1,
12
+ provider2
13
+ );
14
+
15
+ const result = middleware({})({thing1: 'first', thing7: 'seven'});
16
+
17
+ // just trying to make TS complain if these are the wrong type or result is never
18
+ result.thing1.length;
19
+ result.thing2.toFixed;
20
+ result.thing3.length;
21
+ result.thing7.length;
22
+
23
+ expect(result).toEqual({
24
+ thing1: 'first',
25
+ thing2: 10,
26
+ thing3: 'first-copy-copy',
27
+ thing7: 'seven',
28
+ });
29
+ });
30
+
31
+ it('composes middleware arguments', () => {
32
+ const provider1 = () => <M extends {thing1: string}>(middleware: M, argument: string) => ({...middleware, thing2: `${middleware.thing1}-${argument}`});
33
+ const provider2 = () => <M extends {thing2: string}>(middleware: M) => ({...middleware, thing3: `${middleware.thing2}-copy`});
34
+
35
+ const composeMiddleware = makeComposeMiddleware<{}, {thing1: string; thing7: string}>();
36
+
37
+ const middleware = composeMiddleware(
38
+ provider1,
39
+ provider2
40
+ );
41
+
42
+ const result = middleware({})({thing1: 'first', thing7: 'seven'}, 'extra value');
43
+
44
+ // just trying to make TS complain if these are the wrong type or result is never
45
+ result.thing1.length;
46
+ result.thing2.length;
47
+ result.thing3.length;
48
+ result.thing7.length;
49
+
50
+
51
+ expect(result).toEqual({
52
+ thing1: 'first',
53
+ thing2: 'first-extra value',
54
+ thing3: 'first-extra value-copy',
55
+ thing7: 'seven',
56
+ });
57
+ });
58
+
59
+ it('transforms optional data', () => {
60
+ const provider1 = () => (middleware: {thing: string} | undefined) => middleware || {thing: 'default'};
61
+ const provider2 = () => (middleware: {thing: string}) => middleware;
62
+
63
+ const composeMiddleware = makeComposeMiddleware<{}, {thing: string} | undefined>();
64
+
65
+ const middleware = composeMiddleware(
66
+ provider1,
67
+ provider2,
68
+ );
69
+
70
+ // just trying to make TS complain if these are the wrong type or result is never
71
+ middleware({})(undefined).thing.length;
72
+ middleware({})({thing: 'first'}).thing.length;
73
+
74
+ expect(middleware({})(undefined).thing).toBe('default');
75
+ expect(middleware({})({thing: 'first'}).thing).toBe('first');
76
+ });
77
+
78
+ it('transforms non-hash data', () => {
79
+ const default0 = () => (middleware: number | undefined) => middleware || 0;
80
+ const add2 = () => (middleware: number) => middleware + 2;
81
+ const doubleIt = () => (middleware: number) => middleware * 2;
82
+
83
+ const composeMiddleware = makeComposeMiddleware<{}, number | undefined>();
84
+
85
+ const middleware = composeMiddleware(
86
+ default0,
87
+ add2,
88
+ doubleIt,
89
+ add2
90
+ );
91
+
92
+ // just trying to make TS complain if these are the wrong type or result is never
93
+ middleware({})(undefined).toFixed;
94
+ middleware({})(2).toFixed;
95
+
96
+ expect(middleware({})(undefined)).toBe(6);
97
+ expect(middleware({})(2)).toBe(10);
98
+ });
99
+ });
@@ -1,11 +1,51 @@
1
1
  import { TupleZip } from '../types';
2
- export type MiddlewareProvider<Sa, M, A extends any[], R> = (app: Sa, appBinder?: ((app: Sa, provider: MiddlewareProvider<Sa, M, A, R>) => (middleware: M, ...args: A) => R)) => (middleware: M, ...args: A) => R;
2
+
3
+ // this is a more standard flow provider that takes input and produces an unrelated output
4
+ export type MiddlewareProvider<Sa, M, A extends any[], R> = (
5
+ app: Sa,
6
+ appBinder?: ((app: Sa, provider: MiddlewareProvider<Sa, M, A, R>) => (middleware: M, ...args: A) => R)
7
+ ) => (middleware: M, ...args: A) => R;
8
+
9
+ // this detects generics that forward the input to the output while modifying or adding properties
3
10
  export type MiddlewareTransformProvider<Sa, M, A extends any[], R> = (app: Sa) => (middleware: M, ...args: A) => Omit<M, keyof R> & R;
11
+
4
12
  export type MiddlewareInput<S> = S extends MiddlewareProvider<any, infer M, any, any> ? M : never;
5
- export type ServiceMiddlewareProviderResult<M, S> = [M] extends [never] ? never : [M] extends [MiddlewareInput<S>] ? S extends MiddlewareTransformProvider<any, M, any, infer R> ? (Omit<R, keyof M> & M) extends R ? Omit<R, keyof M> & M : R extends M ? R : Omit<M, keyof R> & R : S extends MiddlewareProvider<any, M, any, infer R> ? R : never : never;
13
+
14
+ export type ServiceMiddlewareProviderResult<M, S> = [M] extends [never]
15
+ ? never
16
+ : [M] extends [MiddlewareInput<S>]
17
+ ? S extends MiddlewareTransformProvider<any, M, any, infer R>
18
+ ? (Omit<R, keyof M> & M) extends R
19
+ ? Omit<R, keyof M> & M // if R includes any keys from M, the M keys are more specific, use M
20
+ : R extends M
21
+ ? R // R is a more specific version of M, use R
22
+ : Omit<M, keyof R> & R // R overwrites some type from M, use R
23
+ : S extends MiddlewareProvider<any, M, any, infer R>
24
+ ? R
25
+ : never
26
+ : never;
27
+
6
28
  export type ServiceMiddlewareProviderArgs<S> = S extends MiddlewareProvider<any, any, infer A, any> ? A : never;
7
- export type ServiceMiddlewareProviderChainResult<C, M> = C extends [infer S1, ...infer S] ? S extends never[] ? ServiceMiddlewareProviderResult<M, S1> : ServiceMiddlewareProviderChainResult<S, ServiceMiddlewareProviderResult<M, S1>> : C extends unknown ? M : never;
8
- export type ServiceMiddlewareProviderChainArgs<C> = C extends [infer S1, ...infer S] ? S extends never[] ? ServiceMiddlewareProviderArgs<S1> : TupleZip<ServiceMiddlewareProviderChainArgs<S>, ServiceMiddlewareProviderArgs<S1>> : C extends unknown ? [] : never;
29
+
30
+ export type ServiceMiddlewareProviderChainResult<C, M> = C extends [infer S1, ...infer S]
31
+ ? S extends never[]
32
+ ? ServiceMiddlewareProviderResult<M, S1>
33
+ : ServiceMiddlewareProviderChainResult<S,
34
+ ServiceMiddlewareProviderResult<M, S1>
35
+ >
36
+ : C extends unknown
37
+ ? M
38
+ : never
39
+ ;
40
+ export type ServiceMiddlewareProviderChainArgs<C> = C extends [infer S1, ...infer S]
41
+ ? S extends never[]
42
+ ? ServiceMiddlewareProviderArgs<S1>
43
+ : TupleZip<ServiceMiddlewareProviderChainArgs<S>, ServiceMiddlewareProviderArgs<S1>>
44
+ : C extends unknown
45
+ ? []
46
+ : never
47
+ ;
48
+
9
49
  /**
10
50
  * Creates a middleware composer for given AppServices and input value types. The composer accepts a list of middleware
11
51
  * that it assembles into a chain. The function returned by the composer takes a value of the given input value type,
@@ -44,4 +84,12 @@ export type ServiceMiddlewareProviderChainArgs<C> = C extends [infer S1, ...infe
44
84
  * eg: const myThing: myType = makeComposeMiddleware()(...);
45
85
  * ```
46
86
  */
47
- export declare const makeComposeMiddleware: <Sa, M>() => <C extends any[]>(...chain: C) => MiddlewareProvider<Sa, M, ServiceMiddlewareProviderChainArgs<C>, ServiceMiddlewareProviderChainResult<C, M>>;
87
+ export const makeComposeMiddleware = <Sa, M>() => <C extends any[]>(
88
+ ...chain: C
89
+ ): MiddlewareProvider<Sa, M, ServiceMiddlewareProviderChainArgs<C>, ServiceMiddlewareProviderChainResult<C, M>> => (app, appBinder) => {
90
+ const boundChain = chain.map(provider => appBinder ? appBinder(app, provider) : provider(app));
91
+
92
+ return (middleware: M, ...args) => {
93
+ return boundChain.reduce((result, provider) => provider(result, ...args), middleware);
94
+ };
95
+ };
@@ -0,0 +1,103 @@
1
+ import { APIGatewayProxyEventV2 } from 'aws-lambda';
2
+ import { apiJsonResponse } from '../routing';
3
+ import { createLambdaCorsResponseMiddleware } from './lambdaCorsResponseMiddleware';
4
+
5
+ describe('createLambdaCorsResponseMiddleware', () => {
6
+ it('adds cors headers for openstax subdomains', async() => {
7
+ const request = {
8
+ cookies: [],
9
+ headers: {
10
+ origin: 'https://neato.openstax.org'
11
+ },
12
+ requestContext: {
13
+ http: {
14
+ method: 'GET'
15
+ }
16
+ }
17
+ } as unknown as APIGatewayProxyEventV2;
18
+
19
+ const response = await createLambdaCorsResponseMiddleware({corsAllowedHostRegex: '(openstax.org|herokuapp.com)$'})()(
20
+ Promise.resolve(apiJsonResponse(200, {})), {request}
21
+ );
22
+
23
+ expect(response?.headers?.['Access-Control-Allow-Origin']).toBe('https://neato.openstax.org');
24
+ expect(response?.headers?.['Access-Control-Allow-Methods']).toBe('POST, GET, PUT, PATCH, DELETE, OPTIONS');
25
+ });
26
+
27
+ it('adds cors headers for openstax apex', async() => {
28
+ const request = {
29
+ cookies: [],
30
+ headers: {
31
+ origin: 'https://openstax.org'
32
+ },
33
+ requestContext: {
34
+ http: {
35
+ method: 'GET'
36
+ }
37
+ }
38
+ } as unknown as APIGatewayProxyEventV2;
39
+
40
+ const response = await createLambdaCorsResponseMiddleware({corsAllowedHostRegex: '(openstax.org|herokuapp.com)$'})()(
41
+ Promise.resolve(apiJsonResponse(200, {})), {request}
42
+ );
43
+
44
+ expect(response?.headers?.['Access-Control-Allow-Origin']).toBe('https://openstax.org');
45
+ expect(response?.headers?.['Access-Control-Allow-Methods']).toBe('POST, GET, PUT, PATCH, DELETE, OPTIONS');
46
+ });
47
+
48
+ it('omits headers without origin', async() => {
49
+ const request = {
50
+ cookies: [],
51
+ headers: {
52
+ },
53
+ requestContext: {
54
+ http: {
55
+ method: 'GET'
56
+ }
57
+ }
58
+ } as unknown as APIGatewayProxyEventV2;
59
+
60
+ const response = await createLambdaCorsResponseMiddleware({corsAllowedHostRegex: '(openstax.org|herokuapp.com)$'})()(
61
+ Promise.resolve(apiJsonResponse(200, {})), {request}
62
+ );
63
+
64
+ expect(response?.headers?.['Access-Control-Allow-Origin']).toBeUndefined();
65
+ expect(response?.headers?.['Access-Control-Allow-Methods']).toBeUndefined();
66
+ });
67
+
68
+ it('forwards undefined response if its not options', async() => {
69
+ const request = {
70
+ cookies: [],
71
+ headers: {
72
+ },
73
+ requestContext: {
74
+ http: {
75
+ method: 'GET'
76
+ }
77
+ }
78
+ } as unknown as APIGatewayProxyEventV2;
79
+
80
+ const response = await createLambdaCorsResponseMiddleware({corsAllowedHostRegex: '(openstax.org|herokuapp.com)$'})()(undefined, {request});
81
+
82
+ expect(response).toBeUndefined();
83
+ });
84
+
85
+ it('responds to options', async() => {
86
+ const request = {
87
+ cookies: [],
88
+ headers: {
89
+ origin: 'https://openstax.org'
90
+ },
91
+ requestContext: {
92
+ http: {
93
+ method: 'OPTIONS'
94
+ }
95
+ }
96
+ } as unknown as APIGatewayProxyEventV2;
97
+
98
+ const response = await createLambdaCorsResponseMiddleware({corsAllowedHostRegex: '(openstax.org|herokuapp.com)$'})()(undefined, {request});
99
+
100
+ expect(response?.headers?.['Access-Control-Allow-Origin']).toBe('https://openstax.org');
101
+ expect(response?.headers?.['Access-Control-Allow-Methods']).toBe('POST, GET, PUT, PATCH, DELETE, OPTIONS');
102
+ });
103
+ });
@@ -0,0 +1,52 @@
1
+ import { APIGatewayProxyEventV2 } from 'aws-lambda';
2
+ import { ConfigProviderForConfig } from '../config';
3
+ import { resolveConfigValue } from '../config/resolveConfigValue';
4
+ import { once } from '../misc/helpers';
5
+ import { ApiResponse, apiTextResponse } from '../routing';
6
+
7
+ type Config = {
8
+ corsAllowedHostRegex: string;
9
+ };
10
+
11
+ /**
12
+ * Creates response middleware that adds CORS headers to responses from approved hosts.
13
+ *
14
+ * @param config the config object
15
+ * @param config.corsAllowedHostRegex the config that specifies the regex for allowed hosts
16
+ * @example
17
+ * createLambdaCorsResponseMiddleware({
18
+ * corsAllowedHostRegex: '(openstax.org|herokuapp.com)$'
19
+ * }),
20
+ */
21
+ export const createLambdaCorsResponseMiddleware = (config: ConfigProviderForConfig<Config>) => () => (responsePromise: Promise<ApiResponse<number, any>> | undefined, {request}: {request: APIGatewayProxyEventV2}): Promise<ApiResponse<number, any>> | undefined => {
22
+ const getAllowedHostRegex = once(() => resolveConfigValue(config.corsAllowedHostRegex));
23
+
24
+ const cors = async () => {
25
+ const allowedHost = await getAllowedHostRegex();
26
+
27
+ if (request.headers.origin && request.headers.origin !== 'null' && new URL(request.headers.origin).hostname.match(new RegExp(allowedHost))) {
28
+ return {
29
+ 'Access-Control-Allow-Origin': request.headers.origin,
30
+ 'Access-Control-Allow-Credentials': 'true',
31
+ 'Access-Control-Allow-Headers': 'content-type, x-request-id',
32
+ 'Access-Control-Allow-Methods': 'POST, GET, PUT, PATCH, DELETE, OPTIONS',
33
+ };
34
+ }
35
+ };
36
+
37
+ if (responsePromise) {
38
+ return responsePromise.then(async response => {
39
+ response.headers = {
40
+ ...await cors(),
41
+ ...response.headers
42
+ };
43
+ return response;
44
+ });
45
+ }
46
+
47
+ if (request.requestContext.http.method === 'OPTIONS') {
48
+ return cors().then(headers => apiTextResponse(200, '', headers));
49
+ }
50
+
51
+ return responsePromise;
52
+ };
@@ -0,0 +1,20 @@
1
+ import { NotFoundError } from '../errors';
2
+ import { createThrowNotFoundMiddleware } from './throwNotFoundMiddleware';
3
+
4
+
5
+ describe('throwNotFoundMiddleware', () => {
6
+ it('defaults to 404', async() => {
7
+ const default404MiddlewareNoResponse = () => createThrowNotFoundMiddleware<any>()()(undefined);
8
+
9
+ // Normally caught by the default errorHandler
10
+ expect(default404MiddlewareNoResponse).toThrow(NotFoundError);
11
+ expect(default404MiddlewareNoResponse).toThrow('not found');
12
+ });
13
+
14
+ it('keeps response', async() => {
15
+ const initial = {};
16
+ const response = await createThrowNotFoundMiddleware<any>()()(Promise.resolve(initial));
17
+
18
+ expect(response).toBe(initial);
19
+ });
20
+ });
@@ -0,0 +1,11 @@
1
+ import { NotFoundError } from '../errors';
2
+
3
+ /**
4
+ * Creates response middleware that throws a `NotFoundError` if the response is undefined.
5
+ */
6
+ export const createThrowNotFoundMiddleware = <Ro>() => () => (response: Promise<Ro> | undefined): Promise<Ro> => {
7
+ if (!response) {
8
+ throw new NotFoundError('not found');
9
+ }
10
+ return response;
11
+ };
@@ -0,0 +1,18 @@
1
+ import { createHash } from 'crypto';
2
+
3
+ export type HashValue = string | number | boolean | null | HashCompoundValue;
4
+ export type HashCompoundValue = Array<HashValue> | {[key: string]: HashValue};
5
+
6
+ /**
7
+ * creates a string hash of lots of different kinds of things.
8
+ *
9
+ * @example hashValue({someKey: 'someValue'})
10
+ */
11
+ export const hashValue = (value: HashValue) => {
12
+ // hack for sorting keys https://stackoverflow.com/a/53593328/14809536
13
+ const allKeys = new Set<string>();
14
+ JSON.stringify(value, (k, v) => (allKeys.add(k), v));
15
+ const strValue = JSON.stringify(value, Array.from(allKeys).sort());
16
+
17
+ return createHash('sha1').update(strValue).digest('hex');
18
+ };