@firestone-hs/content-craetor-input 0.0.2

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bgs-heroes.js","sourceRoot":"","sources":["../../src/types/bgs-heroes.ts"],"names":[],"mappings":"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2yBpB,CAAC","sourcesContent":["/* eslint-disable no-extra-boolean-cast */\r\nimport { PatchInfo, S3 } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { gzipSync } from 'zlib';\r\nimport { Input } from '../input-model';\r\nimport { deepEqual } from '../utils';\r\n\r\nconst bucket = 'static.zerotoheroes.com';\r\nconst fileKey = 'hearthstone/data/battlegrounds-strategies/bgs-hero-strategies.gz.json';\r\n\r\nexport const processBgsHero = async (input: Input, bgPatch: PatchInfo, allCards: AllCardsService) => {\r\n\tconst author = input.author;\r\n\tconsole.debug('processing', author);\r\n\tconst existing = await loadExistingInfo();\r\n\tconst result = existing.heroes;\r\n\t// console.debug('loaded existing info');\r\n\tfor (const cardTip of input.data) {\r\n\t\t// console.debug('processing card', cardTip.cardId);\r\n\t\tlet existingCardTip = result.find((t) => t.cardId === cardTip.cardId);\r\n\t\tif (!existingCardTip) {\r\n\t\t\texistingCardTip = {\r\n\t\t\t\tcardId: cardTip.cardId,\r\n\t\t\t\tname: allCards.getCard(cardTip.cardId)?.name,\r\n\t\t\t\ttips: [],\r\n\t\t\t};\r\n\t\t\tresult.push(existingCardTip);\r\n\t\t}\r\n\t\tif (!!cardTip.tip?.length) {\r\n\t\t\tlet existingTip = existingCardTip.tips.find((t) => t.author === author);\r\n\t\t\tif (!existingTip) {\r\n\t\t\t\texistingTip = {\r\n\t\t\t\t\tauthor: author,\r\n\t\t\t\t} as CardTip;\r\n\t\t\t\texistingCardTip.tips.push(existingTip);\r\n\t\t\t}\r\n\t\t\texistingTip.language = 'enUS';\r\n\t\t\tif (\r\n\t\t\t\t!deepEqual(existingTip.summary, cardTip.tip) ||\r\n\t\t\t\t(cardTip.patchNumber && existingTip.patch !== cardTip.patchNumber)\r\n\t\t\t) {\r\n\t\t\t\texistingTip.summary = cardTip.tip;\r\n\t\t\t\texistingTip.date = new Date().toISOString().substring(0, 10);\r\n\t\t\t\texistingTip.patch = bgPatch.number;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\texistingCardTip.tips = existingCardTip.tips.filter((t) => t.author !== author);\r\n\t\t}\r\n\t}\r\n\tconsole.debug('built aggregated tips', result);\r\n\tawait saveInfo({\r\n\t\theroes: result,\r\n\t\tcurves: existing.curves,\r\n\t});\r\n\tconsole.debug('saved aggregated tips');\r\n};\r\n\r\nconst loadExistingInfo = async (): Promise<{ heroes: CardItem[]; curves: any[] }> => {\r\n\tconst s3 = new S3();\r\n\t// console.debug('created s3');\r\n\tconst asString = await s3.readGzipContent(bucket, fileKey, 5);\r\n\t// console.debug('loaded existing info', asString?.length);\r\n\tif (!asString) {\r\n\t\treturn { heroes: [], curves: JSON.parse(curvesString) };\r\n\t}\r\n\treturn JSON.parse(asString);\r\n};\r\n\r\nconst saveInfo = async (info: { heroes: CardItem[]; curves: any[] }) => {\r\n\tconst s3 = new S3();\r\n\tawait s3.writeFile(gzipSync(JSON.stringify(info)), bucket, fileKey, 'application/json', 'gzip');\r\n};\r\n\r\ninterface CardItem {\r\n\tcardId: string;\r\n\tname: string;\r\n\ttips: CardTip[];\r\n}\r\ninterface CardTip {\r\n\tsummary: string;\r\n\tauthor: string;\r\n\tlanguage: string;\r\n\tpatch: number;\r\n\tdate: string;\r\n}\r\n\r\nconst curvesString = `\r\n[\r\n\t\t{\r\n\t\t\t\"id\": \"basic\",\r\n\t\t\t\"name\": \"Basic Curve\",\r\n\t\t\t\"notes\": \"Stronger with a token start, turn 4 shop RNG weakness. No heropower requirement.\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\"sell\", \"buy\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t\"buy\",\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\", \"roll\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 7,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 4\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"roll\",\r\n\t\t\t\t\t\t\"buy\"\r\n\t\t\t\t\t]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"fast-basic\",\r\n\t\t\t\"name\": \"Fast Basic Curve\",\r\n\t\t\t\"notes\": \"Stronger with a token start, turn 4 shop RNG weakness. No heropower requirement.\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\"sell\", \"buy\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t\"buy\",\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 4\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"roll\"\r\n\t\t\t\t\t]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"jeef\",\r\n\t\t\t\"name\": \"Jeef Curve\",\r\n\t\t\t\"notes\": \"Uses tier 1 economy and strong pairs for a flexible start to the game with its variations.\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"buy\",\r\n\t\t\t\t\t\t\"sell\"\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 4\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"buy\",\r\n\t\t\t\t\t\t\"sell\"\r\n\t\t\t\t\t]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"fast-jeef\",\r\n\t\t\t\"name\": \"Fast Jeef Curve\",\r\n\t\t\t\"notes\": \"Uses tier 1 economy and strong pairs for a flexible start to the game with its variations. Pushes levels quickly.\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"buy\",\r\n\t\t\t\t\t\t\"sell\"\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 4\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\", \"roll\", \"roll\"]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"slow-jeef\",\r\n\t\t\t\"name\": \"Slow Jeef Curve\",\r\n\t\t\t\"notes\": \"Uses tier 1 economy and strong pairs for a flexible start to the game with its variations. Stays on tier 2 to solidify the board.\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"buy\",\r\n\t\t\t\t\t\t\"sell\"\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"buy\",\r\n\t\t\t\t\t\t\"sell\"\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"roll\"\r\n\t\t\t\t\t]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"warrior\",\r\n\t\t\t\"name\": \"Warrior Curve\",\r\n\t\t\t\"notes\": \"A highly valueable line if tier 1 economy and forced triples are strong.\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"sell\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t\"sell\",\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 4\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"roll\"\r\n\t\t\t\t\t]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"extended-warrior\",\r\n\t\t\t\"name\": \"Extended Warrior Curve\",\r\n\t\t\t\"notes\": \"A highly valueable line if tier 1 economy and forced triples are strong. This variant is a fallback option in case a triple hasn't shown up yet playing regular warrior curve.\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"sell\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"roll\"\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 7,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 4\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"roll\"\r\n\t\t\t\t\t]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"basic-yogg\",\r\n\t\t\t\"name\": \"Basic Yogg Curve\",\r\n\t\t\t\"notes\": \"Uses a 2-cost heropower to get to tier 3 faster.\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"hero-power\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\"hero-power\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"sell\",\r\n\t\t\t\t\t\t\"hero-power\"\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\"hero-power\", \"sell\", \"buy\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 4\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"hero-power\"\r\n\t\t\t\t\t]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"aggro-yogg\",\r\n\t\t\t\"name\": \"Aggro Yogg Curve\",\r\n\t\t\t\"notes\": \"Uses a 2-cost heropower to get good tier 1s on board before leveling to 3 faster\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"hero-power\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"sell\", \"hero-power\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"hero-power\"\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\"hero-power\", \"roll\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"hero-power\"\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 4\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"hero-power\"\r\n\t\t\t\t\t]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"rafaam\",\r\n\t\t\t\"name\": \"Rafaam Curve\",\r\n\t\t\t\"notes\": \"Clean leveling using 1-cost heropower, 2-cost heropower with economy, or tavern tippers\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"hero-power\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"roll\", \"hero-power\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"buy\",\r\n\t\t\t\t\t\t\"hero-power\"\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"hero-power\"\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 4\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"hero-power\"\r\n\t\t\t\t\t]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"slow-rafaam\",\r\n\t\t\t\"name\": \"Slow Rafaam Curve\",\r\n\t\t\t\"notes\": \"Clean leveling using 1-cost heropower, 2-cost heropower with economy, or tavern tippers. Cut off on tier 2 to get stronger\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"hero-power\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"roll\", \"hero-power\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"buy\",\r\n\t\t\t\t\t\t\"hero-power\"\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\", \"hero-power\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"buy\"\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 7,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 4\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"3-on-3\",\r\n\t\t\t\"name\": \"3 on 3 (Level on 8)\",\r\n\t\t\t\"notes\": \"Sacrifices early health to get very fast access to tier 3 minions, then pushes levels\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t\"sell\",\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t\"buy\",\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 4\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 7,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\", \"roll\", \"roll\", \"roll\"]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"3-on-3-bis\",\r\n\t\t\t\"name\": \"3 on 3 (Level on 9)\",\r\n\t\t\t\"notes\": \"Sacrifices early health to fill the board with tier 3 minions\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t\"sell\",\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\", \"roll\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 7,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 4\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"roll\",\r\n\t\t\t\t\t\t\"roll\",\r\n\t\t\t\t\t\t\"buy\"\r\n\t\t\t\t\t]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"4-on-4\",\r\n\t\t\t\"name\": \"4 on 4\",\r\n\t\t\t\"notes\": \"Sacrifices early health to get very fast access to tier 3 minions. A fallback option in case of a bad shop after 3 on 3; requires economy\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"buy-token\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t\"sell\",\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t\"sell\",\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 4\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\", \"roll\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 7,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\", \"roll\", \"roll\", \"roll\"]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"toki\",\r\n\t\t\t\"name\": \"Toki Curve\",\r\n\t\t\t\"notes\": \"A way to use 1 cost heropowers that don't provide tempo\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"buy-token\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\"sell\", \"buy\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"hero-power\"\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\"hero-power\", \"buy\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\"roll\", \"buy\", \"roll\", \"buy\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 7,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 7\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"id\": \"pocky\",\r\n\t\t\t\"name\": \"Pocky Curve\",\r\n\t\t\t\"notes\": \"A very niche use for 1 cost heropowers\",\r\n\t\t\t\"steps\": [\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 1,\r\n\t\t\t\t\t\"actions\": [\"buy-token\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 2,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 2\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 3,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"hero-power\", \"roll\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 4,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 3\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"sell\",\r\n\t\t\t\t\t\t\"hero-power\"\r\n\t\t\t\t\t]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 5,\r\n\t\t\t\t\t\"actions\": [\"buy\", \"buy\", \"hero-power\"]\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t\t\"turn\": 6,\r\n\t\t\t\t\t\"actions\": [\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\t\"type\": \"level\",\r\n\t\t\t\t\t\t\t\"param\": 4\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\"roll\",\r\n\t\t\t\t\t\t\"buy\"\r\n\t\t\t\t\t]\r\n\t\t\t\t}\r\n\t\t\t]\r\n\t\t}\r\n\t]\r\n`;\r\n"]}
@@ -0,0 +1,4 @@
1
+ import { PatchInfo } from '@firestone-hs/aws-lambda-utils';
2
+ import { AllCardsService } from '@firestone-hs/reference-data';
3
+ import { Input } from '../input-model';
4
+ export declare const processBgsTrinket: (input: Input, bgPatch: PatchInfo, allCards: AllCardsService) => Promise<void>;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processBgsTrinket = void 0;
4
+ const aws_lambda_utils_1 = require("@firestone-hs/aws-lambda-utils");
5
+ const zlib_1 = require("zlib");
6
+ const utils_1 = require("../utils");
7
+ const bucket = 'static.zerotoheroes.com';
8
+ const fileKey = 'hearthstone/data/battlegrounds-strategies/bgs-trinket-strategies.gz.json';
9
+ const processBgsTrinket = async (input, bgPatch, allCards) => {
10
+ const author = input.author;
11
+ console.debug('processing', author);
12
+ const result = await loadExistingInfo();
13
+ for (const cardTip of input.data) {
14
+ let existingCardTip = result.find((t) => t.cardId === cardTip.cardId);
15
+ if (!existingCardTip) {
16
+ existingCardTip = {
17
+ cardId: cardTip.cardId,
18
+ name: allCards.getCard(cardTip.cardId)?.name,
19
+ tips: [],
20
+ };
21
+ result.push(existingCardTip);
22
+ }
23
+ if (!!cardTip.tip?.length) {
24
+ let existingTip = existingCardTip.tips.find((t) => t.author === author);
25
+ if (!existingTip) {
26
+ existingTip = {
27
+ author: author,
28
+ };
29
+ existingCardTip.tips.push(existingTip);
30
+ }
31
+ existingTip.language = 'enUS';
32
+ if (!(0, utils_1.deepEqual)(existingTip.summary, cardTip.tip)) {
33
+ existingTip.summary = cardTip.tip;
34
+ existingTip.date = new Date().toISOString().substring(0, 10);
35
+ existingTip.patch = bgPatch.number;
36
+ }
37
+ }
38
+ else {
39
+ existingCardTip.tips = existingCardTip.tips.filter((t) => t.author !== author);
40
+ }
41
+ }
42
+ console.debug('built aggregated tips', result);
43
+ await saveInfo(result);
44
+ console.debug('saved aggregated tips');
45
+ };
46
+ exports.processBgsTrinket = processBgsTrinket;
47
+ const loadExistingInfo = async () => {
48
+ const s3 = new aws_lambda_utils_1.S3();
49
+ const asString = await s3.readGzipContent(bucket, fileKey, 5);
50
+ if (!asString) {
51
+ return [];
52
+ }
53
+ return JSON.parse(asString);
54
+ };
55
+ const saveInfo = async (info) => {
56
+ const s3 = new aws_lambda_utils_1.S3();
57
+ await s3.writeFile((0, zlib_1.gzipSync)(JSON.stringify(info)), bucket, fileKey, 'application/json', 'gzip');
58
+ };
59
+ //# sourceMappingURL=trinkets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trinkets.js","sourceRoot":"","sources":["../../src/types/trinkets.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable no-extra-boolean-cast */\r\nimport { PatchInfo, S3 } from '@firestone-hs/aws-lambda-utils';\r\nimport { AllCardsService } from '@firestone-hs/reference-data';\r\nimport { gzipSync } from 'zlib';\r\nimport { Input } from '../input-model';\r\nimport { deepEqual } from '../utils';\r\n\r\nconst bucket = 'static.zerotoheroes.com';\r\nconst fileKey = 'hearthstone/data/battlegrounds-strategies/bgs-trinket-strategies.gz.json';\r\n\r\nexport const processBgsTrinket = async (input: Input, bgPatch: PatchInfo, allCards: AllCardsService) => {\r\n\tconst author = input.author;\r\n\tconsole.debug('processing', author);\r\n\tconst result = await loadExistingInfo();\r\n\t// console.debug('loaded existing info');\r\n\tfor (const cardTip of input.data) {\r\n\t\t// console.debug('processing card', cardTip.cardId);\r\n\t\tlet existingCardTip = result.find((t) => t.cardId === cardTip.cardId);\r\n\t\tif (!existingCardTip) {\r\n\t\t\texistingCardTip = {\r\n\t\t\t\tcardId: cardTip.cardId,\r\n\t\t\t\tname: allCards.getCard(cardTip.cardId)?.name,\r\n\t\t\t\ttips: [],\r\n\t\t\t};\r\n\t\t\tresult.push(existingCardTip);\r\n\t\t}\r\n\t\tif (!!cardTip.tip?.length) {\r\n\t\t\tlet existingTip = existingCardTip.tips.find((t) => t.author === author);\r\n\t\t\tif (!existingTip) {\r\n\t\t\t\texistingTip = {\r\n\t\t\t\t\tauthor: author,\r\n\t\t\t\t} as CardTip;\r\n\t\t\t\texistingCardTip.tips.push(existingTip);\r\n\t\t\t}\r\n\t\t\texistingTip.language = 'enUS';\r\n\t\t\tif (!deepEqual(existingTip.summary, cardTip.tip)) {\r\n\t\t\t\texistingTip.summary = cardTip.tip;\r\n\t\t\t\texistingTip.date = new Date().toISOString().substring(0, 10);\r\n\t\t\t\texistingTip.patch = bgPatch.number;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\texistingCardTip.tips = existingCardTip.tips.filter((t) => t.author !== author);\r\n\t\t}\r\n\t}\r\n\tconsole.debug('built aggregated tips', result);\r\n\tawait saveInfo(result);\r\n\tconsole.debug('saved aggregated tips');\r\n};\r\n\r\nconst loadExistingInfo = async (): Promise<CardItem[]> => {\r\n\tconst s3 = new S3();\r\n\t// console.debug('created s3');\r\n\tconst asString = await s3.readGzipContent(bucket, fileKey, 5);\r\n\t// console.debug('loaded existing info', asString?.length);\r\n\tif (!asString) {\r\n\t\treturn [];\r\n\t}\r\n\treturn JSON.parse(asString);\r\n};\r\n\r\nconst saveInfo = async (info: CardItem[]) => {\r\n\tconst s3 = new S3();\r\n\tawait s3.writeFile(gzipSync(JSON.stringify(info)), bucket, fileKey, 'application/json', 'gzip');\r\n};\r\n\r\ninterface CardItem {\r\n\tcardId: string;\r\n\tname: string;\r\n\ttips: CardTip[];\r\n}\r\ninterface CardTip {\r\n\tsummary: string;\r\n\tauthor: string;\r\n\tlanguage: string;\r\n\tpatch: number;\r\n\tdate: string;\r\n}\r\n"]}
@@ -0,0 +1,4 @@
1
+ export declare const deepEqual: (a: any, b: any) => any;
2
+ export type Mutable<T> = {
3
+ -readonly [P in keyof T]: T[P];
4
+ };
package/dist/utils.js ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.deepEqual = void 0;
7
+ const deep_equal_1 = __importDefault(require("deep-equal"));
8
+ const deepEqual = (a, b) => (0, deep_equal_1.default)(a, b, {
9
+ strict: false,
10
+ });
11
+ exports.deepEqual = deepEqual;
12
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;;;;;AAAA,4DAA+B;AAExB,MAAM,SAAS,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACjC,IAAA,oBAAK,EAAC,CAAC,EAAE,CAAC,EAAE;IACX,MAAM,EAAE,KAAK;CACb,CAAC,CAAC;AAHS,QAAA,SAAS,aAGlB","sourcesContent":["import equal from 'deep-equal';\r\n\r\nexport const deepEqual = (a, b) =>\r\n\tequal(a, b, {\r\n\t\tstrict: false,\r\n\t});\r\n\r\nexport type Mutable<T> = {\r\n\t-readonly [P in keyof T]: T[P];\r\n};\r\n"]}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@firestone-hs/content-craetor-input",
3
+ "version": "0.0.2",
4
+ "description": "",
5
+ "scripts": {
6
+ "lint": "eslint --color --fix --ext .ts .",
7
+ "build": "webpack --color",
8
+ "package": "sam package --template-file template.yaml --s3-bucket com.zerotoheroes.artifact --output-template-file template.packaged.yaml",
9
+ "deploy": "sam deploy --template-file template.packaged.yaml --stack-name ContentCreatorInputStack --capabilities CAPABILITY_IAM",
10
+ "full-deploy": "npm run build && npm run package && npm run deploy",
11
+ "publish-version": "rm -rf dist && tsc && rm -rf dist/node_modules && npm publish --access public"
12
+ },
13
+ "repository": {},
14
+ "author": "",
15
+ "license": "MIT",
16
+ "private": false,
17
+ "main": "dist/_public-api.js",
18
+ "types": "dist/_public-api.d.ts",
19
+ "files": [
20
+ "dist/**/*"
21
+ ],
22
+ "dependencies": {
23
+ "@firestone-hs/aws-lambda-utils": "^1.0.5",
24
+ "@firestone-hs/reference-data": "^2.0.82",
25
+ "aws-sdk": "^2.1040.0",
26
+ "deep-equal": "^2.2.3",
27
+ "mysql": "^2.18.1",
28
+ "serverless-mysql": "^1.5.4",
29
+ "sqlstring": "^2.3.2"
30
+ },
31
+ "devDependencies": {
32
+ "@types/aws-lambda": "8.10.31",
33
+ "@types/jsonwebtoken": "^9.0.2",
34
+ "@types/jszip": "^3.1.7",
35
+ "@types/mysql": "^2.15.7",
36
+ "@types/node": "^18.16.0",
37
+ "@types/pako": "^1.0.1",
38
+ "@typescript-eslint/eslint-plugin": "^5.59.1",
39
+ "@typescript-eslint/parser": "^5.59.1",
40
+ "eslint": "^8.39.0",
41
+ "eslint-config-prettier": "^8.8.0",
42
+ "eslint-plugin-prettier": "^4.2.1",
43
+ "eslint-webpack-plugin": "^4.0.1",
44
+ "prettier": "^2.8.8",
45
+ "ts-loader": "^9.4.2",
46
+ "ts-node": "^10.9.1",
47
+ "typescript": "^5.0.4",
48
+ "webpack": "^5.80.0",
49
+ "webpack-cli": "^5.0.2",
50
+ "yaml-cfn": "^0.2.2"
51
+ }
52
+ }