@beesolve/analytics-processor 0.0.0 → 0.2.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 (341) hide show
  1. package/DOCS.md +20 -0
  2. package/README.md +87 -3
  3. package/dist/cdk.d.ts +49 -0
  4. package/dist/cdk.js +127 -0
  5. package/dist/dailyRollup/bowser-UJEXXM6S.mjs +2 -0
  6. package/dist/dailyRollup/bowser-UJEXXM6S.mjs.map +7 -0
  7. package/dist/dailyRollup/chunk-3GD7PA4I.mjs +2 -0
  8. package/dist/dailyRollup/chunk-3GD7PA4I.mjs.map +7 -0
  9. package/dist/dailyRollup/chunk-3YRRUMLY.mjs +10 -0
  10. package/dist/dailyRollup/chunk-3YRRUMLY.mjs.map +7 -0
  11. package/dist/dailyRollup/chunk-5JDAL5HL.mjs +2 -0
  12. package/dist/dailyRollup/chunk-5JDAL5HL.mjs.map +7 -0
  13. package/dist/dailyRollup/chunk-C4CD3R2M.mjs +2 -0
  14. package/dist/dailyRollup/chunk-C4CD3R2M.mjs.map +7 -0
  15. package/dist/dailyRollup/chunk-CFZ5JWD3.mjs +2 -0
  16. package/dist/dailyRollup/chunk-CFZ5JWD3.mjs.map +7 -0
  17. package/dist/dailyRollup/chunk-FLISSIFQ.mjs +4 -0
  18. package/dist/dailyRollup/chunk-FLISSIFQ.mjs.map +7 -0
  19. package/dist/dailyRollup/chunk-G7FCKJTE.mjs +8 -0
  20. package/dist/dailyRollup/chunk-G7FCKJTE.mjs.map +7 -0
  21. package/dist/dailyRollup/chunk-GHMUY3QB.mjs +13 -0
  22. package/dist/dailyRollup/chunk-GHMUY3QB.mjs.map +7 -0
  23. package/dist/dailyRollup/chunk-HGD7WY52.mjs +2 -0
  24. package/dist/dailyRollup/chunk-HGD7WY52.mjs.map +7 -0
  25. package/dist/dailyRollup/chunk-IHCR62UU.mjs +6 -0
  26. package/dist/dailyRollup/chunk-IHCR62UU.mjs.map +7 -0
  27. package/dist/dailyRollup/chunk-KT7DZL3D.mjs +2 -0
  28. package/dist/dailyRollup/chunk-KT7DZL3D.mjs.map +7 -0
  29. package/dist/dailyRollup/chunk-LK4IXOEA.mjs +2 -0
  30. package/dist/dailyRollup/chunk-LK4IXOEA.mjs.map +7 -0
  31. package/dist/dailyRollup/chunk-MATUPZWL.mjs +6 -0
  32. package/dist/dailyRollup/chunk-MATUPZWL.mjs.map +7 -0
  33. package/dist/dailyRollup/chunk-NX6AKUU3.mjs +2 -0
  34. package/dist/dailyRollup/chunk-NX6AKUU3.mjs.map +7 -0
  35. package/dist/dailyRollup/chunk-PBJCPHYW.mjs +10 -0
  36. package/dist/dailyRollup/chunk-PBJCPHYW.mjs.map +7 -0
  37. package/dist/dailyRollup/chunk-PNUYSX4A.mjs +2 -0
  38. package/dist/dailyRollup/chunk-PNUYSX4A.mjs.map +7 -0
  39. package/dist/dailyRollup/chunk-RO44VKXZ.mjs +2 -0
  40. package/dist/dailyRollup/chunk-RO44VKXZ.mjs.map +7 -0
  41. package/dist/dailyRollup/chunk-RU3KGSS6.mjs +2 -0
  42. package/dist/dailyRollup/chunk-RU3KGSS6.mjs.map +7 -0
  43. package/dist/dailyRollup/chunk-VG37NXBO.mjs +2 -0
  44. package/dist/dailyRollup/chunk-VG37NXBO.mjs.map +7 -0
  45. package/dist/dailyRollup/chunk-VVG5B2RA.mjs +13 -0
  46. package/dist/dailyRollup/chunk-VVG5B2RA.mjs.map +7 -0
  47. package/dist/dailyRollup/chunk-YIZKQ2WK.mjs +10 -0
  48. package/dist/dailyRollup/chunk-YIZKQ2WK.mjs.map +7 -0
  49. package/dist/dailyRollup/chunk-ZH5DZOB5.mjs +2 -0
  50. package/dist/dailyRollup/chunk-ZH5DZOB5.mjs.map +7 -0
  51. package/dist/dailyRollup/client-7VYWT6KE.mjs +2 -0
  52. package/dist/dailyRollup/client-7VYWT6KE.mjs.map +7 -0
  53. package/dist/dailyRollup/dailyRollup.mjs +2 -0
  54. package/dist/dailyRollup/dailyRollup.mjs.map +7 -0
  55. package/dist/dailyRollup/dist-es-3PO6WBRA.mjs +2 -0
  56. package/dist/dailyRollup/dist-es-3PO6WBRA.mjs.map +7 -0
  57. package/dist/dailyRollup/dist-es-4375P743.mjs +2 -0
  58. package/dist/dailyRollup/dist-es-4375P743.mjs.map +7 -0
  59. package/dist/dailyRollup/dist-es-43J27JDM.mjs +3 -0
  60. package/dist/dailyRollup/dist-es-43J27JDM.mjs.map +7 -0
  61. package/dist/dailyRollup/dist-es-6SRW3I3T.mjs +2 -0
  62. package/dist/dailyRollup/dist-es-6SRW3I3T.mjs.map +7 -0
  63. package/dist/dailyRollup/dist-es-BMGNYEV6.mjs +3 -0
  64. package/dist/dailyRollup/dist-es-BMGNYEV6.mjs.map +7 -0
  65. package/dist/dailyRollup/dist-es-BQ5OLCIJ.mjs +2 -0
  66. package/dist/dailyRollup/dist-es-BQ5OLCIJ.mjs.map +7 -0
  67. package/dist/dailyRollup/dist-es-CFDT5MDO.mjs +2 -0
  68. package/dist/dailyRollup/dist-es-CFDT5MDO.mjs.map +7 -0
  69. package/dist/dailyRollup/dist-es-FPBJ7DAB.mjs +2 -0
  70. package/dist/dailyRollup/dist-es-FPBJ7DAB.mjs.map +7 -0
  71. package/dist/dailyRollup/dist-es-G4DL2UUB.mjs +7 -0
  72. package/dist/dailyRollup/dist-es-G4DL2UUB.mjs.map +7 -0
  73. package/dist/dailyRollup/dist-es-IRYFH3EH.mjs +2 -0
  74. package/dist/dailyRollup/dist-es-IRYFH3EH.mjs.map +7 -0
  75. package/dist/dailyRollup/dist-es-L5F6PNYU.mjs +2 -0
  76. package/dist/dailyRollup/dist-es-L5F6PNYU.mjs.map +7 -0
  77. package/dist/dailyRollup/dist-es-LEKBJS4E.mjs +2 -0
  78. package/dist/dailyRollup/dist-es-LEKBJS4E.mjs.map +7 -0
  79. package/dist/dailyRollup/dist-es-NMUDTELL.mjs +2 -0
  80. package/dist/dailyRollup/dist-es-NMUDTELL.mjs.map +7 -0
  81. package/dist/dailyRollup/dist-es-OY2VA72W.mjs +2 -0
  82. package/dist/dailyRollup/dist-es-OY2VA72W.mjs.map +7 -0
  83. package/dist/dailyRollup/dist-es-SJKDRHZJ.mjs +2 -0
  84. package/dist/dailyRollup/dist-es-SJKDRHZJ.mjs.map +7 -0
  85. package/dist/dailyRollup/dist-es-UGFAGDM2.mjs +7 -0
  86. package/dist/dailyRollup/dist-es-UGFAGDM2.mjs.map +7 -0
  87. package/dist/dailyRollup/dist-es-YRXTT57X.mjs +3 -0
  88. package/dist/dailyRollup/dist-es-YRXTT57X.mjs.map +7 -0
  89. package/dist/dailyRollup/event-streams-G2EZD32F.mjs +2 -0
  90. package/dist/dailyRollup/event-streams-G2EZD32F.mjs.map +7 -0
  91. package/dist/dailyRollup/event-streams-H4LI66VS.mjs +2 -0
  92. package/dist/dailyRollup/event-streams-H4LI66VS.mjs.map +7 -0
  93. package/dist/dailyRollup/event-streams-U52YN65T.mjs +2 -0
  94. package/dist/dailyRollup/event-streams-U52YN65T.mjs.map +7 -0
  95. package/dist/dailyRollup/loadCognitoIdentity-3OXED256.mjs +2 -0
  96. package/dist/dailyRollup/loadCognitoIdentity-3OXED256.mjs.map +7 -0
  97. package/dist/dailyRollup/loadSso-6KWTKR23.mjs +2 -0
  98. package/dist/dailyRollup/loadSso-6KWTKR23.mjs.map +7 -0
  99. package/dist/dailyRollup/loadSso-AITTIS6M.mjs +2 -0
  100. package/dist/dailyRollup/loadSso-AITTIS6M.mjs.map +7 -0
  101. package/dist/dailyRollup/loadSts-LQCNCE76.mjs +2 -0
  102. package/dist/dailyRollup/loadSts-LQCNCE76.mjs.map +7 -0
  103. package/dist/dailyRollup/signin-THWW5VM5.mjs +2 -0
  104. package/dist/dailyRollup/signin-THWW5VM5.mjs.map +7 -0
  105. package/dist/dailyRollup/signin-ZKLDJEMJ.mjs +2 -0
  106. package/dist/dailyRollup/signin-ZKLDJEMJ.mjs.map +7 -0
  107. package/dist/dailyRollup/sso-oidc-MI4NLGSV.mjs +2 -0
  108. package/dist/dailyRollup/sso-oidc-MI4NLGSV.mjs.map +7 -0
  109. package/dist/dailyRollup/sso-oidc-OWLWHDBI.mjs +2 -0
  110. package/dist/dailyRollup/sso-oidc-OWLWHDBI.mjs.map +7 -0
  111. package/dist/dailyRollup/sts-AQIPDWOX.mjs +2 -0
  112. package/dist/dailyRollup/sts-AQIPDWOX.mjs.map +7 -0
  113. package/dist/dailyRollup/sts-EN7K54DW.mjs +2 -0
  114. package/dist/dailyRollup/sts-EN7K54DW.mjs.map +7 -0
  115. package/dist/hourly/bowser-UJEXXM6S.mjs +2 -0
  116. package/dist/hourly/bowser-UJEXXM6S.mjs.map +7 -0
  117. package/dist/hourly/chunk-2LV65MUY.mjs +2 -0
  118. package/dist/hourly/chunk-2LV65MUY.mjs.map +7 -0
  119. package/dist/hourly/chunk-3GD7PA4I.mjs +2 -0
  120. package/dist/hourly/chunk-3GD7PA4I.mjs.map +7 -0
  121. package/dist/hourly/chunk-4X6M4ZIM.mjs +13 -0
  122. package/dist/hourly/chunk-4X6M4ZIM.mjs.map +7 -0
  123. package/dist/hourly/chunk-5EEREEGM.mjs +10 -0
  124. package/dist/hourly/chunk-5EEREEGM.mjs.map +7 -0
  125. package/dist/hourly/chunk-5JDAL5HL.mjs +2 -0
  126. package/dist/hourly/chunk-5JDAL5HL.mjs.map +7 -0
  127. package/dist/hourly/chunk-C4CD3R2M.mjs +2 -0
  128. package/dist/hourly/chunk-C4CD3R2M.mjs.map +7 -0
  129. package/dist/hourly/chunk-CDK2TDZ3.mjs +2 -0
  130. package/dist/hourly/chunk-CDK2TDZ3.mjs.map +7 -0
  131. package/dist/hourly/chunk-CFZ5JWD3.mjs +2 -0
  132. package/dist/hourly/chunk-CFZ5JWD3.mjs.map +7 -0
  133. package/dist/hourly/chunk-DDOSB7QU.mjs +10 -0
  134. package/dist/hourly/chunk-DDOSB7QU.mjs.map +7 -0
  135. package/dist/hourly/chunk-FLISSIFQ.mjs +4 -0
  136. package/dist/hourly/chunk-FLISSIFQ.mjs.map +7 -0
  137. package/dist/hourly/chunk-G7FCKJTE.mjs +8 -0
  138. package/dist/hourly/chunk-G7FCKJTE.mjs.map +7 -0
  139. package/dist/hourly/chunk-HGD7WY52.mjs +2 -0
  140. package/dist/hourly/chunk-HGD7WY52.mjs.map +7 -0
  141. package/dist/hourly/chunk-IHCR62UU.mjs +6 -0
  142. package/dist/hourly/chunk-IHCR62UU.mjs.map +7 -0
  143. package/dist/hourly/chunk-LK4IXOEA.mjs +2 -0
  144. package/dist/hourly/chunk-LK4IXOEA.mjs.map +7 -0
  145. package/dist/hourly/chunk-MATUPZWL.mjs +6 -0
  146. package/dist/hourly/chunk-MATUPZWL.mjs.map +7 -0
  147. package/dist/hourly/chunk-NX6AKUU3.mjs +2 -0
  148. package/dist/hourly/chunk-NX6AKUU3.mjs.map +7 -0
  149. package/dist/hourly/chunk-OV75J3RB.mjs +10 -0
  150. package/dist/hourly/chunk-OV75J3RB.mjs.map +7 -0
  151. package/dist/hourly/chunk-RO44VKXZ.mjs +2 -0
  152. package/dist/hourly/chunk-RO44VKXZ.mjs.map +7 -0
  153. package/dist/hourly/chunk-RU3KGSS6.mjs +2 -0
  154. package/dist/hourly/chunk-RU3KGSS6.mjs.map +7 -0
  155. package/dist/hourly/chunk-SEATMW6H.mjs +2 -0
  156. package/dist/hourly/chunk-SEATMW6H.mjs.map +7 -0
  157. package/dist/hourly/chunk-UEL4UF23.mjs +2 -0
  158. package/dist/hourly/chunk-UEL4UF23.mjs.map +7 -0
  159. package/dist/hourly/chunk-VG37NXBO.mjs +2 -0
  160. package/dist/hourly/chunk-VG37NXBO.mjs.map +7 -0
  161. package/dist/hourly/chunk-YLTURKBY.mjs +13 -0
  162. package/dist/hourly/chunk-YLTURKBY.mjs.map +7 -0
  163. package/dist/hourly/chunk-ZH5DZOB5.mjs +2 -0
  164. package/dist/hourly/chunk-ZH5DZOB5.mjs.map +7 -0
  165. package/dist/hourly/client-YFAS5DGU.mjs +2 -0
  166. package/dist/hourly/client-YFAS5DGU.mjs.map +7 -0
  167. package/dist/hourly/dist-es-2QGRGQLF.mjs +7 -0
  168. package/dist/hourly/dist-es-2QGRGQLF.mjs.map +7 -0
  169. package/dist/hourly/dist-es-4JJUYAKR.mjs +2 -0
  170. package/dist/hourly/dist-es-4JJUYAKR.mjs.map +7 -0
  171. package/dist/hourly/dist-es-4NUPISR6.mjs +3 -0
  172. package/dist/hourly/dist-es-4NUPISR6.mjs.map +7 -0
  173. package/dist/hourly/dist-es-4PFASTED.mjs +2 -0
  174. package/dist/hourly/dist-es-4PFASTED.mjs.map +7 -0
  175. package/dist/hourly/dist-es-ARVZEK2B.mjs +2 -0
  176. package/dist/hourly/dist-es-ARVZEK2B.mjs.map +7 -0
  177. package/dist/hourly/dist-es-BH4D2XQ2.mjs +2 -0
  178. package/dist/hourly/dist-es-BH4D2XQ2.mjs.map +7 -0
  179. package/dist/hourly/dist-es-D46ET7B3.mjs +2 -0
  180. package/dist/hourly/dist-es-D46ET7B3.mjs.map +7 -0
  181. package/dist/hourly/dist-es-DQHOM6HA.mjs +3 -0
  182. package/dist/hourly/dist-es-DQHOM6HA.mjs.map +7 -0
  183. package/dist/hourly/dist-es-ETNPEJSC.mjs +2 -0
  184. package/dist/hourly/dist-es-ETNPEJSC.mjs.map +7 -0
  185. package/dist/hourly/dist-es-HCGEEOBW.mjs +2 -0
  186. package/dist/hourly/dist-es-HCGEEOBW.mjs.map +7 -0
  187. package/dist/hourly/dist-es-LONCZIHI.mjs +2 -0
  188. package/dist/hourly/dist-es-LONCZIHI.mjs.map +7 -0
  189. package/dist/hourly/dist-es-PV5J6DAM.mjs +2 -0
  190. package/dist/hourly/dist-es-PV5J6DAM.mjs.map +7 -0
  191. package/dist/hourly/dist-es-S4EGUNEL.mjs +2 -0
  192. package/dist/hourly/dist-es-S4EGUNEL.mjs.map +7 -0
  193. package/dist/hourly/dist-es-VDZMHJW2.mjs +7 -0
  194. package/dist/hourly/dist-es-VDZMHJW2.mjs.map +7 -0
  195. package/dist/hourly/dist-es-WBVL2T3J.mjs +2 -0
  196. package/dist/hourly/dist-es-WBVL2T3J.mjs.map +7 -0
  197. package/dist/hourly/dist-es-YFKUCAP2.mjs +2 -0
  198. package/dist/hourly/dist-es-YFKUCAP2.mjs.map +7 -0
  199. package/dist/hourly/dist-es-YZBMXOS5.mjs +3 -0
  200. package/dist/hourly/dist-es-YZBMXOS5.mjs.map +7 -0
  201. package/dist/hourly/event-streams-G2EZD32F.mjs +2 -0
  202. package/dist/hourly/event-streams-G2EZD32F.mjs.map +7 -0
  203. package/dist/hourly/event-streams-H4LI66VS.mjs +2 -0
  204. package/dist/hourly/event-streams-H4LI66VS.mjs.map +7 -0
  205. package/dist/hourly/event-streams-U52YN65T.mjs +2 -0
  206. package/dist/hourly/event-streams-U52YN65T.mjs.map +7 -0
  207. package/dist/hourly/hourly.mjs +11 -0
  208. package/dist/hourly/hourly.mjs.map +7 -0
  209. package/dist/hourly/loadCognitoIdentity-KHSY4IOA.mjs +2 -0
  210. package/dist/hourly/loadCognitoIdentity-KHSY4IOA.mjs.map +7 -0
  211. package/dist/hourly/loadSso-HHJP34KX.mjs +2 -0
  212. package/dist/hourly/loadSso-HHJP34KX.mjs.map +7 -0
  213. package/dist/hourly/loadSso-R47RBCPJ.mjs +2 -0
  214. package/dist/hourly/loadSso-R47RBCPJ.mjs.map +7 -0
  215. package/dist/hourly/loadSts-5X55AJY5.mjs +2 -0
  216. package/dist/hourly/loadSts-5X55AJY5.mjs.map +7 -0
  217. package/dist/hourly/signin-F7JF6BF6.mjs +2 -0
  218. package/dist/hourly/signin-F7JF6BF6.mjs.map +7 -0
  219. package/dist/hourly/signin-WDXS6SW2.mjs +2 -0
  220. package/dist/hourly/signin-WDXS6SW2.mjs.map +7 -0
  221. package/dist/hourly/sso-oidc-63EGB35D.mjs +2 -0
  222. package/dist/hourly/sso-oidc-63EGB35D.mjs.map +7 -0
  223. package/dist/hourly/sso-oidc-UVLJZI2R.mjs +2 -0
  224. package/dist/hourly/sso-oidc-UVLJZI2R.mjs.map +7 -0
  225. package/dist/hourly/sts-4M7S3GN4.mjs +2 -0
  226. package/dist/hourly/sts-4M7S3GN4.mjs.map +7 -0
  227. package/dist/hourly/sts-YXUOYWFS.mjs +2 -0
  228. package/dist/hourly/sts-YXUOYWFS.mjs.map +7 -0
  229. package/dist/index.d.ts +359 -0
  230. package/dist/index.js +1011 -0
  231. package/dist/monthlyRollup/bowser-UJEXXM6S.mjs +2 -0
  232. package/dist/monthlyRollup/bowser-UJEXXM6S.mjs.map +7 -0
  233. package/dist/monthlyRollup/chunk-3GD7PA4I.mjs +2 -0
  234. package/dist/monthlyRollup/chunk-3GD7PA4I.mjs.map +7 -0
  235. package/dist/monthlyRollup/chunk-3YRRUMLY.mjs +10 -0
  236. package/dist/monthlyRollup/chunk-3YRRUMLY.mjs.map +7 -0
  237. package/dist/monthlyRollup/chunk-5JDAL5HL.mjs +2 -0
  238. package/dist/monthlyRollup/chunk-5JDAL5HL.mjs.map +7 -0
  239. package/dist/monthlyRollup/chunk-C4CD3R2M.mjs +2 -0
  240. package/dist/monthlyRollup/chunk-C4CD3R2M.mjs.map +7 -0
  241. package/dist/monthlyRollup/chunk-CFZ5JWD3.mjs +2 -0
  242. package/dist/monthlyRollup/chunk-CFZ5JWD3.mjs.map +7 -0
  243. package/dist/monthlyRollup/chunk-FLISSIFQ.mjs +4 -0
  244. package/dist/monthlyRollup/chunk-FLISSIFQ.mjs.map +7 -0
  245. package/dist/monthlyRollup/chunk-G7FCKJTE.mjs +8 -0
  246. package/dist/monthlyRollup/chunk-G7FCKJTE.mjs.map +7 -0
  247. package/dist/monthlyRollup/chunk-GHMUY3QB.mjs +13 -0
  248. package/dist/monthlyRollup/chunk-GHMUY3QB.mjs.map +7 -0
  249. package/dist/monthlyRollup/chunk-HGD7WY52.mjs +2 -0
  250. package/dist/monthlyRollup/chunk-HGD7WY52.mjs.map +7 -0
  251. package/dist/monthlyRollup/chunk-IHCR62UU.mjs +6 -0
  252. package/dist/monthlyRollup/chunk-IHCR62UU.mjs.map +7 -0
  253. package/dist/monthlyRollup/chunk-KT7DZL3D.mjs +2 -0
  254. package/dist/monthlyRollup/chunk-KT7DZL3D.mjs.map +7 -0
  255. package/dist/monthlyRollup/chunk-LK4IXOEA.mjs +2 -0
  256. package/dist/monthlyRollup/chunk-LK4IXOEA.mjs.map +7 -0
  257. package/dist/monthlyRollup/chunk-MATUPZWL.mjs +6 -0
  258. package/dist/monthlyRollup/chunk-MATUPZWL.mjs.map +7 -0
  259. package/dist/monthlyRollup/chunk-NX6AKUU3.mjs +2 -0
  260. package/dist/monthlyRollup/chunk-NX6AKUU3.mjs.map +7 -0
  261. package/dist/monthlyRollup/chunk-PBJCPHYW.mjs +10 -0
  262. package/dist/monthlyRollup/chunk-PBJCPHYW.mjs.map +7 -0
  263. package/dist/monthlyRollup/chunk-PNUYSX4A.mjs +2 -0
  264. package/dist/monthlyRollup/chunk-PNUYSX4A.mjs.map +7 -0
  265. package/dist/monthlyRollup/chunk-RO44VKXZ.mjs +2 -0
  266. package/dist/monthlyRollup/chunk-RO44VKXZ.mjs.map +7 -0
  267. package/dist/monthlyRollup/chunk-RU3KGSS6.mjs +2 -0
  268. package/dist/monthlyRollup/chunk-RU3KGSS6.mjs.map +7 -0
  269. package/dist/monthlyRollup/chunk-VG37NXBO.mjs +2 -0
  270. package/dist/monthlyRollup/chunk-VG37NXBO.mjs.map +7 -0
  271. package/dist/monthlyRollup/chunk-VVG5B2RA.mjs +13 -0
  272. package/dist/monthlyRollup/chunk-VVG5B2RA.mjs.map +7 -0
  273. package/dist/monthlyRollup/chunk-YIZKQ2WK.mjs +10 -0
  274. package/dist/monthlyRollup/chunk-YIZKQ2WK.mjs.map +7 -0
  275. package/dist/monthlyRollup/chunk-ZH5DZOB5.mjs +2 -0
  276. package/dist/monthlyRollup/chunk-ZH5DZOB5.mjs.map +7 -0
  277. package/dist/monthlyRollup/client-7VYWT6KE.mjs +2 -0
  278. package/dist/monthlyRollup/client-7VYWT6KE.mjs.map +7 -0
  279. package/dist/monthlyRollup/dist-es-3PO6WBRA.mjs +2 -0
  280. package/dist/monthlyRollup/dist-es-3PO6WBRA.mjs.map +7 -0
  281. package/dist/monthlyRollup/dist-es-4375P743.mjs +2 -0
  282. package/dist/monthlyRollup/dist-es-4375P743.mjs.map +7 -0
  283. package/dist/monthlyRollup/dist-es-43J27JDM.mjs +3 -0
  284. package/dist/monthlyRollup/dist-es-43J27JDM.mjs.map +7 -0
  285. package/dist/monthlyRollup/dist-es-6SRW3I3T.mjs +2 -0
  286. package/dist/monthlyRollup/dist-es-6SRW3I3T.mjs.map +7 -0
  287. package/dist/monthlyRollup/dist-es-BMGNYEV6.mjs +3 -0
  288. package/dist/monthlyRollup/dist-es-BMGNYEV6.mjs.map +7 -0
  289. package/dist/monthlyRollup/dist-es-BQ5OLCIJ.mjs +2 -0
  290. package/dist/monthlyRollup/dist-es-BQ5OLCIJ.mjs.map +7 -0
  291. package/dist/monthlyRollup/dist-es-CFDT5MDO.mjs +2 -0
  292. package/dist/monthlyRollup/dist-es-CFDT5MDO.mjs.map +7 -0
  293. package/dist/monthlyRollup/dist-es-FPBJ7DAB.mjs +2 -0
  294. package/dist/monthlyRollup/dist-es-FPBJ7DAB.mjs.map +7 -0
  295. package/dist/monthlyRollup/dist-es-G4DL2UUB.mjs +7 -0
  296. package/dist/monthlyRollup/dist-es-G4DL2UUB.mjs.map +7 -0
  297. package/dist/monthlyRollup/dist-es-IRYFH3EH.mjs +2 -0
  298. package/dist/monthlyRollup/dist-es-IRYFH3EH.mjs.map +7 -0
  299. package/dist/monthlyRollup/dist-es-L5F6PNYU.mjs +2 -0
  300. package/dist/monthlyRollup/dist-es-L5F6PNYU.mjs.map +7 -0
  301. package/dist/monthlyRollup/dist-es-LEKBJS4E.mjs +2 -0
  302. package/dist/monthlyRollup/dist-es-LEKBJS4E.mjs.map +7 -0
  303. package/dist/monthlyRollup/dist-es-NMUDTELL.mjs +2 -0
  304. package/dist/monthlyRollup/dist-es-NMUDTELL.mjs.map +7 -0
  305. package/dist/monthlyRollup/dist-es-OY2VA72W.mjs +2 -0
  306. package/dist/monthlyRollup/dist-es-OY2VA72W.mjs.map +7 -0
  307. package/dist/monthlyRollup/dist-es-SJKDRHZJ.mjs +2 -0
  308. package/dist/monthlyRollup/dist-es-SJKDRHZJ.mjs.map +7 -0
  309. package/dist/monthlyRollup/dist-es-UGFAGDM2.mjs +7 -0
  310. package/dist/monthlyRollup/dist-es-UGFAGDM2.mjs.map +7 -0
  311. package/dist/monthlyRollup/dist-es-YRXTT57X.mjs +3 -0
  312. package/dist/monthlyRollup/dist-es-YRXTT57X.mjs.map +7 -0
  313. package/dist/monthlyRollup/event-streams-G2EZD32F.mjs +2 -0
  314. package/dist/monthlyRollup/event-streams-G2EZD32F.mjs.map +7 -0
  315. package/dist/monthlyRollup/event-streams-H4LI66VS.mjs +2 -0
  316. package/dist/monthlyRollup/event-streams-H4LI66VS.mjs.map +7 -0
  317. package/dist/monthlyRollup/event-streams-U52YN65T.mjs +2 -0
  318. package/dist/monthlyRollup/event-streams-U52YN65T.mjs.map +7 -0
  319. package/dist/monthlyRollup/loadCognitoIdentity-3OXED256.mjs +2 -0
  320. package/dist/monthlyRollup/loadCognitoIdentity-3OXED256.mjs.map +7 -0
  321. package/dist/monthlyRollup/loadSso-6KWTKR23.mjs +2 -0
  322. package/dist/monthlyRollup/loadSso-6KWTKR23.mjs.map +7 -0
  323. package/dist/monthlyRollup/loadSso-AITTIS6M.mjs +2 -0
  324. package/dist/monthlyRollup/loadSso-AITTIS6M.mjs.map +7 -0
  325. package/dist/monthlyRollup/loadSts-LQCNCE76.mjs +2 -0
  326. package/dist/monthlyRollup/loadSts-LQCNCE76.mjs.map +7 -0
  327. package/dist/monthlyRollup/monthlyRollup.mjs +2 -0
  328. package/dist/monthlyRollup/monthlyRollup.mjs.map +7 -0
  329. package/dist/monthlyRollup/signin-THWW5VM5.mjs +2 -0
  330. package/dist/monthlyRollup/signin-THWW5VM5.mjs.map +7 -0
  331. package/dist/monthlyRollup/signin-ZKLDJEMJ.mjs +2 -0
  332. package/dist/monthlyRollup/signin-ZKLDJEMJ.mjs.map +7 -0
  333. package/dist/monthlyRollup/sso-oidc-MI4NLGSV.mjs +2 -0
  334. package/dist/monthlyRollup/sso-oidc-MI4NLGSV.mjs.map +7 -0
  335. package/dist/monthlyRollup/sso-oidc-OWLWHDBI.mjs +2 -0
  336. package/dist/monthlyRollup/sso-oidc-OWLWHDBI.mjs.map +7 -0
  337. package/dist/monthlyRollup/sts-AQIPDWOX.mjs +2 -0
  338. package/dist/monthlyRollup/sts-AQIPDWOX.mjs.map +7 -0
  339. package/dist/monthlyRollup/sts-EN7K54DW.mjs +2 -0
  340. package/dist/monthlyRollup/sts-EN7K54DW.mjs.map +7 -0
  341. package/package.json +55 -6
package/dist/index.js ADDED
@@ -0,0 +1,1011 @@
1
+ // packages/analytics-processor/index.ts
2
+ export * from "@beesolve/ip-info";
3
+
4
+ // packages/analytics-processor/src/appliedMarkers.ts
5
+ import { GetCommand } from "@aws-sdk/lib-dynamodb";
6
+ import * as v from "valibot";
7
+
8
+ // packages/analytics-processor/src/keys.ts
9
+ var grains = ["hour", "day", "month"];
10
+ var dimensions = ["status", "country", "device", "path"];
11
+ var appliedSources = ["v1", "v2"];
12
+
13
+ // packages/analytics-processor/src/appliedMarkers.ts
14
+ var appliedMarkerSchema = v.object({
15
+ pk: v.string(),
16
+ sk: v.string(),
17
+ source: v.picklist(appliedSources),
18
+ appliedAt: v.number(),
19
+ ttl: v.optional(v.number())
20
+ });
21
+
22
+ class AppliedMarkers {
23
+ props;
24
+ constructor(props) {
25
+ this.props = props;
26
+ }
27
+ isApplied = async (props) => {
28
+ const { Item: item } = await this.props.dynamo.send(new GetCommand({
29
+ TableName: this.props.tableName,
30
+ Key: { pk: partitionKey(props), sk: "applied" }
31
+ }));
32
+ return item != null;
33
+ };
34
+ buildMarkerPut = (props) => {
35
+ const item = {
36
+ pk: partitionKey(props),
37
+ sk: "applied",
38
+ source: props.source,
39
+ appliedAt: Date.now()
40
+ };
41
+ if (props.ttl != null) {
42
+ item.ttl = props.ttl;
43
+ }
44
+ return {
45
+ Put: {
46
+ TableName: this.props.tableName,
47
+ Item: item,
48
+ ConditionExpression: "attribute_not_exists(pk) AND attribute_not_exists(sk)"
49
+ }
50
+ };
51
+ };
52
+ }
53
+ function partitionKey(props) {
54
+ return `applied#${props.grain}#${props.periodKey}`;
55
+ }
56
+ // packages/analytics-processor/src/athena.ts
57
+ import {
58
+ GetQueryExecutionCommand,
59
+ GetQueryResultsCommand,
60
+ StartQueryExecutionCommand
61
+ } from "@aws-sdk/client-athena";
62
+
63
+ // packages/analytics-processor/src/reduce.ts
64
+ function sumTotals(items) {
65
+ const summed = {
66
+ hits: 0,
67
+ success: 0,
68
+ errors: 0,
69
+ errors4xx: 0,
70
+ errors5xx: 0,
71
+ bytesSent: 0,
72
+ bytesReceived: 0
73
+ };
74
+ return items.reduce((accumulator, item) => ({
75
+ hits: accumulator.hits + item.hits,
76
+ success: accumulator.success + item.success,
77
+ errors: accumulator.errors + item.errors,
78
+ errors4xx: accumulator.errors4xx + item.errors4xx,
79
+ errors5xx: accumulator.errors5xx + item.errors5xx,
80
+ bytesSent: accumulator.bytesSent + item.bytesSent,
81
+ bytesReceived: accumulator.bytesReceived + item.bytesReceived
82
+ }), summed);
83
+ }
84
+ function sumBreakdown(items) {
85
+ const byValue = {};
86
+ for (const item of items) {
87
+ const existing = byValue[item.value];
88
+ if (existing == null) {
89
+ byValue[item.value] = { value: item.value, hits: item.hits, bytes: item.bytes };
90
+ } else {
91
+ byValue[item.value] = {
92
+ value: item.value,
93
+ hits: existing.hits + item.hits,
94
+ bytes: existing.bytes + item.bytes
95
+ };
96
+ }
97
+ }
98
+ return Object.values(byValue);
99
+ }
100
+ function topNWithOther({
101
+ items,
102
+ n,
103
+ otherValue
104
+ }) {
105
+ const sorted = [...items].sort((left, right) => right.hits - left.hits);
106
+ const top = sorted.slice(0, n);
107
+ const remainder = sorted.slice(n);
108
+ if (remainder.length === 0)
109
+ return top;
110
+ const other = remainder.reduce((accumulator, item) => ({
111
+ value: otherValue,
112
+ hits: accumulator.hits + item.hits,
113
+ bytes: accumulator.bytes + item.bytes
114
+ }), { value: otherValue, hits: 0, bytes: 0 });
115
+ return [...top, other];
116
+ }
117
+
118
+ // packages/analytics-processor/src/athena.ts
119
+ var requiredRecordFields = [
120
+ "timestamp",
121
+ "sc_status",
122
+ "sc_bytes",
123
+ "cs_bytes",
124
+ "time_taken",
125
+ "x_edge_result_type",
126
+ "x_edge_detailed_result_type",
127
+ "cs_uri_stem",
128
+ "c_ip",
129
+ "cs_user_agent"
130
+ ];
131
+ var columnMaps = {
132
+ v2: {
133
+ status: "sc_status",
134
+ bytesSent: "sc_bytes",
135
+ bytesReceived: "cs_bytes",
136
+ timeTaken: "time_taken",
137
+ resultType: "x_edge_result_type",
138
+ detailedResultType: "x_edge_detailed_result_type",
139
+ uriStem: "cs_uri_stem",
140
+ clientIp: "c_ip",
141
+ userAgent: "cs_user_agent",
142
+ timestamp: "timestamp"
143
+ },
144
+ v1: {
145
+ status: 'CAST("sc-status" AS integer)',
146
+ bytesSent: 'CAST("sc-bytes" AS bigint)',
147
+ bytesReceived: 'CAST("cs-bytes" AS bigint)',
148
+ timeTaken: 'CAST("time-taken" AS double)',
149
+ resultType: '"x-edge-result-type"',
150
+ detailedResultType: '"x-edge-detailed-result-type"',
151
+ uriStem: '"cs-uri-stem"',
152
+ clientIp: '"c-ip"',
153
+ userAgent: '"cs(User-Agent)"',
154
+ timestamp: '"time"'
155
+ }
156
+ };
157
+ function hourKeyParts(hourKey) {
158
+ const match = /^(\d{4})-(\d{2})-(\d{2})-(\d{2})$/.exec(hourKey);
159
+ if (match == null) {
160
+ throw new Error(`Invalid hourKey: ${hourKey}`);
161
+ }
162
+ const [, year, month, day, hour] = match;
163
+ if (year == null || month == null || day == null || hour == null) {
164
+ throw new Error(`Invalid hourKey: ${hourKey}`);
165
+ }
166
+ return { year, month, day, hour };
167
+ }
168
+ function deviceCaseExpression(userAgentColumn) {
169
+ return [
170
+ "CASE",
171
+ `WHEN lower(${userAgentColumn}) LIKE '%bot%' OR lower(${userAgentColumn}) LIKE '%crawler%' OR lower(${userAgentColumn}) LIKE '%spider%' OR lower(${userAgentColumn}) LIKE '%slurp%' THEN 'bot'`,
172
+ `WHEN lower(${userAgentColumn}) LIKE '%mobi%' OR lower(${userAgentColumn}) LIKE '%android%' OR lower(${userAgentColumn}) LIKE '%iphone%' OR lower(${userAgentColumn}) LIKE '%ipad%' THEN 'mobile'`,
173
+ `WHEN lower(${userAgentColumn}) LIKE '%windows nt%' OR lower(${userAgentColumn}) LIKE '%macintosh%' OR lower(${userAgentColumn}) LIKE '%x11%' OR lower(${userAgentColumn}) LIKE '%linux%' THEN 'desktop'`,
174
+ "ELSE 'other'",
175
+ "END"
176
+ ].join(" ");
177
+ }
178
+ function predicateFor({
179
+ source,
180
+ hourKey,
181
+ columns
182
+ }) {
183
+ const parts = hourKeyParts(hourKey);
184
+ if (source === "v2") {
185
+ return [
186
+ `year = '${parts.year}'`,
187
+ `month = '${parts.month}'`,
188
+ `day = '${parts.day}'`,
189
+ `hour = '${parts.hour}'`
190
+ ].join(" AND ");
191
+ }
192
+ return [
193
+ `"date" = DATE '${parts.year}-${parts.month}-${parts.day}'`,
194
+ `substr(${columns.timestamp}, 1, 2) = '${parts.hour}'`
195
+ ].join(" AND ");
196
+ }
197
+ function buildHourlyQuery({
198
+ table,
199
+ source,
200
+ hourKey,
201
+ topPaths: _topPaths
202
+ }) {
203
+ const columns = columnMaps[source];
204
+ const predicate = predicateFor({ source, hourKey, columns });
205
+ const device = deviceCaseExpression(columns.userAgent);
206
+ const groupingSets = [
207
+ "()",
208
+ `(${columns.status})`,
209
+ "(device)",
210
+ `(${columns.uriStem})`,
211
+ `(${columns.clientIp})`
212
+ ].join(", ");
213
+ return [
214
+ "SELECT",
215
+ ` ${columns.status} AS status_value,`,
216
+ ` ${device} AS device,`,
217
+ ` ${columns.uriStem} AS path_value,`,
218
+ ` ${columns.clientIp} AS ip_value,`,
219
+ " count(*) AS hits,",
220
+ ` sum(CASE WHEN ${columns.status} BETWEEN 200 AND 399 THEN 1 ELSE 0 END) AS success,`,
221
+ ` sum(CASE WHEN ${columns.status} BETWEEN 400 AND 599 THEN 1 ELSE 0 END) AS errors,`,
222
+ ` sum(CASE WHEN ${columns.status} BETWEEN 400 AND 499 THEN 1 ELSE 0 END) AS errors4xx,`,
223
+ ` sum(CASE WHEN ${columns.status} BETWEEN 500 AND 599 THEN 1 ELSE 0 END) AS errors5xx,`,
224
+ ` sum(${columns.bytesSent}) AS bytes_sent,`,
225
+ ` sum(${columns.bytesReceived}) AS bytes_received,`,
226
+ ` approx_percentile(${columns.timeTaken}, 0.5) AS p50_time_taken,`,
227
+ ` approx_percentile(${columns.timeTaken}, 0.95) AS p95_time_taken,`,
228
+ ` sum(CASE WHEN ${columns.resultType} = 'Hit' THEN 1 ELSE 0 END) AS cache_hits,`,
229
+ ` count(DISTINCT ${columns.clientIp}) AS unique_ip_count`,
230
+ `FROM "${table}"`,
231
+ `WHERE ${predicate}`,
232
+ `GROUP BY GROUPING SETS (${groupingSets})`
233
+ ].join(`
234
+ `);
235
+ }
236
+ function toNumber(value) {
237
+ if (value == null || value === "")
238
+ return 0;
239
+ const parsed = Number(value);
240
+ return Number.isNaN(parsed) ? 0 : parsed;
241
+ }
242
+ function cellValue(value) {
243
+ if (value == null || value === "")
244
+ return;
245
+ return value;
246
+ }
247
+ function parseRow(columns) {
248
+ return {
249
+ status: cellValue(columns[0]),
250
+ device: cellValue(columns[1]),
251
+ path: cellValue(columns[2]),
252
+ ip: cellValue(columns[3]),
253
+ hits: toNumber(columns[4]),
254
+ success: toNumber(columns[5]),
255
+ errors: toNumber(columns[6]),
256
+ errors4xx: toNumber(columns[7]),
257
+ errors5xx: toNumber(columns[8]),
258
+ bytesSent: toNumber(columns[9]),
259
+ bytesReceived: toNumber(columns[10]),
260
+ p50TimeTaken: toNumber(columns[11]),
261
+ p95TimeTaken: toNumber(columns[12]),
262
+ cacheHits: toNumber(columns[13]),
263
+ uniqueIpCount: toNumber(columns[14])
264
+ };
265
+ }
266
+ function assembleResult({
267
+ rows,
268
+ topPaths
269
+ }) {
270
+ const totalsRow = rows.find((row) => row.status == null && row.device == null && row.path == null && row.ip == null);
271
+ const totals = totalsRow == null ? {
272
+ hits: 0,
273
+ success: 0,
274
+ errors: 0,
275
+ errors4xx: 0,
276
+ errors5xx: 0,
277
+ bytesSent: 0,
278
+ bytesReceived: 0,
279
+ p50TimeTaken: 0,
280
+ p95TimeTaken: 0,
281
+ cacheHitRatio: 0,
282
+ uniqueIpCount: 0
283
+ } : {
284
+ hits: totalsRow.hits,
285
+ success: totalsRow.success,
286
+ errors: totalsRow.errors,
287
+ errors4xx: totalsRow.errors4xx,
288
+ errors5xx: totalsRow.errors5xx,
289
+ bytesSent: totalsRow.bytesSent,
290
+ bytesReceived: totalsRow.bytesReceived,
291
+ p50TimeTaken: totalsRow.p50TimeTaken,
292
+ p95TimeTaken: totalsRow.p95TimeTaken,
293
+ cacheHitRatio: totalsRow.hits === 0 ? 0 : totalsRow.cacheHits / totalsRow.hits,
294
+ uniqueIpCount: totalsRow.uniqueIpCount
295
+ };
296
+ const byStatus = rows.filter((row) => row.status != null && row.device == null && row.path == null && row.ip == null).map((row) => ({ value: row.status ?? "", hits: row.hits, bytes: row.bytesSent }));
297
+ const byDevice = rows.filter((row) => row.device != null && row.status == null && row.path == null && row.ip == null).map((row) => ({ value: row.device ?? "", hits: row.hits, bytes: row.bytesSent }));
298
+ const byPathAll = rows.filter((row) => row.path != null && row.status == null && row.device == null && row.ip == null).map((row) => ({ value: row.path ?? "", hits: row.hits, bytes: row.bytesSent }));
299
+ const byPath = topNWithOther({ items: byPathAll, n: topPaths, otherValue: "__other__" });
300
+ const topIps = rows.filter((row) => row.ip != null && row.status == null && row.device == null && row.path == null).map((row) => ({ ip: row.ip ?? "", hits: row.hits })).sort((left, right) => right.hits - left.hits).slice(0, topPaths);
301
+ return { totals, byStatus, byDevice, byPath, topIps };
302
+ }
303
+ async function waitForQuery({
304
+ athena,
305
+ queryExecutionId
306
+ }) {
307
+ let delayMs = 250;
308
+ const maxDelayMs = 5000;
309
+ while (true) {
310
+ const execution = await athena.send(new GetQueryExecutionCommand({ QueryExecutionId: queryExecutionId }));
311
+ const state = execution.QueryExecution?.Status?.State;
312
+ if (state === "SUCCEEDED")
313
+ return;
314
+ if (state === "FAILED" || state === "CANCELLED") {
315
+ const reason = execution.QueryExecution?.Status?.StateChangeReason ?? "unknown reason";
316
+ throw new Error(`Athena query ${state}: ${reason}`);
317
+ }
318
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
319
+ delayMs = Math.min(delayMs * 2, maxDelayMs);
320
+ }
321
+ }
322
+ async function fetchRows({
323
+ athena,
324
+ queryExecutionId
325
+ }) {
326
+ const rows = [];
327
+ let nextToken;
328
+ let isFirstPage = true;
329
+ do {
330
+ const results = await athena.send(new GetQueryResultsCommand({ QueryExecutionId: queryExecutionId, NextToken: nextToken }));
331
+ const resultRows = results.ResultSet?.Rows ?? [];
332
+ const dataRows = isFirstPage ? resultRows.slice(1) : resultRows;
333
+ for (const dataRow of dataRows) {
334
+ const cells = (dataRow.Data ?? []).map((datum) => datum.VarCharValue);
335
+ rows.push(parseRow(cells));
336
+ }
337
+ nextToken = results.NextToken;
338
+ isFirstPage = false;
339
+ } while (nextToken != null);
340
+ return rows;
341
+ }
342
+ async function runHourlyAthenaQuery({
343
+ athena,
344
+ database,
345
+ table,
346
+ workgroup,
347
+ outputLocation,
348
+ source,
349
+ hourKey,
350
+ topPaths
351
+ }) {
352
+ const queryString = buildHourlyQuery({ table, source, hourKey, topPaths });
353
+ const started = await athena.send(new StartQueryExecutionCommand({
354
+ QueryString: queryString,
355
+ QueryExecutionContext: { Database: database },
356
+ WorkGroup: workgroup,
357
+ ResultConfiguration: outputLocation == null ? undefined : { OutputLocation: outputLocation }
358
+ }));
359
+ const queryExecutionId = started.QueryExecutionId;
360
+ if (queryExecutionId == null) {
361
+ throw new Error("Athena StartQueryExecution returned no QueryExecutionId");
362
+ }
363
+ await waitForQuery({ athena, queryExecutionId });
364
+ const rows = await fetchRows({ athena, queryExecutionId });
365
+ return assembleResult({ rows, topPaths });
366
+ }
367
+ // packages/analytics-processor/src/breakdowns.ts
368
+ import { UpdateCommand } from "@aws-sdk/lib-dynamodb";
369
+ import { queryAll } from "@beesolve/dynamo-helpers";
370
+ import * as v2 from "valibot";
371
+ var breakdownSchema = v2.object({
372
+ pk: v2.string(),
373
+ sk: v2.string(),
374
+ dimension: v2.picklist(dimensions),
375
+ grain: v2.picklist(grains),
376
+ periodKey: v2.string(),
377
+ value: v2.string(),
378
+ hits: v2.number(),
379
+ bytes: v2.number(),
380
+ ttl: v2.optional(v2.number())
381
+ });
382
+
383
+ class Breakdowns {
384
+ props;
385
+ constructor(props) {
386
+ this.props = props;
387
+ }
388
+ addMany = async (props) => {
389
+ const updates = this.buildUpdates(props);
390
+ for (const update of updates) {
391
+ await this.props.dynamo.send(new UpdateCommand(update.Update));
392
+ }
393
+ };
394
+ buildUpdates = (props) => props.items.map((item) => ({
395
+ Update: this.buildUpdateMembers({
396
+ dimension: props.dimension,
397
+ grain: props.grain,
398
+ periodKey: props.periodKey,
399
+ item,
400
+ ttl: props.ttl
401
+ })
402
+ }));
403
+ getForPeriod = async (props) => {
404
+ const items = await queryAll({
405
+ dynamo: this.props.dynamo,
406
+ input: {
407
+ TableName: this.props.tableName,
408
+ KeyConditionExpression: "#pk = :pk",
409
+ ExpressionAttributeNames: { "#pk": "pk" },
410
+ ExpressionAttributeValues: {
411
+ ":pk": partitionKey2({
412
+ dimension: props.dimension,
413
+ grain: props.grain,
414
+ periodKey: props.periodKey
415
+ })
416
+ }
417
+ }
418
+ });
419
+ return items.map((item) => this.parseOne(item));
420
+ };
421
+ buildUpdateMembers = (props) => {
422
+ const names = {
423
+ "#dimension": "dimension",
424
+ "#grain": "grain",
425
+ "#periodKey": "periodKey",
426
+ "#value": "value",
427
+ "#hits": "hits",
428
+ "#bytes": "bytes"
429
+ };
430
+ const values = {
431
+ ":dimension": props.dimension,
432
+ ":grain": props.grain,
433
+ ":periodKey": props.periodKey,
434
+ ":value": props.item.value,
435
+ ":hits": props.item.hits,
436
+ ":bytes": props.item.bytes
437
+ };
438
+ const setParts = [
439
+ "#dimension = :dimension",
440
+ "#grain = :grain",
441
+ "#periodKey = :periodKey",
442
+ "#value = :value"
443
+ ];
444
+ if (props.ttl != null) {
445
+ names["#ttl"] = "ttl";
446
+ values[":ttl"] = props.ttl;
447
+ setParts.push("#ttl = :ttl");
448
+ }
449
+ return {
450
+ TableName: this.props.tableName,
451
+ Key: {
452
+ pk: partitionKey2({
453
+ dimension: props.dimension,
454
+ grain: props.grain,
455
+ periodKey: props.periodKey
456
+ }),
457
+ sk: props.item.value
458
+ },
459
+ UpdateExpression: `SET ${setParts.join(", ")} ADD #hits :hits, #bytes :bytes`,
460
+ ExpressionAttributeNames: names,
461
+ ExpressionAttributeValues: values
462
+ };
463
+ };
464
+ parseOne = (item) => {
465
+ const result = v2.safeParse(breakdownSchema, item);
466
+ if (!result.success) {
467
+ console.error(v2.flatten(result.issues));
468
+ throw new Error("Malformed stored breakdown record");
469
+ }
470
+ return result.output;
471
+ };
472
+ }
473
+ function partitionKey2(props) {
474
+ return `breakdown#${props.dimension}#${props.grain}#${props.periodKey}`;
475
+ }
476
+ // packages/analytics-processor/src/device.ts
477
+ var botPattern = /bot|crawler|spider|crawl|slurp|mediapartners|facebookexternalhit|bingpreview|duckduckbot|baiduspider|yandex|semrush|ahrefs|headlesschrome|python-requests|curl|wget|monitor|pingdom|uptime/i;
478
+ var mobilePattern = /mobi|android|iphone|ipad|ipod|iemobile|blackberry|opera mini|windows phone|webos/i;
479
+ var desktopPattern = /windows nt|macintosh|mac os x|x11|cros|linux/i;
480
+ function classifyDevice(userAgent) {
481
+ if (userAgent === "")
482
+ return "other";
483
+ if (botPattern.test(userAgent))
484
+ return "bot";
485
+ if (mobilePattern.test(userAgent))
486
+ return "mobile";
487
+ if (desktopPattern.test(userAgent))
488
+ return "desktop";
489
+ return "other";
490
+ }
491
+ // packages/analytics-processor/src/processHour.ts
492
+ import { TransactWriteCommand } from "@aws-sdk/lib-dynamodb";
493
+ import { splitArrayToChunks } from "@beesolve/helpers";
494
+ var transactionLimit = 100;
495
+ var unresolvedCountry = "ZZ";
496
+ async function processHour({
497
+ hourKey,
498
+ source,
499
+ models,
500
+ athena,
501
+ options,
502
+ dynamo
503
+ }) {
504
+ const alreadyApplied = await models.markers.isApplied({ grain: "hour", periodKey: hourKey });
505
+ if (alreadyApplied)
506
+ return { status: "skipped" };
507
+ const query = await runHourlyAthenaQuery({
508
+ athena: athena.client,
509
+ database: athena.database,
510
+ table: athena.table,
511
+ workgroup: athena.workgroup,
512
+ outputLocation: athena.outputLocation,
513
+ source,
514
+ hourKey,
515
+ topPaths: options.topPaths
516
+ });
517
+ const byCountry = await resolveCountryBreakdown({
518
+ topIps: query.topIps,
519
+ ipCache: models.ipCache,
520
+ hasApiKey: options.ipInfoApiKey != null
521
+ });
522
+ const ttl = computeHourlyTtl(options.hourlyTtlDays);
523
+ const markerPut = models.markers.buildMarkerPut({
524
+ grain: "hour",
525
+ periodKey: hourKey,
526
+ source,
527
+ ttl
528
+ });
529
+ const totalsUpdate = models.totals.buildHourlyUpdate({
530
+ item: {
531
+ timeKey: hourKey,
532
+ hits: query.totals.hits,
533
+ success: query.totals.success,
534
+ errors: query.totals.errors,
535
+ errors4xx: query.totals.errors4xx,
536
+ errors5xx: query.totals.errors5xx,
537
+ bytesSent: query.totals.bytesSent,
538
+ bytesReceived: query.totals.bytesReceived,
539
+ p50TimeTaken: query.totals.p50TimeTaken,
540
+ p95TimeTaken: query.totals.p95TimeTaken,
541
+ cacheHitRatio: query.totals.cacheHitRatio,
542
+ uniqueIpCount: query.totals.uniqueIpCount
543
+ },
544
+ ttl
545
+ });
546
+ const breakdownUpdates = buildBreakdownUpdates({
547
+ breakdowns: models.breakdowns,
548
+ grain: "hour",
549
+ periodKey: hourKey,
550
+ ttl,
551
+ byStatus: query.byStatus,
552
+ byDevice: query.byDevice,
553
+ byPath: query.byPath,
554
+ byCountry
555
+ });
556
+ return sendTransacted({
557
+ dynamo,
558
+ leading: [markerPut, totalsUpdate],
559
+ rest: breakdownUpdates
560
+ });
561
+ }
562
+ async function applyDailyRollup({
563
+ dayKey,
564
+ models,
565
+ dynamo
566
+ }) {
567
+ const alreadyApplied = await models.markers.isApplied({ grain: "day", periodKey: dayKey });
568
+ if (alreadyApplied)
569
+ return { status: "skipped" };
570
+ const hourTotals = await models.totals.queryWindow({
571
+ grain: "hour",
572
+ startKey: `${dayKey}-00`,
573
+ endKey: `${dayKey}-23`
574
+ });
575
+ const summed = sumTotals(hourTotals);
576
+ const byDimension = await aggregateFinerBreakdowns({
577
+ breakdowns: models.breakdowns,
578
+ grain: "hour",
579
+ periodKeys: hourWindowKeys(dayKey)
580
+ });
581
+ const totalsUpdate = models.totals.buildAggregateUpdate({
582
+ grain: "day",
583
+ item: { timeKey: dayKey, ...summed }
584
+ });
585
+ const breakdownUpdates = buildBreakdownUpdates({
586
+ breakdowns: models.breakdowns,
587
+ grain: "day",
588
+ periodKey: dayKey,
589
+ byStatus: byDimension.status,
590
+ byDevice: byDimension.device,
591
+ byPath: byDimension.path,
592
+ byCountry: byDimension.country
593
+ });
594
+ const markerPut = models.markers.buildMarkerPut({
595
+ grain: "day",
596
+ periodKey: dayKey,
597
+ source: "v2"
598
+ });
599
+ return sendTransacted({
600
+ dynamo,
601
+ leading: [markerPut, totalsUpdate],
602
+ rest: breakdownUpdates
603
+ });
604
+ }
605
+ async function applyMonthlyRollup({
606
+ monthKey,
607
+ models,
608
+ dynamo
609
+ }) {
610
+ const alreadyApplied = await models.markers.isApplied({ grain: "month", periodKey: monthKey });
611
+ if (alreadyApplied)
612
+ return { status: "skipped" };
613
+ const dayTotals = await models.totals.queryWindow({
614
+ grain: "day",
615
+ startKey: `${monthKey}-01`,
616
+ endKey: `${monthKey}-31`
617
+ });
618
+ const summed = sumTotals(dayTotals);
619
+ const byDimension = await aggregateFinerBreakdowns({
620
+ breakdowns: models.breakdowns,
621
+ grain: "day",
622
+ periodKeys: dayTotals.map((item) => item.timeKey)
623
+ });
624
+ const totalsUpdate = models.totals.buildAggregateUpdate({
625
+ grain: "month",
626
+ item: { timeKey: monthKey, ...summed }
627
+ });
628
+ const breakdownUpdates = buildBreakdownUpdates({
629
+ breakdowns: models.breakdowns,
630
+ grain: "month",
631
+ periodKey: monthKey,
632
+ byStatus: byDimension.status,
633
+ byDevice: byDimension.device,
634
+ byPath: byDimension.path,
635
+ byCountry: byDimension.country
636
+ });
637
+ const markerPut = models.markers.buildMarkerPut({
638
+ grain: "month",
639
+ periodKey: monthKey,
640
+ source: "v2"
641
+ });
642
+ return sendTransacted({
643
+ dynamo,
644
+ leading: [markerPut, totalsUpdate],
645
+ rest: breakdownUpdates
646
+ });
647
+ }
648
+ function chunkTransactItems({
649
+ leading,
650
+ rest,
651
+ limit = transactionLimit
652
+ }) {
653
+ const firstCapacity = Math.max(limit - leading.length, 0);
654
+ const firstChunk = [...leading, ...rest.slice(0, firstCapacity)];
655
+ const tail = splitArrayToChunks(rest.slice(firstCapacity), limit);
656
+ return [firstChunk, ...tail];
657
+ }
658
+ async function sendTransacted({
659
+ dynamo,
660
+ leading,
661
+ rest
662
+ }) {
663
+ const chunks = chunkTransactItems({ leading, rest });
664
+ try {
665
+ for (const chunk of chunks) {
666
+ if (chunk.length === 0)
667
+ continue;
668
+ await dynamo.send(new TransactWriteCommand({ TransactItems: chunk }));
669
+ }
670
+ } catch (error) {
671
+ if (isMarkerRaceError(error))
672
+ return { status: "skipped" };
673
+ throw error;
674
+ }
675
+ return { status: "applied" };
676
+ }
677
+ function isMarkerRaceError(error) {
678
+ if (error == null || typeof error !== "object")
679
+ return false;
680
+ const name = "name" in error ? error.name : undefined;
681
+ return name === "TransactionCanceledException" || name === "ConditionalCheckFailedException";
682
+ }
683
+ function buildBreakdownUpdates({
684
+ breakdowns,
685
+ grain,
686
+ periodKey,
687
+ ttl,
688
+ byStatus,
689
+ byDevice,
690
+ byPath,
691
+ byCountry
692
+ }) {
693
+ const dimensionRows = [
694
+ { dimension: "status", items: byStatus },
695
+ { dimension: "device", items: byDevice },
696
+ { dimension: "country", items: byCountry },
697
+ { dimension: "path", items: byPath }
698
+ ];
699
+ const updates = [];
700
+ for (const row of dimensionRows) {
701
+ if (row.items.length === 0)
702
+ continue;
703
+ updates.push(...breakdowns.buildUpdates({
704
+ dimension: row.dimension,
705
+ grain,
706
+ periodKey,
707
+ items: row.items,
708
+ ttl
709
+ }));
710
+ }
711
+ return updates;
712
+ }
713
+ async function resolveCountryBreakdown({
714
+ topIps,
715
+ ipCache,
716
+ hasApiKey
717
+ }) {
718
+ if (topIps.length === 0)
719
+ return [];
720
+ const resolved = hasApiKey ? await ipCache.enrichMany({ ips: topIps.map((entry) => entry.ip) }) : {};
721
+ const hitsByCountry = {};
722
+ for (const entry of topIps) {
723
+ const info = resolved[entry.ip];
724
+ const country = info?.countryCode ?? unresolvedCountry;
725
+ hitsByCountry[country] = (hitsByCountry[country] ?? 0) + entry.hits;
726
+ }
727
+ return Object.entries(hitsByCountry).map(([country, hits]) => ({
728
+ value: country,
729
+ hits,
730
+ bytes: 0
731
+ }));
732
+ }
733
+ async function aggregateFinerBreakdowns({
734
+ breakdowns,
735
+ grain,
736
+ periodKeys
737
+ }) {
738
+ const status = [];
739
+ const device = [];
740
+ const path = [];
741
+ const country = [];
742
+ for (const periodKey of periodKeys) {
743
+ const [statusItems, deviceItems, pathItems, countryItems] = await Promise.all([
744
+ breakdowns.getForPeriod({ dimension: "status", grain, periodKey }),
745
+ breakdowns.getForPeriod({ dimension: "device", grain, periodKey }),
746
+ breakdowns.getForPeriod({ dimension: "path", grain, periodKey }),
747
+ breakdowns.getForPeriod({ dimension: "country", grain, periodKey })
748
+ ]);
749
+ status.push(...statusItems.map(toBreakdownRow));
750
+ device.push(...deviceItems.map(toBreakdownRow));
751
+ path.push(...pathItems.map(toBreakdownRow));
752
+ country.push(...countryItems.map(toBreakdownRow));
753
+ }
754
+ return {
755
+ status: sumBreakdown(status),
756
+ device: sumBreakdown(device),
757
+ path: sumBreakdown(path),
758
+ country: sumBreakdown(country)
759
+ };
760
+ }
761
+ function hourWindowKeys(dayKey) {
762
+ const keys = [];
763
+ for (let hour = 0;hour < 24; hour += 1) {
764
+ keys.push(`${dayKey}-${hour.toString().padStart(2, "0")}`);
765
+ }
766
+ return keys;
767
+ }
768
+ function computeHourlyTtl(hourlyTtlDays) {
769
+ const nowSeconds = Math.floor(Date.now() / 1000);
770
+ return nowSeconds + hourlyTtlDays * 24 * 60 * 60;
771
+ }
772
+ function toBreakdownRow(item) {
773
+ return { value: item.value, hits: item.hits, bytes: item.bytes };
774
+ }
775
+ // packages/analytics-processor/src/time.ts
776
+ function pad2(value) {
777
+ return value.toString().padStart(2, "0");
778
+ }
779
+ function pad4(value) {
780
+ return value.toString().padStart(4, "0");
781
+ }
782
+ function yearKey(date) {
783
+ return pad4(date.getUTCFullYear());
784
+ }
785
+ function monthKey(date) {
786
+ return `${pad4(date.getUTCFullYear())}-${pad2(date.getUTCMonth() + 1)}`;
787
+ }
788
+ function dayKey(date) {
789
+ return `${monthKey(date)}-${pad2(date.getUTCDate())}`;
790
+ }
791
+ function hourKey(date) {
792
+ return `${dayKey(date)}-${pad2(date.getUTCHours())}`;
793
+ }
794
+ function maxWindowFor(grain) {
795
+ if (grain === "hour")
796
+ return 24;
797
+ if (grain === "day")
798
+ return 30;
799
+ return 12;
800
+ }
801
+ function keyFor(grain, date) {
802
+ if (grain === "hour")
803
+ return hourKey(date);
804
+ if (grain === "day")
805
+ return dayKey(date);
806
+ return monthKey(date);
807
+ }
808
+ function shiftAnchor({
809
+ grain,
810
+ anchor,
811
+ size,
812
+ direction
813
+ }) {
814
+ const delta = direction === "next" ? size : -size;
815
+ const shifted = new Date(anchor.getTime());
816
+ if (grain === "hour") {
817
+ shifted.setUTCHours(shifted.getUTCHours() + delta);
818
+ } else if (grain === "day") {
819
+ shifted.setUTCDate(shifted.getUTCDate() + delta);
820
+ } else {
821
+ shifted.setUTCMonth(shifted.getUTCMonth() + delta);
822
+ }
823
+ return shifted;
824
+ }
825
+ function windowKeys({ grain, anchor, size }) {
826
+ const endKey = keyFor(grain, anchor);
827
+ const start = shiftAnchor({ grain, anchor, size: size - 1, direction: "prev" });
828
+ const startKey = keyFor(grain, start);
829
+ return { startKey, endKey };
830
+ }
831
+ function hoursBetween({ from, to }) {
832
+ const keys = [];
833
+ const cursor = new Date(Date.UTC(from.getUTCFullYear(), from.getUTCMonth(), from.getUTCDate(), from.getUTCHours()));
834
+ const end = Date.UTC(to.getUTCFullYear(), to.getUTCMonth(), to.getUTCDate(), to.getUTCHours());
835
+ while (cursor.getTime() <= end) {
836
+ keys.push(hourKey(cursor));
837
+ cursor.setUTCHours(cursor.getUTCHours() + 1);
838
+ }
839
+ return keys;
840
+ }
841
+ // packages/analytics-processor/src/totals.ts
842
+ import { GetCommand as GetCommand2, UpdateCommand as UpdateCommand2 } from "@aws-sdk/lib-dynamodb";
843
+ import { queryAll as queryAll2 } from "@beesolve/dynamo-helpers";
844
+ import * as v3 from "valibot";
845
+ var additiveFields = [
846
+ "hits",
847
+ "success",
848
+ "errors",
849
+ "errors4xx",
850
+ "errors5xx",
851
+ "bytesSent",
852
+ "bytesReceived"
853
+ ];
854
+ var hourlyDetailFields = [
855
+ "p50TimeTaken",
856
+ "p95TimeTaken",
857
+ "cacheHitRatio",
858
+ "uniqueIpCount"
859
+ ];
860
+ var totalsSchema = v3.object({
861
+ pk: v3.string(),
862
+ sk: v3.string(),
863
+ grain: v3.picklist(grains),
864
+ timeKey: v3.string(),
865
+ hits: v3.number(),
866
+ success: v3.number(),
867
+ errors: v3.number(),
868
+ errors4xx: v3.number(),
869
+ errors5xx: v3.number(),
870
+ bytesSent: v3.number(),
871
+ bytesReceived: v3.number(),
872
+ p50TimeTaken: v3.optional(v3.number()),
873
+ p95TimeTaken: v3.optional(v3.number()),
874
+ cacheHitRatio: v3.optional(v3.number()),
875
+ uniqueIpCount: v3.optional(v3.number()),
876
+ ttl: v3.optional(v3.number())
877
+ });
878
+
879
+ class Totals {
880
+ props;
881
+ constructor(props) {
882
+ this.props = props;
883
+ }
884
+ addHourly = async (props) => {
885
+ const update = this.buildHourlyUpdate(props);
886
+ await this.props.dynamo.send(new UpdateCommand2(update.Update));
887
+ };
888
+ addAggregate = async (props) => {
889
+ const update = this.buildAggregateUpdate(props);
890
+ await this.props.dynamo.send(new UpdateCommand2(update.Update));
891
+ };
892
+ buildHourlyUpdate = (props) => ({
893
+ Update: this.buildUpdateMembers({
894
+ grain: "hour",
895
+ item: props.item,
896
+ ttl: props.ttl,
897
+ includeHourlyDetail: true
898
+ })
899
+ });
900
+ buildAggregateUpdate = (props) => ({
901
+ Update: this.buildUpdateMembers({
902
+ grain: props.grain,
903
+ item: props.item,
904
+ includeHourlyDetail: false
905
+ })
906
+ });
907
+ queryWindow = async (props) => {
908
+ const items = await queryAll2({
909
+ dynamo: this.props.dynamo,
910
+ input: {
911
+ TableName: this.props.tableName,
912
+ KeyConditionExpression: "#pk = :pk AND #sk BETWEEN :start AND :end",
913
+ ExpressionAttributeNames: { "#pk": "pk", "#sk": "sk" },
914
+ ExpressionAttributeValues: {
915
+ ":pk": partitionKey3(props.grain),
916
+ ":start": props.startKey,
917
+ ":end": props.endKey
918
+ }
919
+ }
920
+ });
921
+ return items.map((item) => this.parseOne(item));
922
+ };
923
+ getOne = async (props) => {
924
+ const { Item: item } = await this.props.dynamo.send(new GetCommand2({
925
+ TableName: this.props.tableName,
926
+ Key: { pk: partitionKey3(props.grain), sk: props.timeKey }
927
+ }));
928
+ if (item == null)
929
+ return;
930
+ return this.parseOne(item);
931
+ };
932
+ buildUpdateMembers = (props) => {
933
+ const names = { "#grain": "grain", "#timeKey": "timeKey" };
934
+ const values = {
935
+ ":grain": props.grain,
936
+ ":timeKey": props.item.timeKey
937
+ };
938
+ const setParts = ["#grain = :grain", "#timeKey = :timeKey"];
939
+ const addParts = [];
940
+ for (const field of additiveFields) {
941
+ names[`#${field}`] = field;
942
+ values[`:${field}`] = props.item[field];
943
+ addParts.push(`#${field} :${field}`);
944
+ }
945
+ if (props.includeHourlyDetail) {
946
+ for (const field of hourlyDetailFields) {
947
+ const value = props.item[field];
948
+ if (value == null)
949
+ continue;
950
+ names[`#${field}`] = field;
951
+ values[`:${field}`] = value;
952
+ setParts.push(`#${field} = :${field}`);
953
+ }
954
+ }
955
+ if (props.ttl != null) {
956
+ names["#ttl"] = "ttl";
957
+ values[":ttl"] = props.ttl;
958
+ setParts.push("#ttl = :ttl");
959
+ }
960
+ return {
961
+ TableName: this.props.tableName,
962
+ Key: { pk: partitionKey3(props.grain), sk: props.item.timeKey },
963
+ UpdateExpression: `SET ${setParts.join(", ")} ADD ${addParts.join(", ")}`,
964
+ ExpressionAttributeNames: names,
965
+ ExpressionAttributeValues: values
966
+ };
967
+ };
968
+ parseOne = (item) => {
969
+ const result = v3.safeParse(totalsSchema, item);
970
+ if (!result.success) {
971
+ console.error(v3.flatten(result.issues));
972
+ throw new Error("Malformed stored totals record");
973
+ }
974
+ return result.output;
975
+ };
976
+ }
977
+ function partitionKey3(grain) {
978
+ return `totals#${grain}`;
979
+ }
980
+ export {
981
+ AppliedMarkers,
982
+ Breakdowns,
983
+ Totals,
984
+ appliedMarkerSchema,
985
+ appliedSources,
986
+ applyDailyRollup,
987
+ applyMonthlyRollup,
988
+ breakdownSchema,
989
+ buildHourlyQuery,
990
+ chunkTransactItems,
991
+ classifyDevice,
992
+ columnMaps,
993
+ dayKey,
994
+ dimensions,
995
+ grains,
996
+ hourKey,
997
+ hourKeyParts,
998
+ hoursBetween,
999
+ maxWindowFor,
1000
+ monthKey,
1001
+ processHour,
1002
+ requiredRecordFields,
1003
+ runHourlyAthenaQuery,
1004
+ shiftAnchor,
1005
+ sumBreakdown,
1006
+ sumTotals,
1007
+ topNWithOther,
1008
+ totalsSchema,
1009
+ windowKeys,
1010
+ yearKey
1011
+ };