diff --git a/src/http/get-benefits/index.js b/src/http/get-benefits/index.js index 9755a25..4a2c225 100644 --- a/src/http/get-benefits/index.js +++ b/src/http/get-benefits/index.js @@ -5,6 +5,7 @@ const { getDefinitions } = require("@architect/shared/s3"); // Definitions will be loaded from benefits-recs-defs.json in S3. // We keep it outside the handler to cache it between Lambda runs. +/** @type {import('./node_modules/@architect/shared/s3.js').Definitions} */ let definitions = {}; /** Core function for get-benefits. */ @@ -19,9 +20,7 @@ exports.handler = arc.http.async(async (req) => { const language = req.query.language || "en"; const allLinks = assembleLinks(definitions, language, host); - console.log("All:" + allLinks.length); const links = await applyRules(definitions, allLinks, host); - console.log("Filtered:" + links.length); const data = { header: "Apply for more benefits!", tagline: "You might be able to get:", diff --git a/src/shared/links.js b/src/shared/links.js index 1408a3c..5c5e403 100644 --- a/src/shared/links.js +++ b/src/shared/links.js @@ -47,12 +47,23 @@ const addAnalytics = (linkUrl, analytics, hostDef) => { } }; +/** + * @typedef TargetLink + * @type {object} + * @property {string} id + * @property {string} language + * @property {string} lead + * @property {string} catalyst + * @property {string} url + * @property {string} graphic + */ + /** * Construct link objects for the given language and host. - * @param {object} definitions + * @param {import('./s3.js').Definitions} definitions * @param {string} language * @param {string} host - * @returns + * @returns {TargetLink[]} */ exports.assembleLinks = (definitions, language, host) => { const { targets, hosts: hostDefs } = definitions; @@ -76,9 +87,6 @@ exports.assembleLinks = (definitions, language, host) => { const catalyst = translations[langKey]?.catalyst || translations.en.catalyst || ""; - const description = - translations[langKey]?.description || translations.en.description || ""; - const linkUrl = translations[langKey]?.url || translations.en.url || ""; const analytics = @@ -87,11 +95,8 @@ exports.assembleLinks = (definitions, language, host) => { const urlWithAnalytics = addAnalytics(linkUrl, analytics, hostDef); return { - linktext: lead, // linktext depreciated - program: catalyst, // program depreciated lead, catalyst, - description, // description possibly depreciated url: urlWithAnalytics, graphic, language: langKey, diff --git a/src/shared/rules.js b/src/shared/rules.js index 947a524..0a533ed 100644 --- a/src/shared/rules.js +++ b/src/shared/rules.js @@ -1,3 +1,6 @@ +const url = require("./url"); +const { getThrottles } = require("./throttles"); + /** * rules.js * Welcome to rules. @@ -8,10 +11,19 @@ * Rules are processed in a specific order. */ -const url = require("./url"); -const { getThrottles } = require("./throttles"); +/** + * @callback Rule + * @param {import('./links.js').TargetLink[]} links + * @param {object} params + * @param {string} [params.host] + * @param {import('./s3.js').Throttle[]} [params.throttles] + * @returns {import('./links.js').TargetLink[]} + */ -/** Remove links that have exceeded daily throttles. */ +/** + * Remove links that have exceeded daily throttles. + * @type {Rule} + */ const removeThrottledLinks = (links, { throttles }) => links.filter((link) => { const blockingThrottles = throttles.filter( @@ -22,21 +34,33 @@ const removeThrottledLinks = (links, { throttles }) => return blockingThrottles.length < 1; }); -/** Remove links that point back to the same host site as the widget. */ +/** + * Remove links that point back to the same host site as the widget. + * @type {Rule} + */ const removeLinkBacks = (links, { host }) => links.filter((link) => !url.matchHosts(host, link.url)); -/** Randomize the order of the links. */ +/** + * Randomize the order of the links. + * @type {Rule} + */ const randomizeOrder = (links) => links .map((link) => ({ link, sort: Math.random() })) .sort((a, b) => a.sort - b.sort) .map(({ link }) => link); -/** Reduce the list of links to just the top three. */ +/** + * Reduce the list of links to just the top three. + * @type {Rule} + */ const pickTopThree = (links) => links.slice(0, 3); -/** Active rules, in order. */ +/** + * Active rules, in order. + * @type {Rule[]} + */ const rules = [ removeThrottledLinks, removeLinkBacks, @@ -44,7 +68,13 @@ const rules = [ pickTopThree, ]; -/** Apply the rules to the list of links. */ +/** + * Apply the rules to the list of links. + * @param {import('./s3.js').Definitions} definitions + * @param {import('./links.js').TargetLink[]} allLinks + * @param {string} host + * @returns {Promise} + */ const applyRules = async (definitions, allLinks, host) => { const throttles = await getThrottles(definitions); diff --git a/src/shared/s3.js b/src/shared/s3.js index dc531fa..3ecddeb 100644 --- a/src/shared/s3.js +++ b/src/shared/s3.js @@ -2,7 +2,57 @@ const { GetObjectCommand, S3Client } = require("@aws-sdk/client-s3"); const s3 = new S3Client({}); -/** Grab the definitions file from S3. */ +/** + * @typedef Definitions + * @type {object} + * @property {string} name + * @property {string} description + * @property {string} updated + * @property {Target[]} targets + * @property {Throttle[]} throttles + * @property {Host[]} hosts + */ + +/** + * @typedef Target + * @type {object} + * @property {string} id + * @property {object.} translations + * @property {string[]} throttle_ids + */ + +/** + * @typedef Translation + * @type {object} + * @property {string} id + * @property {string} url + * @property {string} icon + * @property {string} analytics + * @property {string} lead + * @property {string} catalyst + */ + +/** + * @typedef Throttle + * @type {object} + * @property {string} id + * @property {number} [limit] + * @property {string} [start] + * @property {string} [end] + * @property {string[]} urls + * @property {boolean} [exceeded] + */ + +/** + * @typedef Host + * @type {object} + * @property {string} id + * @property {string[]} urls + */ + +/** Grab the definitions file from S3. + * @returns {Promise} + */ exports.getDefinitions = async () => { const command = new GetObjectCommand({ Bucket: "cdn.innovation.ca.gov", diff --git a/src/shared/throttles.js b/src/shared/throttles.js index 4a8a180..2cbd500 100644 --- a/src/shared/throttles.js +++ b/src/shared/throttles.js @@ -1,6 +1,10 @@ const arc = require("@architect/functions"); -/** Retrieve throttles. */ +/** + * Retrieve throttles. + * @param {import('./s3.js').Definitions} definitions + * @returns {Promise} + */ exports.getThrottles = async (definitions) => { const { throttles: throttleDefs } = definitions; diff --git a/src/shared/url.js b/src/shared/url.js index 21ceb2f..d7152ec 100644 --- a/src/shared/url.js +++ b/src/shared/url.js @@ -1,11 +1,11 @@ +const { URL } = require("url"); + /** * url.js * A collection of functions for comparing URLs. * We'll be doing a lot of that when targetting links to send to the widget. */ -const { URL } = require("url"); - /** * Get a URL object from a string, if possible. * @param {string} input A string representation of the URL. @@ -60,6 +60,12 @@ const comparePaths = (pUrl1, pUrl2) => { return normalizePath(pUrl1) === normalizePath(pUrl2); }; +/** + * See if two URLs have matching hostnames and pathnames. + * @param {URL} pUrl1 A URL object for the first URL. + * @param {URL} pUrl2 A URL object for the second URL. + * @returns {boolean} + */ const compare = (pUrl1, pUrl2) => { return compareHosts(pUrl1, pUrl2) && comparePaths(pUrl1, pUrl2); };