@firestone-hs/bgs-global-stats 1.0.53 → 1.0.55

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 (159) hide show
  1. package/dist/common/anomalies.js +4 -3
  2. package/dist/common/anomalies.js.map +1 -1
  3. package/dist/common/performance-analyzer.d.ts +12 -0
  4. package/dist/common/performance-analyzer.js +52 -0
  5. package/dist/common/performance-analyzer.js.map +1 -0
  6. package/dist/duos/final-stats/config.js.map +1 -0
  7. package/dist/duos/{aggregate-hourly → final-stats}/heroes/_build-aggregated-stats.js +35 -31
  8. package/dist/duos/final-stats/heroes/_build-aggregated-stats.js.map +1 -0
  9. package/dist/duos/final-stats/heroes/s3-saver.js.map +1 -0
  10. package/dist/duos/{aggregate-hourly → final-stats}/heroes/stats-merger.js +3 -24
  11. package/dist/duos/final-stats/heroes/stats-merger.js.map +1 -0
  12. package/dist/duos/final-stats/hourly-utils.js.map +1 -0
  13. package/dist/duos/final-stats/percentiles.js.map +1 -0
  14. package/dist/duos/final-stats/s3-loader.js.map +1 -0
  15. package/dist/duos/hourly/_build-battlegrounds-hero-stats.js +19 -29
  16. package/dist/duos/hourly/_build-battlegrounds-hero-stats.js.map +1 -1
  17. package/dist/duos/hourly/hero-stats-buikder.js +2 -2
  18. package/dist/duos/hourly/hero-stats-buikder.js.map +1 -1
  19. package/dist/duos/hourly/rows.js +4 -4
  20. package/dist/duos/hourly/rows.js.map +1 -1
  21. package/dist/duos/hourly/utils.js +1 -1
  22. package/dist/duos/hourly/utils.js.map +1 -1
  23. package/dist/internal-model.d.ts +12 -0
  24. package/dist/internal-model.js.map +1 -1
  25. package/dist/model-comps.d.ts +20 -0
  26. package/dist/model-comps.js.map +1 -1
  27. package/dist/models.d.ts +1 -4
  28. package/dist/models.js.map +1 -1
  29. package/dist/solo/aggregate-daily/cards/_build-aggregated-stats.js +9 -13
  30. package/dist/solo/aggregate-daily/cards/_build-aggregated-stats.js.map +1 -1
  31. package/dist/solo/aggregate-daily/cards/s3-saver.js +1 -1
  32. package/dist/solo/aggregate-daily/cards/s3-saver.js.map +1 -1
  33. package/dist/solo/aggregate-daily/cards/stats-builder.js +2 -2
  34. package/dist/solo/aggregate-daily/cards/stats-builder.js.map +1 -1
  35. package/dist/solo/aggregate-daily/heroes/_build-aggregated-stats.js +115 -0
  36. package/dist/solo/aggregate-daily/heroes/_build-aggregated-stats.js.map +1 -0
  37. package/dist/solo/aggregate-daily/heroes/s3-saver.d.ts +2 -0
  38. package/dist/solo/aggregate-daily/heroes/s3-saver.js +24 -0
  39. package/dist/solo/aggregate-daily/heroes/s3-saver.js.map +1 -0
  40. package/dist/solo/final-stats/cards/_build-aggregated-stats.js +11 -29
  41. package/dist/solo/final-stats/cards/_build-aggregated-stats.js.map +1 -1
  42. package/dist/solo/final-stats/cards/s3-saver.js +1 -5
  43. package/dist/solo/final-stats/cards/s3-saver.js.map +1 -1
  44. package/dist/solo/final-stats/cards/stats-builder.js +5 -3
  45. package/dist/solo/final-stats/cards/stats-builder.js.map +1 -1
  46. package/dist/solo/{aggregate-hourly → final-stats}/comps/_build-aggregated-stats.js +19 -23
  47. package/dist/solo/final-stats/comps/_build-aggregated-stats.js.map +1 -0
  48. package/dist/solo/final-stats/comps/s3-saver.js.map +1 -0
  49. package/dist/solo/final-stats/comps/stats-builder.js +88 -0
  50. package/dist/solo/final-stats/comps/stats-builder.js.map +1 -0
  51. package/dist/solo/{aggregate-hourly → final-stats}/config.js +1 -1
  52. package/dist/solo/final-stats/config.js.map +1 -0
  53. package/dist/solo/{aggregate-hourly → final-stats}/heroes/_build-aggregated-stats.js +30 -34
  54. package/dist/solo/final-stats/heroes/_build-aggregated-stats.js.map +1 -0
  55. package/dist/solo/final-stats/heroes/s3-saver.js.map +1 -0
  56. package/dist/solo/{aggregate-hourly → final-stats}/heroes/stats-merger.d.ts +5 -0
  57. package/dist/solo/{aggregate-hourly → final-stats}/heroes/stats-merger.js +6 -5
  58. package/dist/solo/final-stats/heroes/stats-merger.js.map +1 -0
  59. package/dist/solo/final-stats/hourly-utils.js.map +1 -0
  60. package/dist/solo/final-stats/percentiles.js.map +1 -0
  61. package/dist/solo/final-stats/quests/_build-aggregated-stats.d.ts +5 -0
  62. package/dist/solo/{aggregate-hourly → final-stats}/quests/_build-aggregated-stats.js +13 -24
  63. package/dist/solo/final-stats/quests/_build-aggregated-stats.js.map +1 -0
  64. package/dist/solo/{aggregate-hourly → final-stats}/quests/quest-stats-merger.js +4 -4
  65. package/dist/solo/final-stats/quests/quest-stats-merger.js.map +1 -0
  66. package/dist/solo/{aggregate-hourly → final-stats}/quests/reward-stats-merger.js +3 -3
  67. package/dist/solo/final-stats/quests/reward-stats-merger.js.map +1 -0
  68. package/dist/solo/final-stats/quests/s3-saver.js.map +1 -0
  69. package/dist/solo/{aggregate-hourly → final-stats}/s3-loader.d.ts +1 -1
  70. package/dist/solo/{aggregate-hourly → final-stats}/s3-loader.js +22 -17
  71. package/dist/solo/final-stats/s3-loader.js.map +1 -0
  72. package/dist/solo/{aggregate-hourly → final-stats}/trinkets/_build-aggregated-stats.js +8 -18
  73. package/dist/solo/final-stats/trinkets/_build-aggregated-stats.js.map +1 -0
  74. package/dist/solo/final-stats/trinkets/s3-saver.js.map +1 -0
  75. package/dist/solo/{aggregate-hourly → final-stats}/trinkets/stats-builder.js +1 -1
  76. package/dist/solo/final-stats/trinkets/stats-builder.js.map +1 -0
  77. package/dist/solo/hourly/_build-battlegrounds-hero-stats.js +39 -56
  78. package/dist/solo/hourly/_build-battlegrounds-hero-stats.js.map +1 -1
  79. package/dist/solo/hourly/cards/card-stats-builder.js +8 -11
  80. package/dist/solo/hourly/cards/card-stats-builder.js.map +1 -1
  81. package/dist/solo/hourly/cards/card-stats.js +0 -5
  82. package/dist/solo/hourly/cards/card-stats.js.map +1 -1
  83. package/dist/solo/hourly/comps/comp-stats-builder.d.ts +2 -1
  84. package/dist/solo/hourly/comps/comp-stats-builder.js +58 -11
  85. package/dist/solo/hourly/comps/comp-stats-builder.js.map +1 -1
  86. package/dist/solo/hourly/comps/comp-stats.d.ts +2 -1
  87. package/dist/solo/hourly/comps/comp-stats.js +4 -2
  88. package/dist/solo/hourly/comps/comp-stats.js.map +1 -1
  89. package/dist/solo/hourly/hero-stats-buikder.js +2 -2
  90. package/dist/solo/hourly/hero-stats-buikder.js.map +1 -1
  91. package/dist/solo/hourly/quests/quest-stats-buikder.js +3 -3
  92. package/dist/solo/hourly/quests/quest-stats-buikder.js.map +1 -1
  93. package/dist/solo/hourly/quests/reward-stats-builder.js +2 -2
  94. package/dist/solo/hourly/quests/reward-stats-builder.js.map +1 -1
  95. package/dist/solo/hourly/rows.js +17 -16
  96. package/dist/solo/hourly/rows.js.map +1 -1
  97. package/dist/solo/hourly/trinkets/trinket-stats-builder.js +2 -4
  98. package/dist/solo/hourly/trinkets/trinket-stats-builder.js.map +1 -1
  99. package/dist/solo/hourly/utils.js +1 -1
  100. package/dist/solo/hourly/utils.js.map +1 -1
  101. package/package.json +7 -3
  102. package/dist/duos/aggregate-hourly/config.js.map +0 -1
  103. package/dist/duos/aggregate-hourly/heroes/_build-aggregated-stats.js.map +0 -1
  104. package/dist/duos/aggregate-hourly/heroes/s3-saver.js.map +0 -1
  105. package/dist/duos/aggregate-hourly/heroes/stats-merger.js.map +0 -1
  106. package/dist/duos/aggregate-hourly/hourly-utils.js.map +0 -1
  107. package/dist/duos/aggregate-hourly/percentiles.js.map +0 -1
  108. package/dist/duos/aggregate-hourly/s3-loader.js.map +0 -1
  109. package/dist/solo/aggregate-hourly/comps/_build-aggregated-stats.js.map +0 -1
  110. package/dist/solo/aggregate-hourly/comps/s3-saver.js.map +0 -1
  111. package/dist/solo/aggregate-hourly/comps/stats-builder.js +0 -32
  112. package/dist/solo/aggregate-hourly/comps/stats-builder.js.map +0 -1
  113. package/dist/solo/aggregate-hourly/config.js.map +0 -1
  114. package/dist/solo/aggregate-hourly/heroes/_build-aggregated-stats.js.map +0 -1
  115. package/dist/solo/aggregate-hourly/heroes/s3-saver.js.map +0 -1
  116. package/dist/solo/aggregate-hourly/heroes/stats-merger.js.map +0 -1
  117. package/dist/solo/aggregate-hourly/hourly-utils.js.map +0 -1
  118. package/dist/solo/aggregate-hourly/percentiles.js.map +0 -1
  119. package/dist/solo/aggregate-hourly/quests/_build-aggregated-stats.js.map +0 -1
  120. package/dist/solo/aggregate-hourly/quests/quest-stats-merger.js.map +0 -1
  121. package/dist/solo/aggregate-hourly/quests/reward-stats-merger.js.map +0 -1
  122. package/dist/solo/aggregate-hourly/quests/s3-saver.js.map +0 -1
  123. package/dist/solo/aggregate-hourly/s3-loader.js.map +0 -1
  124. package/dist/solo/aggregate-hourly/trinkets/_build-aggregated-stats.js.map +0 -1
  125. package/dist/solo/aggregate-hourly/trinkets/s3-saver.js.map +0 -1
  126. package/dist/solo/aggregate-hourly/trinkets/stats-builder.js.map +0 -1
  127. /package/dist/duos/{aggregate-hourly → final-stats}/config.d.ts +0 -0
  128. /package/dist/duos/{aggregate-hourly → final-stats}/config.js +0 -0
  129. /package/dist/duos/{aggregate-hourly → final-stats}/heroes/_build-aggregated-stats.d.ts +0 -0
  130. /package/dist/duos/{aggregate-hourly → final-stats}/heroes/s3-saver.d.ts +0 -0
  131. /package/dist/duos/{aggregate-hourly → final-stats}/heroes/s3-saver.js +0 -0
  132. /package/dist/duos/{aggregate-hourly → final-stats}/heroes/stats-merger.d.ts +0 -0
  133. /package/dist/duos/{aggregate-hourly → final-stats}/hourly-utils.d.ts +0 -0
  134. /package/dist/duos/{aggregate-hourly → final-stats}/hourly-utils.js +0 -0
  135. /package/dist/duos/{aggregate-hourly → final-stats}/percentiles.d.ts +0 -0
  136. /package/dist/duos/{aggregate-hourly → final-stats}/percentiles.js +0 -0
  137. /package/dist/duos/{aggregate-hourly → final-stats}/s3-loader.d.ts +0 -0
  138. /package/dist/duos/{aggregate-hourly → final-stats}/s3-loader.js +0 -0
  139. /package/dist/solo/{aggregate-hourly → aggregate-daily}/heroes/_build-aggregated-stats.d.ts +0 -0
  140. /package/dist/solo/{aggregate-hourly → final-stats}/comps/_build-aggregated-stats.d.ts +0 -0
  141. /package/dist/solo/{aggregate-hourly → final-stats}/comps/s3-saver.d.ts +0 -0
  142. /package/dist/solo/{aggregate-hourly → final-stats}/comps/s3-saver.js +0 -0
  143. /package/dist/solo/{aggregate-hourly → final-stats}/comps/stats-builder.d.ts +0 -0
  144. /package/dist/solo/{aggregate-hourly → final-stats}/config.d.ts +0 -0
  145. /package/dist/solo/{aggregate-hourly/quests → final-stats/heroes}/_build-aggregated-stats.d.ts +0 -0
  146. /package/dist/solo/{aggregate-hourly → final-stats}/heroes/s3-saver.d.ts +0 -0
  147. /package/dist/solo/{aggregate-hourly → final-stats}/heroes/s3-saver.js +0 -0
  148. /package/dist/solo/{aggregate-hourly → final-stats}/hourly-utils.d.ts +0 -0
  149. /package/dist/solo/{aggregate-hourly → final-stats}/hourly-utils.js +0 -0
  150. /package/dist/solo/{aggregate-hourly → final-stats}/percentiles.d.ts +0 -0
  151. /package/dist/solo/{aggregate-hourly → final-stats}/percentiles.js +0 -0
  152. /package/dist/solo/{aggregate-hourly → final-stats}/quests/quest-stats-merger.d.ts +0 -0
  153. /package/dist/solo/{aggregate-hourly → final-stats}/quests/reward-stats-merger.d.ts +0 -0
  154. /package/dist/solo/{aggregate-hourly → final-stats}/quests/s3-saver.d.ts +0 -0
  155. /package/dist/solo/{aggregate-hourly → final-stats}/quests/s3-saver.js +0 -0
  156. /package/dist/solo/{aggregate-hourly → final-stats}/trinkets/_build-aggregated-stats.d.ts +0 -0
  157. /package/dist/solo/{aggregate-hourly → final-stats}/trinkets/s3-saver.d.ts +0 -0
  158. /package/dist/solo/{aggregate-hourly → final-stats}/trinkets/s3-saver.js +0 -0
  159. /package/dist/solo/{aggregate-hourly → final-stats}/trinkets/stats-builder.d.ts +0 -0
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.readAllAnomalies = void 0;
4
- const aws_sdk_1 = require("aws-sdk");
5
- const s3 = new aws_sdk_1.S3();
4
+ const client_s3_1 = require("@aws-sdk/client-s3");
5
+ const s3 = new client_s3_1.S3();
6
6
  const readAllAnomalies = async (bucket, folder) => {
7
7
  var _a, _b;
8
8
  const params = {
@@ -16,7 +16,8 @@ const readAllAnomalies = async (bucket, folder) => {
16
16
  params.ContinuationToken = continuationToken;
17
17
  }
18
18
  try {
19
- const data = await s3.listObjectsV2(params).promise();
19
+ const command = new client_s3_1.ListObjectsV2Command(params);
20
+ const data = await s3.send(command);
20
21
  const allKeysForToken = (_b = (_a = data.Contents) === null || _a === void 0 ? void 0 : _a.map((item) => item.Key)) !== null && _b !== void 0 ? _b : [];
21
22
  const suffixes = allKeysForToken.map((key) => key.replace(`${folder}/`, ''));
22
23
  const anomalies = suffixes.map((suffix) => suffix.split('/')[0]);
@@ -1 +1 @@
1
- {"version":3,"file":"anomalies.js","sourceRoot":"","sources":["../../src/common/anomalies.ts"],"names":[],"mappings":";;;AAAA,qCAA6B;AAE7B,MAAM,EAAE,GAAG,IAAI,YAAE,EAAE,CAAC;AAEb,MAAM,gBAAgB,GAAG,KAAK,EAAE,MAAc,EAAE,MAAc,EAAuC,EAAE;;IAC7G,MAAM,MAAM,GAAkC;QAC7C,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,MAAM;KACd,CAAC;IACF,IAAI,OAAO,GAAa,EAAE,CAAC;IAC3B,IAAI,iBAAqC,CAAC;IAE1C,GAAG;QACF,IAAI,iBAAiB,EAAE;YACtB,MAAM,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;SAC7C;QAED,IAAI;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC;YAEtD,MAAM,eAAe,GAAG,MAAA,MAAA,IAAI,CAAC,QAAQ,0CAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,mCAAI,EAAE,CAAC;YACrE,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,MAAM,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;YAC7E,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACjE,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;YAEhD,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;YAC1C,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAC;SAC9E;QAAC,OAAO,KAAK,EAAE;YACf,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;YAC7C,OAAO,CAAC,IAAI,CAAC,CAAC;SACd;KACD,QAAQ,iBAAiB,EAAE;IAE5B,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAEzC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,GAAG,UAAU,CAAC,CAAC;IAErC,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAlCW,QAAA,gBAAgB,oBAkC3B","sourcesContent":["import { S3 } from 'aws-sdk';\r\n\r\nconst s3 = new S3();\r\n\r\nexport const readAllAnomalies = async (bucket: string, folder: string): Promise<readonly (string | null)[]> => {\r\n\tconst params: S3.Types.ListObjectsV2Request = {\r\n\t\tBucket: bucket,\r\n\t\tPrefix: folder,\r\n\t};\r\n\tlet allKeys: string[] = [];\r\n\tlet continuationToken: string | undefined;\r\n\r\n\tdo {\r\n\t\tif (continuationToken) {\r\n\t\t\tparams.ContinuationToken = continuationToken;\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tconst data = await s3.listObjectsV2(params).promise();\r\n\t\t\t// console.debug('listing result', params.ContinuationToken, data.Contents);\r\n\t\t\tconst allKeysForToken = data.Contents?.map((item) => item.Key) ?? [];\r\n\t\t\tconst suffixes = allKeysForToken.map((key) => key.replace(`${folder}/`, ''));\r\n\t\t\tconst anomalies = suffixes.map((suffix) => suffix.split('/')[0]);\r\n\t\t\tconst uniqueAnomalies = [...new Set(anomalies)];\r\n\t\t\t// console.debug('uniqueAnomalies', uniqueAnomalies);\r\n\t\t\tallKeys = allKeys.concat(uniqueAnomalies);\r\n\t\t\tcontinuationToken = data.IsTruncated ? data.NextContinuationToken : undefined;\r\n\t\t} catch (error) {\r\n\t\t\tconsole.error('Error listing files:', error);\r\n\t\t\treturn [null];\r\n\t\t}\r\n\t} while (continuationToken);\r\n\r\n\tconst uniqueKeys = [...new Set(allKeys)];\r\n\t// console.debug('uniqueKeys', uniqueKeys);\r\n\tconst result = [null, ...uniqueKeys];\r\n\t// console.debug('listing anomalies', bucket, folder, result);\r\n\treturn result;\r\n};\r\n"]}
1
+ {"version":3,"file":"anomalies.js","sourceRoot":"","sources":["../../src/common/anomalies.ts"],"names":[],"mappings":";;;AAAA,kDAAqH;AAErH,MAAM,EAAE,GAAG,IAAI,cAAE,EAAE,CAAC;AAEb,MAAM,gBAAgB,GAAG,KAAK,EAAE,MAAc,EAAE,MAAc,EAAuC,EAAE;;IAC7G,MAAM,MAAM,GAA8B;QACzC,MAAM,EAAE,MAAM;QACd,MAAM,EAAE,MAAM;KACd,CAAC;IACF,IAAI,OAAO,GAAa,EAAE,CAAC;IAC3B,IAAI,iBAAqC,CAAC;IAE1C,GAAG;QACF,IAAI,iBAAiB,EAAE;YACtB,MAAM,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;SAC7C;QAED,IAAI;YACH,MAAM,OAAO,GAAG,IAAI,gCAAoB,CAAC,MAAM,CAAC,CAAC;YACjD,MAAM,IAAI,GAA+B,MAAM,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEhE,MAAM,eAAe,GAAG,MAAA,MAAA,IAAI,CAAC,QAAQ,0CAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,mCAAI,EAAE,CAAC;YACrE,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,MAAM,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;YAC7E,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACjE,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;YAEhD,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;YAC1C,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,SAAS,CAAC;SAC9E;QAAC,OAAO,KAAK,EAAE;YACf,OAAO,CAAC,KAAK,CAAC,sBAAsB,EAAE,KAAK,CAAC,CAAC;YAC7C,OAAO,CAAC,IAAI,CAAC,CAAC;SACd;KACD,QAAQ,iBAAiB,EAAE;IAE5B,MAAM,UAAU,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAEzC,MAAM,MAAM,GAAG,CAAC,IAAI,EAAE,GAAG,UAAU,CAAC,CAAC;IAErC,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAnCW,QAAA,gBAAgB,oBAmC3B","sourcesContent":["import { ListObjectsV2Command, ListObjectsV2CommandInput, ListObjectsV2CommandOutput, S3 } from '@aws-sdk/client-s3';\r\n\r\nconst s3 = new S3();\r\n\r\nexport const readAllAnomalies = async (bucket: string, folder: string): Promise<readonly (string | null)[]> => {\r\n\tconst params: ListObjectsV2CommandInput = {\r\n\t\tBucket: bucket,\r\n\t\tPrefix: folder,\r\n\t};\r\n\tlet allKeys: string[] = [];\r\n\tlet continuationToken: string | undefined;\r\n\r\n\tdo {\r\n\t\tif (continuationToken) {\r\n\t\t\tparams.ContinuationToken = continuationToken;\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tconst command = new ListObjectsV2Command(params);\r\n\t\t\tconst data: ListObjectsV2CommandOutput = await s3.send(command);\r\n\t\t\t// console.debug('listing result', params.ContinuationToken, data.Contents);\r\n\t\t\tconst allKeysForToken = data.Contents?.map((item) => item.Key) ?? [];\r\n\t\t\tconst suffixes = allKeysForToken.map((key) => key.replace(`${folder}/`, ''));\r\n\t\t\tconst anomalies = suffixes.map((suffix) => suffix.split('/')[0]);\r\n\t\t\tconst uniqueAnomalies = [...new Set(anomalies)];\r\n\t\t\t// console.debug('uniqueAnomalies', uniqueAnomalies);\r\n\t\t\tallKeys = allKeys.concat(uniqueAnomalies);\r\n\t\t\tcontinuationToken = data.IsTruncated ? data.NextContinuationToken : undefined;\r\n\t\t} catch (error) {\r\n\t\t\tconsole.error('Error listing files:', error);\r\n\t\t\treturn [null];\r\n\t\t}\r\n\t} while (continuationToken);\r\n\r\n\tconst uniqueKeys = [...new Set(allKeys)];\r\n\t// console.debug('uniqueKeys', uniqueKeys);\r\n\tconst result = [null, ...uniqueKeys];\r\n\t// console.debug('listing anomalies', bucket, folder, result);\r\n\treturn result;\r\n};\r\n"]}
@@ -0,0 +1,12 @@
1
+ export declare class PerformanceAnalyzer {
2
+ private timers;
3
+ private results;
4
+ startTimer(name: string): void;
5
+ endTimer(name: string): number;
6
+ getResults(): {
7
+ [key: string]: number;
8
+ };
9
+ logSummary(): void;
10
+ private getTotalTime;
11
+ }
12
+ export declare const perf: PerformanceAnalyzer;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.perf = exports.PerformanceAnalyzer = void 0;
4
+ const perf_hooks_1 = require("perf_hooks");
5
+ class PerformanceAnalyzer {
6
+ constructor() {
7
+ this.timers = new Map();
8
+ this.results = new Map();
9
+ }
10
+ startTimer(name) {
11
+ this.timers.set(name, perf_hooks_1.performance.now());
12
+ }
13
+ endTimer(name) {
14
+ return 0;
15
+ const startTime = this.timers.get(name);
16
+ if (!startTime) {
17
+ console.warn(`Timer ${name} was not started`);
18
+ return 0;
19
+ }
20
+ const duration = perf_hooks_1.performance.now() - startTime;
21
+ this.results.set(name, duration);
22
+ this.timers.delete(name);
23
+ console.log(`⏱️ ${name}: ${duration.toFixed(2)}ms`);
24
+ return duration;
25
+ }
26
+ getResults() {
27
+ return Object.fromEntries(this.results);
28
+ }
29
+ logSummary() {
30
+ return;
31
+ console.log('\n📊 Performance Summary:');
32
+ console.log('========================');
33
+ const sorted = Array.from(this.results.entries())
34
+ .sort((a, b) => b[1] - a[1])
35
+ .map(([name, duration]) => ({
36
+ name,
37
+ duration: duration.toFixed(2),
38
+ percentage: ((duration / this.getTotalTime()) * 100).toFixed(1),
39
+ }));
40
+ sorted.forEach(({ name, duration, percentage }) => {
41
+ console.log(`${name.padEnd(30)} ${duration}ms (${percentage}%)`);
42
+ });
43
+ console.log(`${'TOTAL'.padEnd(30)} ${this.getTotalTime().toFixed(2)}ms`);
44
+ console.log('========================\n');
45
+ }
46
+ getTotalTime() {
47
+ return Array.from(this.results.values()).reduce((sum, duration) => sum + duration, 0);
48
+ }
49
+ }
50
+ exports.PerformanceAnalyzer = PerformanceAnalyzer;
51
+ exports.perf = new PerformanceAnalyzer();
52
+ //# sourceMappingURL=performance-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"performance-analyzer.js","sourceRoot":"","sources":["../../src/common/performance-analyzer.ts"],"names":[],"mappings":";;;AAAA,2CAAyC;AAEzC,MAAa,mBAAmB;IAAhC;QACS,WAAM,GAAwB,IAAI,GAAG,EAAE,CAAC;QACxC,YAAO,GAAwB,IAAI,GAAG,EAAE,CAAC;IAkDlD,CAAC;IAhDA,UAAU,CAAC,IAAY;QACtB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,wBAAW,CAAC,GAAG,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,QAAQ,CAAC,IAAY;QACpB,OAAO,CAAC,CAAC;QACT,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,SAAS,EAAE;YACf,OAAO,CAAC,IAAI,CAAC,SAAS,IAAI,kBAAkB,CAAC,CAAC;YAC9C,OAAO,CAAC,CAAC;SACT;QAED,MAAM,QAAQ,GAAG,wBAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QAC/C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACjC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAEzB,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACrD,OAAO,QAAQ,CAAC;IACjB,CAAC;IAED,UAAU;QACT,OAAO,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAED,UAAU;QACT,OAAO;QACP,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;QAExC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;aAC/C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;aAC3B,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3B,IAAI;YACJ,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;YAC7B,UAAU,EAAE,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;SAC/D,CAAC,CAAC,CAAC;QAEL,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;YACjD,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,QAAQ,OAAO,UAAU,IAAI,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IAC3C,CAAC;IAEO,YAAY;QACnB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC,GAAG,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC;IACvF,CAAC;CACD;AApDD,kDAoDC;AAGY,QAAA,IAAI,GAAG,IAAI,mBAAmB,EAAE,CAAC","sourcesContent":["import { performance } from 'perf_hooks';\r\n\r\nexport class PerformanceAnalyzer {\r\n\tprivate timers: Map<string, number> = new Map();\r\n\tprivate results: Map<string, number> = new Map();\r\n\r\n\tstartTimer(name: string): void {\r\n\t\tthis.timers.set(name, performance.now());\r\n\t}\r\n\r\n\tendTimer(name: string): number {\r\n\t\treturn 0;\r\n\t\tconst startTime = this.timers.get(name);\r\n\t\tif (!startTime) {\r\n\t\t\tconsole.warn(`Timer ${name} was not started`);\r\n\t\t\treturn 0;\r\n\t\t}\r\n\r\n\t\tconst duration = performance.now() - startTime;\r\n\t\tthis.results.set(name, duration);\r\n\t\tthis.timers.delete(name);\r\n\r\n\t\tconsole.log(`⏱️ ${name}: ${duration.toFixed(2)}ms`);\r\n\t\treturn duration;\r\n\t}\r\n\r\n\tgetResults(): { [key: string]: number } {\r\n\t\treturn Object.fromEntries(this.results);\r\n\t}\r\n\r\n\tlogSummary(): void {\r\n\t\treturn;\r\n\t\tconsole.log('\\n📊 Performance Summary:');\r\n\t\tconsole.log('========================');\r\n\r\n\t\tconst sorted = Array.from(this.results.entries())\r\n\t\t\t.sort((a, b) => b[1] - a[1])\r\n\t\t\t.map(([name, duration]) => ({\r\n\t\t\t\tname,\r\n\t\t\t\tduration: duration.toFixed(2),\r\n\t\t\t\tpercentage: ((duration / this.getTotalTime()) * 100).toFixed(1),\r\n\t\t\t}));\r\n\r\n\t\tsorted.forEach(({ name, duration, percentage }) => {\r\n\t\t\tconsole.log(`${name.padEnd(30)} ${duration}ms (${percentage}%)`);\r\n\t\t});\r\n\r\n\t\tconsole.log(`${'TOTAL'.padEnd(30)} ${this.getTotalTime().toFixed(2)}ms`);\r\n\t\tconsole.log('========================\\n');\r\n\t}\r\n\r\n\tprivate getTotalTime(): number {\r\n\t\treturn Array.from(this.results.values()).reduce((sum, duration) => sum + duration, 0);\r\n\t}\r\n}\r\n\r\n// Singleton instance\r\nexport const perf = new PerformanceAnalyzer();\r\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/duos/final-stats/config.ts"],"names":[],"mappings":";;;AAAA,+FAA6E;AAEhE,QAAA,aAAa,GAAG,GAAG,kDAAgB,oFAAoF,CAAC;AACxH,QAAA,mBAAmB,GAAG,GAAG,kDAAgB,2DAA2D,CAAC;AACrG,QAAA,cAAc,GAAG,GAAG,kDAAgB,4EAA4E,CAAC","sourcesContent":["import { STATS_KEY_PREFIX } from '../hourly/_build-battlegrounds-hero-stats';\r\n\r\nexport const STAT_KEY_HERO = `${STATS_KEY_PREFIX}/hero-stats/mmr-%mmrPercentile%/%timePeriod%/%anomaly%overview-from-hourly.gz.json`;\r\nexport const STAT_KEY_PERCENTILE = `${STATS_KEY_PREFIX}/hero-stats/%timePeriod%/%anomaly%mmr-percentiles.gz.json`;\r\nexport const STAT_KEY_QUEST = `${STATS_KEY_PREFIX}/quest-stats/mmr-%mmrPercentile%/%timePeriod%/overview-from-hourly.gz.json`;\r\n"]}
@@ -1,22 +1,21 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.s3 = void 0;
4
+ const client_lambda_1 = require("@aws-sdk/client-lambda");
7
5
  const aws_lambda_utils_1 = require("@firestone-hs/aws-lambda-utils");
8
6
  const reference_data_1 = require("@firestone-hs/reference-data");
9
- const aws_sdk_1 = __importDefault(require("aws-sdk"));
10
- const anomalies_1 = require("../../../common/anomalies");
11
- const _build_battlegrounds_hero_stats_1 = require("../../hourly/_build-battlegrounds-hero-stats");
7
+ const performance_analyzer_1 = require("../../../common/performance-analyzer");
12
8
  const percentiles_1 = require("../percentiles");
13
9
  const s3_loader_1 = require("../s3-loader");
14
10
  const s3_saver_1 = require("./s3-saver");
15
11
  const stats_merger_1 = require("./stats-merger");
16
12
  const allCards = new reference_data_1.AllCardsService();
17
13
  exports.s3 = new aws_lambda_utils_1.S3();
18
- const lambda = new aws_sdk_1.default.Lambda();
14
+ const lambda = new client_lambda_1.LambdaClient({
15
+ region: process.env.AWS_REGION || 'us-west-2',
16
+ });
19
17
  exports.default = async (event, context) => {
18
+ performance_analyzer_1.perf.startTimer('total-execution');
20
19
  await allCards.initializeCardsDb();
21
20
  if (!event.timePeriod) {
22
21
  await dispatchEvents(context);
@@ -26,13 +25,17 @@ exports.default = async (event, context) => {
26
25
  const timePeriod = event.timePeriod;
27
26
  const mmrPercentile = event.mmrPercentile;
28
27
  const anomaly = event.anomaly;
28
+ console.log('aggregating data', timePeriod, mmrPercentile);
29
29
  const patchInfo = await (0, aws_lambda_utils_1.getLastBattlegroundsPatch)();
30
+ performance_analyzer_1.perf.startTimer('load-hourly-data');
30
31
  const hourlyData = await (0, s3_loader_1.loadHourlyDataFromS3)('hero', timePeriod, mmrPercentile, anomaly, patchInfo);
32
+ performance_analyzer_1.perf.endTimer('load-hourly-data');
31
33
  if (!(hourlyData === null || hourlyData === void 0 ? void 0 : hourlyData.length)) {
32
34
  console.log('no data found', timePeriod, mmrPercentile, anomaly);
33
35
  cleanup();
34
36
  return;
35
37
  }
38
+ console.log('hourlyData', hourlyData.length);
36
39
  const lastUpdate = hourlyData
37
40
  .map((d) => ({
38
41
  date: new Date(d.lastUpdateDate),
@@ -40,41 +43,42 @@ exports.default = async (event, context) => {
40
43
  time: new Date(d.lastUpdateDate).getTime(),
41
44
  }))
42
45
  .sort((a, b) => b.time - a.time)[0].date;
46
+ performance_analyzer_1.perf.startTimer('merge-stats');
43
47
  const mergedStats = (0, stats_merger_1.mergeStats)(hourlyData, mmrPercentile, allCards);
48
+ performance_analyzer_1.perf.endTimer('merge-stats');
49
+ performance_analyzer_1.perf.startTimer('build-mmr-percentiles');
44
50
  const mmrPercentiles = (0, percentiles_1.buildMmrPercentiles)(hourlyData);
51
+ performance_analyzer_1.perf.endTimer('build-mmr-percentiles');
52
+ performance_analyzer_1.perf.startTimer('persist-data');
45
53
  await (0, s3_saver_1.persistData)(mergedStats, mmrPercentiles, anomaly, lastUpdate, timePeriod, mmrPercentile);
54
+ performance_analyzer_1.perf.endTimer('persist-data');
55
+ performance_analyzer_1.perf.endTimer('total-execution');
56
+ performance_analyzer_1.perf.logSummary();
46
57
  cleanup();
47
58
  };
48
59
  const dispatchEvents = async (context) => {
49
60
  console.log('dispatching events');
50
61
  const allTimePeriod = ['all-time', 'past-three', 'past-seven', 'last-patch'];
51
62
  const mmrPercentiles = [100, 50, 25, 10, 1];
52
- const allAnomalies = await (0, anomalies_1.readAllAnomalies)(_build_battlegrounds_hero_stats_1.STATS_BUCKET, `${_build_battlegrounds_hero_stats_1.STATS_KEY_PREFIX}/hero-stats/anomalies`);
53
- await (0, s3_saver_1.persistAnomaliesList)(allAnomalies);
63
+ const allAnomalies = [null];
54
64
  for (const timePeriod of allTimePeriod) {
55
65
  for (const percentile of mmrPercentiles) {
56
- for (const anomaly of allAnomalies) {
57
- const newEvent = {
58
- timePeriod: timePeriod,
59
- mmrPercentile: percentile,
60
- anomaly: anomaly,
61
- };
62
- const params = {
63
- FunctionName: context.functionName,
64
- InvocationType: 'Event',
65
- LogType: 'Tail',
66
- Payload: JSON.stringify(newEvent),
67
- };
68
- const result = await lambda
69
- .invoke({
70
- FunctionName: context.functionName,
71
- InvocationType: 'Event',
72
- LogType: 'Tail',
73
- Payload: JSON.stringify(newEvent),
74
- })
75
- .promise();
76
- await (0, aws_lambda_utils_1.sleep)(50);
77
- }
66
+ const newEvent = {
67
+ timePeriod: timePeriod,
68
+ mmrPercentile: percentile,
69
+ };
70
+ const params = {
71
+ FunctionName: context.functionName,
72
+ InvocationType: 'Event',
73
+ LogType: 'Tail',
74
+ Payload: JSON.stringify(newEvent),
75
+ };
76
+ const result = await lambda.send(new client_lambda_1.InvokeCommand({
77
+ FunctionName: context.functionName,
78
+ InvocationType: 'Event',
79
+ LogType: 'Tail',
80
+ Payload: JSON.stringify(newEvent),
81
+ }));
78
82
  }
79
83
  }
80
84
  };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_build-aggregated-stats.js","sourceRoot":"","sources":["../../../../src/duos/final-stats/heroes/_build-aggregated-stats.ts"],"names":[],"mappings":"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","sourcesContent":["import { InvokeCommand, LambdaClient } from '@aws-sdk/client-lambda';\r\nimport { S3, getLastBattlegroundsPatch, logBeforeTimeout } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { Context } from 'aws-lambda';\r\nimport { perf } from '../../../common/performance-analyzer';\r\nimport { BgsGlobalHeroStat, BgsHeroStatsV2, MmrPercentile, MmrPercentileFilter, TimePeriod } from '../../../models';\r\nimport { buildMmrPercentiles } from '../percentiles';\r\nimport { loadHourlyDataFromS3 } from '../s3-loader';\r\nimport { persistData } from './s3-saver';\r\nimport { mergeStats } from './stats-merger';\r\n\r\nconst allCards = new AllCardsService();\r\nexport const s3 = new S3();\r\nconst lambda = new LambdaClient({\r\n\tregion: process.env.AWS_REGION || 'us-west-2',\r\n});\r\n\r\nexport default async (event, context: Context): Promise<any> => {\r\n\tperf.startTimer('total-execution');\r\n\tawait allCards.initializeCardsDb();\r\n\r\n\tif (!event.timePeriod) {\r\n\t\tawait dispatchEvents(context);\r\n\t\treturn;\r\n\t}\r\n\r\n\tconst cleanup = logBeforeTimeout(context);\r\n\tconst timePeriod: TimePeriod = event.timePeriod;\r\n\tconst mmrPercentile: MmrPercentileFilter = event.mmrPercentile;\r\n\tconst anomaly: string | null = event.anomaly;\r\n\r\n\tconsole.log('aggregating data', timePeriod, mmrPercentile);\r\n\r\n\t// Build the list of files based on the timeframe, and load all of these\r\n\tconst patchInfo = await getLastBattlegroundsPatch();\r\n\r\n\tperf.startTimer('load-hourly-data');\r\n\tconst hourlyData: readonly BgsHeroStatsV2[] = await loadHourlyDataFromS3(\r\n\t\t'hero',\r\n\t\ttimePeriod,\r\n\t\tmmrPercentile,\r\n\t\tanomaly,\r\n\t\tpatchInfo,\r\n\t);\r\n\tperf.endTimer('load-hourly-data');\r\n\r\n\tif (!hourlyData?.length) {\r\n\t\tconsole.log('no data found', timePeriod, mmrPercentile, anomaly);\r\n\t\tcleanup();\r\n\t\treturn;\r\n\t}\r\n\r\n\tconsole.log('hourlyData', hourlyData.length);\r\n\r\n\tconst lastUpdate = hourlyData\r\n\t\t.map((d) => ({\r\n\t\t\tdate: new Date(d.lastUpdateDate),\r\n\t\t\tdateStr: d.lastUpdateDate,\r\n\t\t\ttime: new Date(d.lastUpdateDate).getTime(),\r\n\t\t}))\r\n\t\t.sort((a, b) => b.time - a.time)[0].date;\r\n\r\n\t// Here it's ok that the MMR corresponding to each MMR percentile is not the same across all the hourly data chunks\r\n\t// as the actual MMR evolves over time\r\n\t// The only issue is that the samples might be too small for the MMR percentiles to be really representative in\r\n\t// each group\r\n\t// Empirically, it looks like there isn't much variation on a hour-by-hour basis, so it should be ok\r\n\t// A possible solution, if this becomes an issue, is to compute the MMR percentiles on the full last day of data\r\n\t// when building the hourly data\r\n\tperf.startTimer('merge-stats');\r\n\tconst mergedStats: readonly BgsGlobalHeroStat[] = mergeStats(hourlyData, mmrPercentile, allCards);\r\n\tperf.endTimer('merge-stats');\r\n\r\n\tperf.startTimer('build-mmr-percentiles');\r\n\tconst mmrPercentiles: readonly MmrPercentile[] = buildMmrPercentiles(hourlyData);\r\n\tperf.endTimer('build-mmr-percentiles');\r\n\r\n\tperf.startTimer('persist-data');\r\n\tawait persistData(mergedStats, mmrPercentiles, anomaly, lastUpdate, timePeriod, mmrPercentile);\r\n\tperf.endTimer('persist-data');\r\n\r\n\tperf.endTimer('total-execution');\r\n\tperf.logSummary();\r\n\r\n\tcleanup();\r\n};\r\n\r\nconst dispatchEvents = async (context: Context) => {\r\n\tconsole.log('dispatching events');\r\n\tconst allTimePeriod: readonly TimePeriod[] = ['all-time', 'past-three', 'past-seven', 'last-patch'];\r\n\tconst mmrPercentiles: readonly MmrPercentileFilter[] = [100, 50, 25, 10, 1];\r\n\tconst allAnomalies: readonly (string | null)[] = [null];\r\n\t// await readAllAnomalies(\r\n\t// \tSTATS_BUCKET,\r\n\t// \t`${STATS_KEY_PREFIX}/hero-stats/anomalies`,\r\n\t// );\r\n\t// await persistAnomaliesList(allAnomalies);\r\n\tfor (const timePeriod of allTimePeriod) {\r\n\t\tfor (const percentile of mmrPercentiles) {\r\n\t\t\t// for (const anomaly of allAnomalies) {\r\n\t\t\tconst newEvent = {\r\n\t\t\t\ttimePeriod: timePeriod,\r\n\t\t\t\tmmrPercentile: percentile,\r\n\t\t\t\t// anomaly: anomaly,\r\n\t\t\t};\r\n\t\t\tconst params = {\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t};\r\n\t\t\t// console.log('\\tinvoking lambda', params);\r\n\t\t\tconst result = await lambda.send(\r\n\t\t\t\tnew InvokeCommand({\r\n\t\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\t\tLogType: 'Tail',\r\n\t\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t\t}),\r\n\t\t\t);\r\n\t\t}\r\n\t\t// }\r\n\t}\r\n};\r\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3-saver.js","sourceRoot":"","sources":["../../../../src/duos/final-stats/heroes/s3-saver.ts"],"names":[],"mappings":";;;AAAA,+BAAgC;AAEhC,kGAA8F;AAC9F,sCAA+D;AAC/D,uEAA+C;AAExC,MAAM,oBAAoB,GAAG,KAAK,EAAE,SAA4B,EAAE,EAAE;IAC1E,MAAM,4BAAE,CAAC,SAAS,CACjB,IAAA,eAAQ,EAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,EACnC,8CAAY,EACZ,GAAG,kDAAgB,yBAAyB,EAC5C,kBAAkB,EAClB,MAAM,CACN,CAAC;AACH,CAAC,CAAC;AARW,QAAA,oBAAoB,wBAQ/B;AAEK,MAAM,WAAW,GAAG,KAAK,EAC/B,WAAyC,EACzC,cAAwC,EACxC,OAAsB,EACtB,UAAgB,EAChB,UAAsB,EACtB,aAAkC,EACjC,EAAE;IACH,MAAM,IAAI,GAAmB;QAC5B,SAAS,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACrC,GAAG,IAAI;YACP,aAAa,EAAE,aAAa;YAC5B,UAAU,EAAE,UAAU;SACtB,CAAC,CAAC;QACH,cAAc,EAAE,UAAU;QAC1B,UAAU,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3E,cAAc,EAAE,cAAc;KAC9B,CAAC;IAEF,MAAM,4BAAE,CAAC,SAAS,CACjB,IAAA,eAAQ,EAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EAC9B,8CAAY,EACZ,sBAAa,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;SACxE,OAAO,CAAC,iBAAiB,EAAE,GAAG,aAAa,EAAE,CAAC;SAC9C,OAAO,CAAC,cAAc,EAAE,UAAU,CAAC,EACrC,kBAAkB,EAClB,MAAM,CACN,CAAC;IACF,MAAM,4BAAE,CAAC,SAAS,CACjB,IAAA,eAAQ,EAAC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,EACxC,8CAAY,EACZ,4BAAmB,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CACvF,cAAc,EACd,UAAU,CACV,EACD,kBAAkB,EAClB,MAAM,CACN,CAAC;AACH,CAAC,CAAC;AAtCW,QAAA,WAAW,eAsCtB","sourcesContent":["import { gzipSync } from 'zlib';\r\nimport { BgsGlobalHeroStat, BgsHeroStatsV2, MmrPercentile, MmrPercentileFilter, TimePeriod } from '../../../models';\r\nimport { STATS_BUCKET, STATS_KEY_PREFIX } from '../../hourly/_build-battlegrounds-hero-stats';\r\nimport { STAT_KEY_HERO, STAT_KEY_PERCENTILE } from '../config';\r\nimport { s3 } from './_build-aggregated-stats';\r\n\r\nexport const persistAnomaliesList = async (anomalies: readonly string[]) => {\r\n\tawait s3.writeFile(\r\n\t\tgzipSync(JSON.stringify(anomalies)),\r\n\t\tSTATS_BUCKET,\r\n\t\t`${STATS_KEY_PREFIX}/anomalies-list.gz.json`,\r\n\t\t'application/json',\r\n\t\t'gzip',\r\n\t);\r\n};\r\n\r\nexport const persistData = async (\r\n\tmergedStats: readonly BgsGlobalHeroStat[],\r\n\tmmrPercentiles: readonly MmrPercentile[],\r\n\tanomaly: string | null,\r\n\tlastUpdate: Date,\r\n\ttimePeriod: TimePeriod,\r\n\tmmrPercentile: MmrPercentileFilter,\r\n) => {\r\n\tconst stat: BgsHeroStatsV2 = {\r\n\t\theroStats: mergedStats.map((stat) => ({\r\n\t\t\t...stat,\r\n\t\t\tmmrPercentile: mmrPercentile,\r\n\t\t\ttimePeriod: timePeriod,\r\n\t\t})),\r\n\t\tlastUpdateDate: lastUpdate,\r\n\t\tdataPoints: mergedStats.map((s) => s.dataPoints).reduce((a, b) => a + b, 0),\r\n\t\tmmrPercentiles: mmrPercentiles,\r\n\t};\r\n\t// console.log('persisting data', stat.dataPoints, stat.heroStats?.length);\r\n\tawait s3.writeFile(\r\n\t\tgzipSync(JSON.stringify(stat)),\r\n\t\tSTATS_BUCKET,\r\n\t\tSTAT_KEY_HERO.replace('%anomaly%', anomaly ? `anomalies/${anomaly}/` : '')\r\n\t\t\t.replace('%mmrPercentile%', `${mmrPercentile}`)\r\n\t\t\t.replace('%timePeriod%', timePeriod),\r\n\t\t'application/json',\r\n\t\t'gzip',\r\n\t);\r\n\tawait s3.writeFile(\r\n\t\tgzipSync(JSON.stringify(mmrPercentiles)),\r\n\t\tSTATS_BUCKET,\r\n\t\tSTAT_KEY_PERCENTILE.replace('%anomaly%', anomaly ? `anomalies/${anomaly}/` : '').replace(\r\n\t\t\t'%timePeriod%',\r\n\t\t\ttimePeriod,\r\n\t\t),\r\n\t\t'application/json',\r\n\t\t'gzip',\r\n\t);\r\n};\r\n"]}
@@ -3,12 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.mergeStats = void 0;
4
4
  const aws_lambda_utils_1 = require("@firestone-hs/aws-lambda-utils");
5
5
  const util_functions_1 = require("../../../common/util-functions");
6
+ const stats_merger_1 = require("../../../solo/final-stats/heroes/stats-merger");
6
7
  const mergeStats = (hourlyData, mmrPercentile, allCards) => {
7
8
  const allStats = hourlyData
8
9
  .flatMap((data) => data.heroStats)
9
10
  .filter((stat) => stat.mmrPercentile === mmrPercentile)
10
11
  .filter((stat) => stat.heroCardId !== "TB_BaconShop_HERO_PH");
11
- const groupedByHero = (0, aws_lambda_utils_1.groupByFunction)((stat) => stat.heroCardId)(allStats);
12
+ const groupedByHero = (0, aws_lambda_utils_1.groupByFunction)(allStats, (stat) => stat.heroCardId);
12
13
  const result = Object.values(groupedByHero).map((stats) => mergeStatsForSingleHero(stats, allCards));
13
14
  const maxDataPoints = Math.max(...result.map((r) => r.dataPoints));
14
15
  const filtered = result.filter((r) => r.dataPoints > maxDataPoints / 50);
@@ -36,7 +37,7 @@ const mergeStatsForSingleHero = (stats, allCards) => {
36
37
  standardDeviation: (0, util_functions_1.round)(standardDeviation),
37
38
  standardDeviationOfTheMean: (0, util_functions_1.round)(standardDeviationOfTheMean),
38
39
  conservativePositionEstimate: (0, util_functions_1.round)(averagePosition + 3 * standardDeviationOfTheMean),
39
- placementDistribution: mergePlacementDistributions(stats),
40
+ placementDistribution: (0, stats_merger_1.mergePlacementDistributions)(stats),
40
41
  warbandStats: mergeWarbandStats(stats),
41
42
  combatWinrate: mergeCombatWinrate(stats, debug),
42
43
  tribeStats: mergeTribeStats(stats, averagePosition).filter((s) => s.dataPointsOnMissingTribe > s.dataPoints / 20),
@@ -72,28 +73,6 @@ const mergeTribeStats = (stats, refAveragePosition) => {
72
73
  });
73
74
  return result;
74
75
  };
75
- const mergePlacementDistributions = (stats) => {
76
- var _a, _b;
77
- const rawMerge = mergePlacementDistributionsRaw(stats);
78
- const result = [];
79
- const totalDataPoints = rawMerge.map((s) => s.totalMatches).reduce((a, b) => a + b, 0);
80
- for (let i = 1; i <= 8; i++) {
81
- const total = (_b = (_a = rawMerge.find((d) => d.rank === i)) === null || _a === void 0 ? void 0 : _a.totalMatches) !== null && _b !== void 0 ? _b : 0;
82
- result.push({ rank: i, percentage: (0, util_functions_1.round)((100 * total) / totalDataPoints) });
83
- }
84
- return result;
85
- };
86
- const mergePlacementDistributionsRaw = (stats) => {
87
- const rawStats = stats.map((stat) => stat.placementDistributionRaw);
88
- const result = [];
89
- for (let i = 1; i <= 8; i++) {
90
- const total = rawStats
91
- .map((d) => { var _a, _b; return (_b = (_a = d === null || d === void 0 ? void 0 : d.find((info) => info.rank === i)) === null || _a === void 0 ? void 0 : _a.totalMatches) !== null && _b !== void 0 ? _b : 0; })
92
- .reduce((a, b) => a + b, 0);
93
- result.push({ rank: i, totalMatches: total });
94
- }
95
- return result;
96
- };
97
76
  const mergeWarbandStats = (stats) => {
98
77
  const { rawMerge, maxTurn } = mergeWarbandStatsRaw(stats);
99
78
  const result = [];
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats-merger.js","sourceRoot":"","sources":["../../../../src/duos/final-stats/heroes/stats-merger.ts"],"names":[],"mappings":"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","sourcesContent":["import { groupByFunction } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService, CardIds } from '@firestone-hs/reference-data';\r\nimport { round } from '../../../common/util-functions';\r\nimport { BgsGlobalHeroStat, BgsHeroStatsV2, BgsHeroTribeStat, MmrPercentileFilter } from '../../../models';\r\nimport { mergePlacementDistributions } from '../../../solo/final-stats/heroes/stats-merger';\r\n\r\nexport const mergeStats = (\r\n\thourlyData: readonly BgsHeroStatsV2[],\r\n\tmmrPercentile: MmrPercentileFilter,\r\n\tallCards: AllCardsService,\r\n): readonly BgsGlobalHeroStat[] => {\r\n\tconst allStats: readonly BgsGlobalHeroStat[] = hourlyData\r\n\t\t.flatMap((data) => data.heroStats)\r\n\t\t.filter((stat) => stat.mmrPercentile === mmrPercentile)\r\n\t\t.filter((stat) => stat.heroCardId !== CardIds.BaconphheroHeroic);\r\n\t// console.debug('allStats', mmrPercentile, allStats.length, '/', hourlyData.length);\r\n\tconst groupedByHero: {\r\n\t\t[heroCardId: string]: readonly BgsGlobalHeroStat[];\r\n\t} = groupByFunction(allStats, (stat) => stat.heroCardId);\r\n\tconst result: readonly BgsGlobalHeroStat[] = Object.values(groupedByHero).map((stats) =>\r\n\t\tmergeStatsForSingleHero(stats, allCards),\r\n\t);\r\n\tconst maxDataPoints = Math.max(...result.map((r) => r.dataPoints));\r\n\tconst filtered = result.filter((r) => r.dataPoints > maxDataPoints / 50);\r\n\treturn filtered;\r\n};\r\n\r\nconst mergeStatsForSingleHero = (stats: readonly BgsGlobalHeroStat[], allCards: AllCardsService): BgsGlobalHeroStat => {\r\n\tconst ref = stats[0];\r\n\tconst debug = ref.heroCardId === 'BG21_HERO_010';\r\n\r\n\tconst totalWeightedAverage = stats.map((s) => s.averagePosition * s.dataPoints).reduce((a, b) => a + b, 0);\r\n\tconst totalDataPoints = stats.map((s) => s.dataPoints).reduce((a, b) => a + b, 0);\r\n\tconst averagePosition = totalWeightedAverage / totalDataPoints;\r\n\r\n\tconst totalWeightedVariance = stats\r\n\t\t.map((s) => s.standardDeviation * s.standardDeviation * s.dataPoints)\r\n\t\t.reduce((a, b) => a + b, 0);\r\n\tconst overallVariance = totalWeightedVariance / totalDataPoints;\r\n\tconst standardDeviation = Math.sqrt(overallVariance);\r\n\tconst standardDeviationOfTheMean = standardDeviation / Math.sqrt(totalDataPoints);\r\n\r\n\tconst result: BgsGlobalHeroStat = {\r\n\t\theroCardId: ref.heroCardId,\r\n\t\tdataPoints: stats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0),\r\n\t\ttotalOffered: stats.map((stat) => stat.totalOffered ?? 0).reduce((a, b) => a + b, 0),\r\n\t\ttotalPicked: stats.map((stat) => stat.totalPicked ?? 0).reduce((a, b) => a + b, 0),\r\n\t\taveragePosition: round(averagePosition),\r\n\t\tstandardDeviation: round(standardDeviation),\r\n\t\tstandardDeviationOfTheMean: round(standardDeviationOfTheMean),\r\n\t\tconservativePositionEstimate: round(averagePosition + 3 * standardDeviationOfTheMean),\r\n\t\tplacementDistribution: mergePlacementDistributions(stats),\r\n\t\twarbandStats: mergeWarbandStats(stats),\r\n\t\tcombatWinrate: mergeCombatWinrate(stats, debug),\r\n\t\ttribeStats: mergeTribeStats(stats, averagePosition).filter(\r\n\t\t\t(s) => s.dataPointsOnMissingTribe > s.dataPoints / 20,\r\n\t\t),\r\n\t};\r\n\treturn result;\r\n};\r\n\r\nconst mergeTribeStats = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\trefAveragePosition: number,\r\n): readonly BgsHeroTribeStat[] => {\r\n\tconst allTribeStats = stats.flatMap((stat) => stat.tribeStats);\r\n\tconst uniqueTribes = new Set(allTribeStats.map((tribe) => tribe.tribe));\r\n\tconst result: BgsHeroTribeStat[] = [...uniqueTribes].map((tribe) => {\r\n\t\tconst tribeStats = allTribeStats.filter((stat) => stat.tribe === tribe);\r\n\t\tconst totalStatDataPoints = tribeStats.map((stat) => stat.dataPoints).reduce((a, b) => a + b, 0);\r\n\t\tconst averagePosition =\r\n\t\t\ttribeStats.map((stat) => stat.averagePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /\r\n\t\t\ttotalStatDataPoints;\r\n\t\tconst averagePositionWithoutTribe =\r\n\t\t\ttribeStats\r\n\t\t\t\t.map((stat) => stat.averagePositionWithoutTribe * stat.dataPointsOnMissingTribe)\r\n\t\t\t\t.reduce((a, b) => a + b, 0) /\r\n\t\t\ttribeStats.map((stat) => stat.dataPointsOnMissingTribe).reduce((a, b) => a + b, 0);\r\n\t\t// const impactAveragePosition =\r\n\t\t// \ttribeStats.map((stat) => stat.impactAveragePosition * stat.dataPoints).reduce((a, b) => a + b, 0) /\r\n\t\t// \ttotalStatDataPoints;\r\n\t\t// const impactAveragePositionVsMissingTribe =\r\n\t\t// \ttribeStats\r\n\t\t// \t\t.map((stat) => stat.impactAveragePositionVsMissingTribe * stat.dataPoints)\r\n\t\t// \t\t.reduce((a, b) => a + b, 0) / totalStatDataPoints;\r\n\t\treturn {\r\n\t\t\ttribe: tribe,\r\n\t\t\tdataPoints: totalStatDataPoints,\r\n\t\t\tdataPointsOnMissingTribe: tribeStats\r\n\t\t\t\t.map((stat) => stat.dataPointsOnMissingTribe)\r\n\t\t\t\t.reduce((a, b) => a + b, 0),\r\n\t\t\ttotalOffered: tribeStats.map((stat) => stat.totalOffered ?? 0).reduce((a, b) => a + b, 0),\r\n\t\t\ttotalPicked: tribeStats.map((stat) => stat.totalPicked ?? 0).reduce((a, b) => a + b, 0),\r\n\t\t\taveragePosition: round(averagePosition),\r\n\t\t\taveragePositionWithoutTribe: round(averagePositionWithoutTribe),\r\n\t\t\trefAveragePosition: refAveragePosition,\r\n\t\t\timpactAveragePosition: round(averagePosition - refAveragePosition),\r\n\t\t\t// impactAveragePositionDebug: round(impactAveragePosition),\r\n\t\t\timpactAveragePositionVsMissingTribe: round(averagePosition - averagePositionWithoutTribe),\r\n\t\t};\r\n\t});\r\n\treturn result;\r\n};\r\n\r\nconst mergeWarbandStats = (stats: readonly BgsGlobalHeroStat[]): readonly { turn: number; averageStats: number }[] => {\r\n\tconst { rawMerge, maxTurn } = mergeWarbandStatsRaw(stats);\r\n\tconst result: { turn: number; averageStats: number }[] = [];\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst statsForTurn = rawMerge.find((d) => d.turn === i);\r\n\t\tresult.push({ turn: i, averageStats: round(statsForTurn.totalStats / statsForTurn.dataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeWarbandStatsRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n): { rawMerge: readonly { turn: number; dataPoints: number; totalStats: number }[]; maxTurn: number } => {\r\n\tconst rawStats = stats.map((stat) => stat.warbandStatsRaw).filter((s) => !!s?.length);\r\n\tconst result: { turn: number; dataPoints: number; totalStats: number }[] = [];\r\n\tconst maxTurn = Math.min(20, Math.max(...rawStats.map((stat) => getMaxTurn(stat))));\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst rawStatsForTurn = rawStats.map((stat) => stat.find((info) => info.turn === i));\r\n\t\tconst totalStats: number = rawStatsForTurn.map((d) => d?.totalStats ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tconst totalDataPoints = rawStatsForTurn.map((d) => d?.dataPoints ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ turn: i, totalStats: totalStats, dataPoints: totalDataPoints });\r\n\t}\r\n\treturn { rawMerge: result, maxTurn: maxTurn };\r\n};\r\n\r\nconst mergeCombatWinrate = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\tdebug = false,\r\n): readonly { turn: number; winrate: number }[] => {\r\n\tconst { rawMerge, maxTurn } = mergeCombatWinrateRaw(stats, debug);\r\n\tconst result: { turn: number; winrate: number }[] = [];\r\n\tfor (let i = 1; i <= maxTurn; i++) {\r\n\t\tconst statForTurn = rawMerge.find((d) => d.turn === i);\r\n\t\tresult.push({ turn: i, winrate: round(statForTurn.totalWinrate / statForTurn.dataPoints) });\r\n\t}\r\n\treturn result;\r\n};\r\n\r\nconst mergeCombatWinrateRaw = (\r\n\tstats: readonly BgsGlobalHeroStat[],\r\n\tdebug = false,\r\n): { rawMerge: readonly { turn: number; dataPoints: number; totalWinrate: number }[]; maxTurn: number } => {\r\n\tconst rawStats = stats.map((stat) => stat.combatWinrateRaw).filter((stat) => !!stat?.length);\r\n\t// debug && console.log('rawStats', rawStats?.length, rawStats);\r\n\tconst result: { turn: number; dataPoints: number; totalWinrate: number }[] = [];\r\n\tconst maxTurn = Math.min(20, Math.max(...rawStats.map((stat) => getMaxTurn(stat))));\r\n\t// debug && console.log('maxTurn', maxTurn);\r\n\tfor (let i = 0; i <= maxTurn; i++) {\r\n\t\tconst rawStatsForTurn = rawStats.map((stat) => stat.find((info) => info.turn === i));\r\n\t\tconst totalWinrate: number = rawStatsForTurn.map((d) => d?.totalWinrate ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tconst totalDataPoints = rawStatsForTurn.map((d) => d?.dataPoints ?? 0).reduce((a, b) => a + b, 0);\r\n\t\tresult.push({ turn: i, totalWinrate: totalWinrate, dataPoints: totalDataPoints });\r\n\t}\r\n\t// debug && console.log('result', result);\r\n\treturn { rawMerge: result, maxTurn: maxTurn };\r\n};\r\n\r\nconst getMaxTurn = (rawStats: readonly { turn: number }[]): number => {\r\n\tif (!rawStats?.length) {\r\n\t\treturn 0;\r\n\t}\r\n\treturn Math.max(...rawStats.map((stat) => stat.turn));\r\n};\r\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hourly-utils.js","sourceRoot":"","sources":["../../../src/duos/final-stats/hourly-utils.ts"],"names":[],"mappings":";;;AAIO,MAAM,uBAAuB,GAAG,CAAC,UAAsB,EAAE,SAAoB,EAAU,EAAE;IAC/F,QAAQ,UAAU,EAAE;QACnB,KAAK,YAAY;YAChB,OAAO,CAAC,GAAG,EAAE,CAAC;QACf,KAAK,YAAY;YAChB,OAAO,CAAC,GAAG,EAAE,CAAC;QACf,KAAK,UAAU;YACd,OAAO,EAAE,GAAG,EAAE,CAAC;QAChB,KAAK,YAAY;YAChB,MAAM,gBAAgB,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,gBAAgB,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;YAEvF,OAAO,KAAK,CAAC;KACd;AACF,CAAC,CAAC;AAdW,QAAA,uBAAuB,2BAclC;AAEK,MAAM,cAAc,GAAG,CAAC,SAAiB,EAAqB,EAAE;IAGtE,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE;QACnC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1D,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAExB,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACnC,SAAS,CAAC,IAAI,CAAC,GAAG,OAAO,EAAE,CAAC,CAAC;KAC7B;IACD,OAAO,SAAS,CAAC;AAClB,CAAC,CAAC;AAfW,QAAA,cAAc,kBAezB","sourcesContent":["/* eslint-disable no-case-declarations */\r\nimport { PatchInfo } from '@firestone-hs/aws-lambda-utils';\r\nimport { TimePeriod } from '../../models';\r\n\r\nexport const computeHoursBackFromNow = (timePeriod: TimePeriod, patchInfo: PatchInfo): number => {\r\n\tswitch (timePeriod) {\r\n\t\tcase 'past-three':\r\n\t\t\treturn 3 * 24;\r\n\t\tcase 'past-seven':\r\n\t\t\treturn 7 * 24;\r\n\t\tcase 'all-time':\r\n\t\t\treturn 20 * 24;\r\n\t\tcase 'last-patch':\r\n\t\t\tconst patchReleaseDate = new Date(patchInfo.date);\r\n\t\t\tconst hours = Math.floor((Date.now() - patchReleaseDate.getTime()) / (1000 * 60 * 60));\r\n\t\t\t// console.debug('hours since last patch', hours, patchReleaseDate, patchInfo);\r\n\t\t\treturn hours;\r\n\t}\r\n};\r\n\r\nexport const buildFileNames = (hoursBack: number): readonly string[] => {\r\n\t// Build a list of file names, in the form YYYY-MM-dd (e.g. 2020-05-01)\r\n\t// that start from the day before the current date and go back in time\r\n\tconst fileNames: string[] = [];\r\n\tconst now = new Date();\r\n\tfor (let i = 0; i < hoursBack; i++) {\r\n\t\tconst date = new Date(now.getTime() - i * 60 * 60 * 1000);\r\n\t\tdate.setMinutes(0);\r\n\t\tdate.setSeconds(0);\r\n\t\tdate.setMilliseconds(0);\r\n\t\t// The date in the format YYYY-MM-ddTHH:mm:ss.sssZ\r\n\t\tconst dateStr = date.toISOString();\r\n\t\tfileNames.push(`${dateStr}`);\r\n\t}\r\n\treturn fileNames;\r\n};\r\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"percentiles.js","sourceRoot":"","sources":["../../../src/duos/final-stats/percentiles.ts"],"names":[],"mappings":";;;AAGO,MAAM,mBAAmB,GAAG,CAClC,UAAuD,EAC5B,EAAE;IAG7B,OAAO,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAC1B,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE,CACrF,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC;AACrB,CAAC,CAAC;AARW,QAAA,mBAAmB,uBAQ9B","sourcesContent":["import { BgsQuestStats } from '../../model-quests';\r\nimport { BgsHeroStatsV2, MmrPercentile } from '../../models';\r\n\r\nexport const buildMmrPercentiles = (\r\n\thourlyData: readonly (BgsHeroStatsV2 | BgsQuestStats)[],\r\n): readonly MmrPercentile[] => {\r\n\t// For now we simply pick the latest MMR percentiles, as it reflects the most accurately the current\r\n\t// state of the game\r\n\treturn [...hourlyData].sort(\r\n\t\t(a, b) => new Date(b.lastUpdateDate).getTime() - new Date(a.lastUpdateDate).getTime(),\r\n\t)[0].mmrPercentiles;\r\n};\r\n"]}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3-loader.js","sourceRoot":"","sources":["../../../src/duos/final-stats/s3-loader.ts"],"names":[],"mappings":";;;AAGA,+FAA4G;AAC5G,8EAAsD;AACtD,iDAAyE;AAKlE,MAAM,oBAAoB,GAAG,KAAK,EACxC,IAAO,EACP,UAAsB,EACtB,aAAkC,EAClC,OAAsB,EACtB,SAAoB,EACgB,EAAE;IACtC,MAAM,SAAS,GAAW,IAAA,sCAAuB,EAAC,UAAU,EAAE,SAAS,CAAC,CAAC;IACzE,MAAM,SAAS,GAAsB,IAAA,6BAAc,EAAC,SAAS,CAAC,CAAC;IAE/D,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,GAAG,CACpC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,wBAAwB,CAAC,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC,CAC7F,CAAC;IACF,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AACjD,CAAC,CAAC;AAdW,QAAA,oBAAoB,wBAc/B;AAEF,MAAM,wBAAwB,GAAG,KAAK,EACrC,IAAO,EACP,OAAsB,EACtB,aAAkC,EAClC,QAAgB,EACS,EAAE;IAC3B,MAAM,OAAO,GAAG,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,iDAAe,CAAC,CAAC,CAAC,kDAAgB,CAAC;IACrE,MAAM,OAAO,GAAG,OAAO;SACrB,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,aAAa,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;SAC5D,OAAO,CAAC,iBAAiB,EAAE,GAAG,aAAa,EAAE,CAAC;SAC9C,OAAO,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,MAAM,4BAAE,CAAC,eAAe,CAAC,8CAAY,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;IACvE,MAAM,MAAM,GAAkB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/C,OAAO,MAAM,CAAC;AACf,CAAC,CAAC","sourcesContent":["import { PatchInfo } from '@firestone-hs/aws-lambda-utils';\r\nimport { BgsQuestStats } from '../../model-quests';\r\nimport { BgsHeroStatsV2, MmrPercentileFilter, TimePeriod } from '../../models';\r\nimport { HOURLY_KEY_HERO, HOURLY_KEY_QUEST, STATS_BUCKET } from '../hourly/_build-battlegrounds-hero-stats';\r\nimport { s3 } from './heroes/_build-aggregated-stats';\r\nimport { buildFileNames, computeHoursBackFromNow } from './hourly-utils';\r\n\r\nexport type DataType = 'hero' | 'quest';\r\nexport type DataResult<T extends DataType> = T extends 'hero' ? BgsHeroStatsV2 : BgsQuestStats;\r\n\r\nexport const loadHourlyDataFromS3 = async <T extends DataType>(\r\n\ttype: T,\r\n\ttimePeriod: TimePeriod,\r\n\tmmrPercentile: MmrPercentileFilter,\r\n\tanomaly: string | null,\r\n\tpatchInfo: PatchInfo,\r\n): Promise<readonly DataResult<T>[]> => {\r\n\tconst hoursBack: number = computeHoursBackFromNow(timePeriod, patchInfo);\r\n\tconst fileNames: readonly string[] = buildFileNames(hoursBack);\r\n\t// console.debug('fileNames', timePeriod, mmrPercentile, fileNames);\r\n\tconst fileResults = await Promise.all(\r\n\t\tfileNames.map((fileName) => loadHourlyDeckStatFromS3(type, anomaly, mmrPercentile, fileName)),\r\n\t);\r\n\treturn fileResults.filter((result) => !!result);\r\n};\r\n\r\nconst loadHourlyDeckStatFromS3 = async <T extends DataType>(\r\n\ttype: T,\r\n\tanomaly: string | null,\r\n\tmmrPercentile: MmrPercentileFilter,\r\n\tfileName: string,\r\n): Promise<DataResult<T>> => {\r\n\tconst mainKey = type === 'hero' ? HOURLY_KEY_HERO : HOURLY_KEY_QUEST;\r\n\tconst fileKey = mainKey\r\n\t\t.replace('%anomaly%', anomaly ? `anomalies/${anomaly}/` : '')\r\n\t\t.replace('%mmrPercentile%', `${mmrPercentile}`)\r\n\t\t.replace('%startDate%', fileName);\r\n\tconst data = await s3.readGzipContent(STATS_BUCKET, fileKey, 1, false);\r\n\tconst result: DataResult<T> = JSON.parse(data);\r\n\treturn result;\r\n};\r\n"]}
@@ -1,18 +1,18 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.handleNewStats = exports.HOURLY_KEY_TRINKET = exports.HOURLY_KEY_QUEST = exports.HOURLY_KEY_HERO = exports.WORKING_ROWS_FILE = exports.STATS_KEY_PREFIX = exports.STATS_BUCKET = exports.s3 = void 0;
4
+ const client_lambda_1 = require("@aws-sdk/client-lambda");
7
5
  const aws_lambda_utils_1 = require("@firestone-hs/aws-lambda-utils");
8
6
  const reference_data_1 = require("@firestone-hs/reference-data");
9
- const aws_sdk_1 = __importDefault(require("aws-sdk"));
10
7
  const trinket_stats_1 = require("../../solo/hourly/trinkets/trinket-stats");
11
8
  const hero_stats_1 = require("./hero-stats");
12
9
  const rows_1 = require("./rows");
10
+ const quest_stats_1 = require("../../solo/hourly/quest-stats");
13
11
  exports.s3 = new aws_lambda_utils_1.S3();
14
12
  const allCards = new reference_data_1.AllCardsService();
15
- const lambda = new aws_sdk_1.default.Lambda();
13
+ const lambda = new client_lambda_1.LambdaClient({
14
+ region: process.env.AWS_REGION || 'us-west-2',
15
+ });
16
16
  const allMmrPercentiles = [100, 50, 25, 10, 1];
17
17
  exports.STATS_BUCKET = 'static.zerotoheroes.com';
18
18
  exports.STATS_KEY_PREFIX = `api/bgs/duo`;
@@ -36,15 +36,13 @@ const handleNewStats = async (event, context) => {
36
36
  cleanup();
37
37
  return;
38
38
  }
39
- if (event.statsV2) {
39
+ if (event.questsV2) {
40
+ const lastHourRows = await (0, rows_1.readRowsFromS3)(event.startDate);
41
+ await (0, quest_stats_1.buildQuestStats)(event.startDate, event.mmr, lastHourRows, allCards, exports.s3);
42
+ }
43
+ else if (event.statsV2) {
40
44
  const lastHourRows = await (0, rows_1.readRowsFromS3)(event.startDate);
41
- const uniqueAnomalies = [
42
- null,
43
- ...lastHourRows
44
- .flatMap((r) => { var _a; return (_a = r.bgsAnomalies) === null || _a === void 0 ? void 0 : _a.split(','); })
45
- .filter((a) => a)
46
- .filter((value, index, self) => self.indexOf(value) === index),
47
- ];
45
+ const uniqueAnomalies = [null];
48
46
  for (const anomaly of uniqueAnomalies) {
49
47
  console.log('building hero stats', event.startDate, event.mmr, lastHourRows === null || lastHourRows === void 0 ? void 0 : lastHourRows.length, anomaly);
50
48
  await (0, hero_stats_1.buildHeroStats)(event.startDate, event.mmr, anomaly, lastHourRows, allCards);
@@ -91,14 +89,12 @@ const dispatchTrinketsLambda = async (context, startDate) => {
91
89
  Payload: JSON.stringify(newEvent),
92
90
  };
93
91
  console.log('\tinvoking lambda', params);
94
- const result = await lambda
95
- .invoke({
92
+ const result = await lambda.send(new client_lambda_1.InvokeCommand({
96
93
  FunctionName: context.functionName,
97
94
  InvocationType: 'Event',
98
95
  LogType: 'Tail',
99
96
  Payload: JSON.stringify(newEvent),
100
- })
101
- .promise();
97
+ }));
102
98
  }
103
99
  };
104
100
  const dispatchQuestsV2Lambda = async (context, startDate) => {
@@ -115,14 +111,12 @@ const dispatchQuestsV2Lambda = async (context, startDate) => {
115
111
  Payload: JSON.stringify(newEvent),
116
112
  };
117
113
  console.log('\tinvoking lambda', params);
118
- const result = await lambda
119
- .invoke({
114
+ const result = await lambda.send(new client_lambda_1.InvokeCommand({
120
115
  FunctionName: context.functionName,
121
116
  InvocationType: 'Event',
122
117
  LogType: 'Tail',
123
118
  Payload: JSON.stringify(newEvent),
124
- })
125
- .promise();
119
+ }));
126
120
  }
127
121
  };
128
122
  const dispatchStatsV2Lambda = async (context, startDate) => {
@@ -139,14 +133,12 @@ const dispatchStatsV2Lambda = async (context, startDate) => {
139
133
  Payload: JSON.stringify(newEvent),
140
134
  };
141
135
  console.log('\tinvoking lambda', params);
142
- const result = await lambda
143
- .invoke({
136
+ const result = await lambda.send(new client_lambda_1.InvokeCommand({
144
137
  FunctionName: context.functionName,
145
138
  InvocationType: 'Event',
146
139
  LogType: 'Tail',
147
140
  Payload: JSON.stringify(newEvent),
148
- })
149
- .promise();
141
+ }));
150
142
  }
151
143
  };
152
144
  const dispatchCatchUpEvents = async (context, daysInThePast) => {
@@ -171,14 +163,12 @@ const dispatchCatchUpEvents = async (context, daysInThePast) => {
171
163
  LogType: 'Tail',
172
164
  Payload: JSON.stringify(newEvent),
173
165
  };
174
- const result = await lambda
175
- .invoke({
166
+ const result = await lambda.send(new client_lambda_1.InvokeCommand({
176
167
  FunctionName: context.functionName,
177
168
  InvocationType: 'Event',
178
169
  LogType: 'Tail',
179
170
  Payload: JSON.stringify(newEvent),
180
- })
181
- .promise();
171
+ }));
182
172
  await (0, aws_lambda_utils_1.sleep)(50);
183
173
  }
184
174
  };
@@ -1 +1 @@
1
- {"version":3,"file":"_build-battlegrounds-hero-stats.js","sourceRoot":"","sources":["../../../src/duos/hourly/_build-battlegrounds-hero-stats.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { S3, logBeforeTimeout, sleep } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { Context } from 'aws-lambda';\r\nimport AWS from 'aws-sdk';\r\nimport { InternalBgsRow } from '../../internal-model';\r\nimport { buildTrinketStats } from '../../solo/hourly/trinkets/trinket-stats';\r\nimport { buildHeroStats } from './hero-stats';\r\nimport { readRowsFromS3, saveRowsOnS3 } from './rows';\r\n\r\nexport const s3 = new S3();\r\nconst allCards = new AllCardsService();\r\nconst lambda = new AWS.Lambda();\r\n\r\nconst allMmrPercentiles: (100 | 50 | 25 | 10 | 1)[] = [100, 50, 25, 10, 1];\r\n\r\nexport const STATS_BUCKET = 'static.zerotoheroes.com';\r\nexport const STATS_KEY_PREFIX = `api/bgs/duo`;\r\nexport const WORKING_ROWS_FILE = `${STATS_KEY_PREFIX}/working/working-rows-%time%.json`;\r\nexport const HOURLY_KEY_HERO = `${STATS_KEY_PREFIX}/hero-stats/%anomaly%mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;\r\nexport const HOURLY_KEY_QUEST = `${STATS_KEY_PREFIX}/quest-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;\r\nexport const HOURLY_KEY_TRINKET = `${STATS_KEY_PREFIX}/trinket-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;\r\n\r\nexport default async (event, context: Context): Promise<any> => {\r\n\tawait handleNewStats(event, context);\r\n};\r\n\r\nexport const handleNewStats = async (event, context: Context) => {\r\n\tconst cleanup = logBeforeTimeout(context);\r\n\t// logger.log('event', event);\r\n\tawait allCards.initializeCardsDb();\r\n\r\n\tif (event.catchUp) {\r\n\t\tawait dispatchCatchUpEvents(context, +event.catchUp);\r\n\t\tcleanup();\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (!event.statsV2 && !event.questsV2 && !event.trinkets) {\r\n\t\tawait dispatchMainEvents(context, event);\r\n\t\tcleanup();\r\n\t\treturn;\r\n\t}\r\n\r\n\t// if (event.questsV2) {\r\n\t// \tconst lastHourRows: readonly InternalBgsRow[] = await readRowsFromS3(event.startDate);\r\n\t// \t// logger.log('building quest stats', event.timePeriod, event.startDate, lastHourRows?.length);\r\n\t// \tawait buildQuestStats(event.startDate, event.mmr, lastHourRows, allCards, s3);\r\n\t// } else\r\n\tif (event.statsV2) {\r\n\t\tconst lastHourRows: readonly InternalBgsRow[] = await readRowsFromS3(event.startDate);\r\n\t\tconst uniqueAnomalies = [\r\n\t\t\tnull,\r\n\t\t\t...lastHourRows\r\n\t\t\t\t.flatMap((r) => r.bgsAnomalies?.split(','))\r\n\t\t\t\t.filter((a) => a)\r\n\t\t\t\t.filter((value, index, self) => self.indexOf(value) === index),\r\n\t\t];\r\n\t\tfor (const anomaly of uniqueAnomalies) {\r\n\t\t\tconsole.log('building hero stats', event.startDate, event.mmr, lastHourRows?.length, anomaly);\r\n\t\t\tawait buildHeroStats(event.startDate, event.mmr, anomaly, lastHourRows, allCards);\r\n\t\t}\r\n\t} else if (event.trinkets) {\r\n\t\tconst lastHourRows: readonly InternalBgsRow[] = await readRowsFromS3(event.startDate);\r\n\t\t// logger.log('building hero stats', event.startDate, lastHourRows?.length);\r\n\t\tawait buildTrinketStats(\r\n\t\t\tevent.startDate,\r\n\t\t\tevent.mmr,\r\n\t\t\tlastHourRows,\r\n\t\t\tallCards,\r\n\t\t\tSTATS_BUCKET,\r\n\t\t\tHOURLY_KEY_TRINKET,\r\n\t\t\ts3,\r\n\t\t);\r\n\t}\r\n\r\n\tcleanup();\r\n};\r\n\r\nconst dispatchMainEvents = async (context: Context, event) => {\r\n\tconst startDate = buildProcessStartDate(event);\r\n\t// End one hour later\r\n\tconst endDate = new Date(startDate);\r\n\tendDate.setHours(endDate.getHours() + 1);\r\n\r\n\tawait saveRowsOnS3(startDate, endDate, allCards);\r\n\r\n\tawait dispatchStatsV2Lambda(context, startDate);\r\n\t// await dispatchQuestsV2Lambda(context, startDate);\r\n\tawait dispatchTrinketsLambda(context, startDate);\r\n};\r\n\r\nconst buildProcessStartDate = (event): Date => {\r\n\tif (event?.targetDate) {\r\n\t\tconst targetDate = new Date(event.targetDate);\r\n\t\treturn targetDate;\r\n\t}\r\n\r\n\t// Start from the start of the current hour\r\n\tconst processStartDate = new Date();\r\n\tprocessStartDate.setMinutes(0);\r\n\tprocessStartDate.setSeconds(0);\r\n\tprocessStartDate.setMilliseconds(0);\r\n\tprocessStartDate.setHours(processStartDate.getHours() - 1);\r\n\treturn processStartDate;\r\n};\r\n\r\nconst dispatchTrinketsLambda = async (context: Context, startDate: Date) => {\r\n\tfor (const mmr of allMmrPercentiles) {\r\n\t\tconst newEvent = {\r\n\t\t\ttrinkets: true,\r\n\t\t\tmmr: mmr,\r\n\t\t\tstartDate: startDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tconsole.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\t// logger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst dispatchQuestsV2Lambda = async (context: Context, startDate: Date) => {\r\n\tfor (const mmr of allMmrPercentiles) {\r\n\t\tconst newEvent = {\r\n\t\t\tquestsV2: true,\r\n\t\t\tmmr: mmr,\r\n\t\t\tstartDate: startDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tconsole.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\t// logger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst dispatchStatsV2Lambda = async (context: Context, startDate: Date) => {\r\n\tfor (const mmr of allMmrPercentiles) {\r\n\t\tconst newEvent = {\r\n\t\t\tstatsV2: true,\r\n\t\t\tmmr: mmr,\r\n\t\t\tstartDate: startDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tconsole.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\t// logger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst dispatchCatchUpEvents = async (context: Context, daysInThePast: number) => {\r\n\t// Build a list of hours for the last `daysInThePast` days, in the format YYYY-MM-ddTHH:mm:ss.sssZ\r\n\tconst now = new Date();\r\n\tconst hours = [];\r\n\tfor (let i = 0; i < 24 * daysInThePast; i++) {\r\n\t\tconst baseDate = new Date(now);\r\n\t\tbaseDate.setMinutes(0);\r\n\t\tbaseDate.setSeconds(0);\r\n\t\tbaseDate.setMilliseconds(0);\r\n\t\tconst hour = new Date(baseDate.getTime() - i * 60 * 60 * 1000);\r\n\t\thours.push(hour.toISOString());\r\n\t}\r\n\r\n\tfor (const targetDate of hours) {\r\n\t\tconsole.log('dispatching catch-up for date', targetDate);\r\n\t\tconst newEvent = {\r\n\t\t\ttargetDate: targetDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\t// console.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda\r\n\t\t\t.invoke({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t})\r\n\t\t\t.promise();\r\n\t\t// console.log('\\tinvocation result', result);\r\n\t\tawait sleep(50);\r\n\t}\r\n};\r\n"]}
1
+ {"version":3,"file":"_build-battlegrounds-hero-stats.js","sourceRoot":"","sources":["../../../src/duos/hourly/_build-battlegrounds-hero-stats.ts"],"names":[],"mappings":";;;AACA,0DAAqE;AACrE,qEAA6E;AAC7E,iEAA+D;AAG/D,4EAA6E;AAC7E,6CAA8C;AAC9C,iCAAsD;AACtD,+DAAgE;AAEnD,QAAA,EAAE,GAAG,IAAI,qBAAE,EAAE,CAAC;AAC3B,MAAM,QAAQ,GAAG,IAAI,gCAAe,EAAE,CAAC;AACvC,MAAM,MAAM,GAAG,IAAI,4BAAY,CAAC;IAC/B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,WAAW;CAC7C,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAA+B,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AAE9D,QAAA,YAAY,GAAG,yBAAyB,CAAC;AACzC,QAAA,gBAAgB,GAAG,aAAa,CAAC;AACjC,QAAA,iBAAiB,GAAG,GAAG,wBAAgB,mCAAmC,CAAC;AAC3E,QAAA,eAAe,GAAG,GAAG,wBAAgB,qEAAqE,CAAC;AAC3G,QAAA,gBAAgB,GAAG,GAAG,wBAAgB,6DAA6D,CAAC;AACpG,QAAA,kBAAkB,GAAG,GAAG,wBAAgB,+DAA+D,CAAC;AAErH,kBAAe,KAAK,EAAE,KAAK,EAAE,OAAgB,EAAgB,EAAE;IAC9D,MAAM,IAAA,sBAAc,EAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACtC,CAAC,CAAC;AAEK,MAAM,cAAc,GAAG,KAAK,EAAE,KAAK,EAAE,OAAgB,EAAE,EAAE;IAC/D,MAAM,OAAO,GAAG,IAAA,mCAAgB,EAAC,OAAO,CAAC,CAAC;IAE1C,MAAM,QAAQ,CAAC,iBAAiB,EAAE,CAAC;IAEnC,IAAI,KAAK,CAAC,OAAO,EAAE;QAClB,MAAM,qBAAqB,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrD,OAAO,EAAE,CAAC;QACV,OAAO;KACP;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE;QACzD,MAAM,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACzC,OAAO,EAAE,CAAC;QACV,OAAO;KACP;IAED,IAAI,KAAK,CAAC,QAAQ,EAAE;QACnB,MAAM,YAAY,GAA8B,MAAM,IAAA,qBAAc,EAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAEtF,MAAM,IAAA,6BAAe,EAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAE,CAAC,CAAC;KAC9E;SAAM,IAAI,KAAK,CAAC,OAAO,EAAE;QACzB,MAAM,YAAY,GAA8B,MAAM,IAAA,qBAAc,EAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACtF,MAAM,eAAe,GAAG,CAAC,IAAI,CAAC,CAAC;QAQ/B,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE;YACtC,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,EAAE,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,MAAM,EAAE,OAAO,CAAC,CAAC;YAC9F,MAAM,IAAA,2BAAc,EAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;SAClF;KACD;SAAM,IAAI,KAAK,CAAC,QAAQ,EAAE;QAC1B,MAAM,YAAY,GAA8B,MAAM,IAAA,qBAAc,EAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAEtF,MAAM,IAAA,iCAAiB,EACtB,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,GAAG,EACT,YAAY,EACZ,QAAQ,EACR,oBAAY,EACZ,0BAAkB,EAClB,UAAE,CACF,CAAC;KACF;IAED,OAAO,EAAE,CAAC;AACX,CAAC,CAAC;AAlDW,QAAA,cAAc,kBAkDzB;AAEF,MAAM,kBAAkB,GAAG,KAAK,EAAE,OAAgB,EAAE,KAAK,EAAE,EAAE;IAC5D,MAAM,SAAS,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAE/C,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IAEzC,MAAM,IAAA,mBAAY,EAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAEjD,MAAM,qBAAqB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IAEhD,MAAM,sBAAsB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AAClD,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,KAAK,EAAQ,EAAE;IAC7C,IAAI,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,UAAU,EAAE;QACtB,MAAM,UAAU,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC9C,OAAO,UAAU,CAAC;KAClB;IAGD,MAAM,gBAAgB,GAAG,IAAI,IAAI,EAAE,CAAC;IACpC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC/B,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAC/B,gBAAgB,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACpC,gBAAgB,CAAC,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IAC3D,OAAO,gBAAgB,CAAC;AACzB,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,KAAK,EAAE,OAAgB,EAAE,SAAe,EAAE,EAAE;IAC1E,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE;QACpC,MAAM,QAAQ,GAAG;YAChB,QAAQ,EAAE,IAAI;YACd,GAAG,EAAE,GAAG;YACR,SAAS,EAAE,SAAS;SACpB,CAAC;QACF,MAAM,MAAM,GAAG;YACd,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,cAAc,EAAE,OAAO;YACvB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;SACjC,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAC/B,IAAI,6BAAa,CAAC;YACjB,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,cAAc,EAAE,OAAO;YACvB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;SACjC,CAAC,CACF,CAAC;KAEF;AACF,CAAC,CAAC;AAEF,MAAM,sBAAsB,GAAG,KAAK,EAAE,OAAgB,EAAE,SAAe,EAAE,EAAE;IAC1E,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE;QACpC,MAAM,QAAQ,GAAG;YAChB,QAAQ,EAAE,IAAI;YACd,GAAG,EAAE,GAAG;YACR,SAAS,EAAE,SAAS;SACpB,CAAC;QACF,MAAM,MAAM,GAAG;YACd,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,cAAc,EAAE,OAAO;YACvB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;SACjC,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAC/B,IAAI,6BAAa,CAAC;YACjB,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,cAAc,EAAE,OAAO;YACvB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;SACjC,CAAC,CACF,CAAC;KAEF;AACF,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,KAAK,EAAE,OAAgB,EAAE,SAAe,EAAE,EAAE;IACzE,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE;QACpC,MAAM,QAAQ,GAAG;YAChB,OAAO,EAAE,IAAI;YACb,GAAG,EAAE,GAAG;YACR,SAAS,EAAE,SAAS;SACpB,CAAC;QACF,MAAM,MAAM,GAAG;YACd,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,cAAc,EAAE,OAAO;YACvB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;SACjC,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAC/B,IAAI,6BAAa,CAAC;YACjB,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,cAAc,EAAE,OAAO;YACvB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;SACjC,CAAC,CACF,CAAC;KAEF;AACF,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,KAAK,EAAE,OAAgB,EAAE,aAAqB,EAAE,EAAE;IAE/E,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,KAAK,GAAG,EAAE,CAAC;IACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,aAAa,EAAE,CAAC,EAAE,EAAE;QAC5C,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/B,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACvB,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACvB,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC/D,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;KAC/B;IAED,KAAK,MAAM,UAAU,IAAI,KAAK,EAAE;QAC/B,OAAO,CAAC,GAAG,CAAC,+BAA+B,EAAE,UAAU,CAAC,CAAC;QACzD,MAAM,QAAQ,GAAG;YAChB,UAAU,EAAE,UAAU;SACtB,CAAC;QACF,MAAM,MAAM,GAAG;YACd,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,cAAc,EAAE,OAAO;YACvB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;SACjC,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAC/B,IAAI,6BAAa,CAAC;YACjB,YAAY,EAAE,OAAO,CAAC,YAAY;YAClC,cAAc,EAAE,OAAO;YACvB,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC;SACjC,CAAC,CACF,CAAC;QAEF,MAAM,IAAA,wBAAK,EAAC,EAAE,CAAC,CAAC;KAChB;AACF,CAAC,CAAC","sourcesContent":["/* eslint-disable @typescript-eslint/no-use-before-define */\r\nimport { InvokeCommand, LambdaClient } from '@aws-sdk/client-lambda';\r\nimport { S3, logBeforeTimeout, sleep } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { Context } from 'aws-lambda';\r\nimport { InternalBgsRow } from '../../internal-model';\r\nimport { buildTrinketStats } from '../../solo/hourly/trinkets/trinket-stats';\r\nimport { buildHeroStats } from './hero-stats';\r\nimport { readRowsFromS3, saveRowsOnS3 } from './rows';\r\nimport { buildQuestStats } from '../../solo/hourly/quest-stats';\r\n\r\nexport const s3 = new S3();\r\nconst allCards = new AllCardsService();\r\nconst lambda = new LambdaClient({\r\n\tregion: process.env.AWS_REGION || 'us-west-2',\r\n});\r\n\r\nconst allMmrPercentiles: (100 | 50 | 25 | 10 | 1)[] = [100, 50, 25, 10, 1];\r\n\r\nexport const STATS_BUCKET = 'static.zerotoheroes.com';\r\nexport const STATS_KEY_PREFIX = `api/bgs/duo`;\r\nexport const WORKING_ROWS_FILE = `${STATS_KEY_PREFIX}/working/working-rows-%time%.json`;\r\nexport const HOURLY_KEY_HERO = `${STATS_KEY_PREFIX}/hero-stats/%anomaly%mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;\r\nexport const HOURLY_KEY_QUEST = `${STATS_KEY_PREFIX}/quest-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;\r\nexport const HOURLY_KEY_TRINKET = `${STATS_KEY_PREFIX}/trinket-stats/mmr-%mmrPercentile%/hourly/%startDate%.gz.json`;\r\n\r\nexport default async (event, context: Context): Promise<any> => {\r\n\tawait handleNewStats(event, context);\r\n};\r\n\r\nexport const handleNewStats = async (event, context: Context) => {\r\n\tconst cleanup = logBeforeTimeout(context);\r\n\t// logger.log('event', event);\r\n\tawait allCards.initializeCardsDb();\r\n\r\n\tif (event.catchUp) {\r\n\t\tawait dispatchCatchUpEvents(context, +event.catchUp);\r\n\t\tcleanup();\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (!event.statsV2 && !event.questsV2 && !event.trinkets) {\r\n\t\tawait dispatchMainEvents(context, event);\r\n\t\tcleanup();\r\n\t\treturn;\r\n\t}\r\n\r\n\tif (event.questsV2) {\r\n\t\tconst lastHourRows: readonly InternalBgsRow[] = await readRowsFromS3(event.startDate);\r\n\t\t// logger.log('building quest stats', event.timePeriod, event.startDate, lastHourRows?.length);\r\n\t\tawait buildQuestStats(event.startDate, event.mmr, lastHourRows, allCards, s3);\r\n\t} else if (event.statsV2) {\r\n\t\tconst lastHourRows: readonly InternalBgsRow[] = await readRowsFromS3(event.startDate);\r\n\t\tconst uniqueAnomalies = [null];\r\n\t\t// [\r\n\t\t// \tnull,\r\n\t\t// \t...lastHourRows\r\n\t\t// \t\t.flatMap((r) => r.bgsAnomalies?.split(','))\r\n\t\t// \t\t.filter((a) => a)\r\n\t\t// \t\t.filter((value, index, self) => self.indexOf(value) === index),\r\n\t\t// ];\r\n\t\tfor (const anomaly of uniqueAnomalies) {\r\n\t\t\tconsole.log('building hero stats', event.startDate, event.mmr, lastHourRows?.length, anomaly);\r\n\t\t\tawait buildHeroStats(event.startDate, event.mmr, anomaly, lastHourRows, allCards);\r\n\t\t}\r\n\t} else if (event.trinkets) {\r\n\t\tconst lastHourRows: readonly InternalBgsRow[] = await readRowsFromS3(event.startDate);\r\n\t\t// logger.log('building hero stats', event.startDate, lastHourRows?.length);\r\n\t\tawait buildTrinketStats(\r\n\t\t\tevent.startDate,\r\n\t\t\tevent.mmr,\r\n\t\t\tlastHourRows,\r\n\t\t\tallCards,\r\n\t\t\tSTATS_BUCKET,\r\n\t\t\tHOURLY_KEY_TRINKET,\r\n\t\t\ts3,\r\n\t\t);\r\n\t}\r\n\r\n\tcleanup();\r\n};\r\n\r\nconst dispatchMainEvents = async (context: Context, event) => {\r\n\tconst startDate = buildProcessStartDate(event);\r\n\t// End one hour later\r\n\tconst endDate = new Date(startDate);\r\n\tendDate.setHours(endDate.getHours() + 1);\r\n\r\n\tawait saveRowsOnS3(startDate, endDate, allCards);\r\n\r\n\tawait dispatchStatsV2Lambda(context, startDate);\r\n\t// await dispatchQuestsV2Lambda(context, startDate);\r\n\tawait dispatchTrinketsLambda(context, startDate);\r\n};\r\n\r\nconst buildProcessStartDate = (event): Date => {\r\n\tif (event?.targetDate) {\r\n\t\tconst targetDate = new Date(event.targetDate);\r\n\t\treturn targetDate;\r\n\t}\r\n\r\n\t// Start from the start of the current hour\r\n\tconst processStartDate = new Date();\r\n\tprocessStartDate.setMinutes(0);\r\n\tprocessStartDate.setSeconds(0);\r\n\tprocessStartDate.setMilliseconds(0);\r\n\tprocessStartDate.setHours(processStartDate.getHours() - 1);\r\n\treturn processStartDate;\r\n};\r\n\r\nconst dispatchTrinketsLambda = async (context: Context, startDate: Date) => {\r\n\tfor (const mmr of allMmrPercentiles) {\r\n\t\tconst newEvent = {\r\n\t\t\ttrinkets: true,\r\n\t\t\tmmr: mmr,\r\n\t\t\tstartDate: startDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tconsole.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda.send(\r\n\t\t\tnew InvokeCommand({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t}),\r\n\t\t);\r\n\t\t// logger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst dispatchQuestsV2Lambda = async (context: Context, startDate: Date) => {\r\n\tfor (const mmr of allMmrPercentiles) {\r\n\t\tconst newEvent = {\r\n\t\t\tquestsV2: true,\r\n\t\t\tmmr: mmr,\r\n\t\t\tstartDate: startDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tconsole.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda.send(\r\n\t\t\tnew InvokeCommand({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t}),\r\n\t\t);\r\n\t\t// logger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst dispatchStatsV2Lambda = async (context: Context, startDate: Date) => {\r\n\tfor (const mmr of allMmrPercentiles) {\r\n\t\tconst newEvent = {\r\n\t\t\tstatsV2: true,\r\n\t\t\tmmr: mmr,\r\n\t\t\tstartDate: startDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\tconsole.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda.send(\r\n\t\t\tnew InvokeCommand({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t}),\r\n\t\t);\r\n\t\t// logger.log('\\tinvocation result', result);\r\n\t}\r\n};\r\n\r\nconst dispatchCatchUpEvents = async (context: Context, daysInThePast: number) => {\r\n\t// Build a list of hours for the last `daysInThePast` days, in the format YYYY-MM-ddTHH:mm:ss.sssZ\r\n\tconst now = new Date();\r\n\tconst hours = [];\r\n\tfor (let i = 0; i < 24 * daysInThePast; i++) {\r\n\t\tconst baseDate = new Date(now);\r\n\t\tbaseDate.setMinutes(0);\r\n\t\tbaseDate.setSeconds(0);\r\n\t\tbaseDate.setMilliseconds(0);\r\n\t\tconst hour = new Date(baseDate.getTime() - i * 60 * 60 * 1000);\r\n\t\thours.push(hour.toISOString());\r\n\t}\r\n\r\n\tfor (const targetDate of hours) {\r\n\t\tconsole.log('dispatching catch-up for date', targetDate);\r\n\t\tconst newEvent = {\r\n\t\t\ttargetDate: targetDate,\r\n\t\t};\r\n\t\tconst params = {\r\n\t\t\tFunctionName: context.functionName,\r\n\t\t\tInvocationType: 'Event',\r\n\t\t\tLogType: 'Tail',\r\n\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t};\r\n\t\t// console.log('\\tinvoking lambda', params);\r\n\t\tconst result = await lambda.send(\r\n\t\t\tnew InvokeCommand({\r\n\t\t\t\tFunctionName: context.functionName,\r\n\t\t\t\tInvocationType: 'Event',\r\n\t\t\t\tLogType: 'Tail',\r\n\t\t\t\tPayload: JSON.stringify(newEvent),\r\n\t\t\t}),\r\n\t\t);\r\n\t\t// console.log('\\tinvocation result', result);\r\n\t\tawait sleep(50);\r\n\t}\r\n};\r\n"]}
@@ -6,7 +6,7 @@ const util_functions_1 = require("../../common/util-functions");
6
6
  const builders_1 = require("./builders");
7
7
  const utils_1 = require("./utils");
8
8
  const buildHeroStatsForMmr = (rows, allCards) => {
9
- const groupedByHero = (0, aws_lambda_utils_1.groupByFunction)((row) => row.heroCardId)(rows);
9
+ const groupedByHero = (0, aws_lambda_utils_1.groupByFunction)(rows, (row) => row.heroCardId);
10
10
  return Object.values(groupedByHero).flatMap((data) => buildStatsForSingleHero(data, rows));
11
11
  };
12
12
  exports.buildHeroStatsForMmr = buildHeroStatsForMmr;
@@ -36,7 +36,7 @@ const buildStatsForSingleHero = (rowsForHero, allRows) => {
36
36
  standardDeviation: (0, util_functions_1.round)(standardDeviation),
37
37
  standardDeviationOfTheMean: (0, util_functions_1.round)(standardDeviationOfTheMean),
38
38
  conservativePositionEstimate: (0, util_functions_1.round)(averagePosition + 3 * standardDeviationOfTheMean),
39
- placementDistributionRaw: placementDistribution,
39
+ placementDistribution: placementDistribution,
40
40
  combatWinrateRaw: rawCombatWinrates,
41
41
  warbandStatsRaw: rawWarbandStats,
42
42
  tribeStats: tribeStats,