diff --git a/deno.jsonc b/deno.jsonc index 8c7261b..5712c60 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -4,7 +4,6 @@ "oak/": "https://deno.land/x/oak@v12.5.0/" }, "tasks": { - // TODO: Remove `--unstable` once KV becomes stable "dev": "deno run --unstable --allow-net --allow-read --watch src/index.ts", "lume": "echo \"import 'lume/cli.ts'\" | deno run --unstable -A -", "build": "deno task lume", diff --git a/deno.lock b/deno.lock index db5aaff..c514122 100644 --- a/deno.lock +++ b/deno.lock @@ -1,5 +1,131 @@ { - "version": "2", + "version": "3", + "packages": { + "specifiers": { + "npm:date-fns@2.30.0": "npm:date-fns@2.30.0", + "npm:highlight.js@11.8.0": "npm:highlight.js@11.8.0", + "npm:markdown-it-attrs@4.1.6": "npm:markdown-it-attrs@4.1.6_markdown-it@13.0.1", + "npm:markdown-it-deflist@2.1.0": "npm:markdown-it-deflist@2.1.0", + "npm:markdown-it@13.0.1": "npm:markdown-it@13.0.1", + "npm:nunjucks@3.2.4": "npm:nunjucks@3.2.4", + "npm:react-dom@18.2.0": "npm:react-dom@18.2.0_react@18.2.0", + "npm:react@18.2.0": "npm:react@18.2.0" + }, + "npm": { + "@babel/runtime@7.22.5": { + "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", + "dependencies": { + "regenerator-runtime": "regenerator-runtime@0.13.11" + } + }, + "a-sync-waterfall@1.0.1": { + "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==", + "dependencies": {} + }, + "argparse@2.0.1": { + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dependencies": {} + }, + "asap@2.0.6": { + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dependencies": {} + }, + "commander@5.1.0": { + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dependencies": {} + }, + "date-fns@2.30.0": { + "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", + "dependencies": { + "@babel/runtime": "@babel/runtime@7.22.5" + } + }, + "entities@3.0.1": { + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", + "dependencies": {} + }, + "highlight.js@11.8.0": { + "integrity": "sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg==", + "dependencies": {} + }, + "js-tokens@4.0.0": { + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dependencies": {} + }, + "linkify-it@4.0.1": { + "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==", + "dependencies": { + "uc.micro": "uc.micro@1.0.6" + } + }, + "loose-envify@1.4.0": { + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "js-tokens@4.0.0" + } + }, + "markdown-it-attrs@4.1.6_markdown-it@13.0.1": { + "integrity": "sha512-O7PDKZlN8RFMyDX13JnctQompwrrILuz2y43pW2GagcwpIIElkAdfeek+erHfxUOlXWPsjFeWmZ8ch1xtRLWpA==", + "dependencies": { + "markdown-it": "markdown-it@13.0.1" + } + }, + "markdown-it-deflist@2.1.0": { + "integrity": "sha512-3OuqoRUlSxJiuQYu0cWTLHNhhq2xtoSFqsZK8plANg91+RJQU1ziQ6lA2LzmFAEes18uPBsHZpcX6We5l76Nzg==", + "dependencies": {} + }, + "markdown-it@13.0.1": { + "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==", + "dependencies": { + "argparse": "argparse@2.0.1", + "entities": "entities@3.0.1", + "linkify-it": "linkify-it@4.0.1", + "mdurl": "mdurl@1.0.1", + "uc.micro": "uc.micro@1.0.6" + } + }, + "mdurl@1.0.1": { + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dependencies": {} + }, + "nunjucks@3.2.4": { + "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==", + "dependencies": { + "a-sync-waterfall": "a-sync-waterfall@1.0.1", + "asap": "asap@2.0.6", + "commander": "commander@5.1.0" + } + }, + "react-dom@18.2.0_react@18.2.0": { + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "loose-envify@1.4.0", + "react": "react@18.2.0", + "scheduler": "scheduler@0.23.0" + } + }, + "react@18.2.0": { + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "loose-envify@1.4.0" + } + }, + "regenerator-runtime@0.13.11": { + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dependencies": {} + }, + "scheduler@0.23.0": { + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "loose-envify@1.4.0" + } + }, + "uc.micro@1.0.6": { + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dependencies": {} + } + } + }, "remote": { "https://deno.land/std@0.170.0/_util/asserts.ts": "d0844e9b62510f89ce1f9878b046f6a57bf88f208a10304aab50efcb48365272", "https://deno.land/std@0.170.0/_util/os.ts": "8a33345f74990e627b9dfe2de9b040004b08ea5146c7c9e8fe9a29070d193934", @@ -103,7 +229,6 @@ "https://deno.land/std@0.188.0/streams/write_all.ts": "aec90152978581ea62d56bb53a5cbf487e6a89c902f87c5969681ffbdf32b998", "https://deno.land/std@0.188.0/streams/writer_from_stream_writer.ts": "07c7ee025151a190f37fc42cbb01ff93afc949119ebddc6e0d0df14df1bf6950", "https://deno.land/std@0.188.0/streams/zip_readable_streams.ts": "a9d81aa451240f79230add674809dbee038d93aabe286e2d9671e66591fc86ca", - "https://deno.land/std@0.188.0/types.d.ts": "dbaeb2c4d7c526db9828fc8df89d8aecf53b9ced72e0c4568f97ddd8cda616a4", "https://deno.land/std@0.190.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462", "https://deno.land/std@0.190.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3", "https://deno.land/std@0.190.0/async/abortable.ts": "fd682fa46f3b7b16b4606a5ab52a7ce309434b76f820d3221bdfb862719a15d7", @@ -399,137 +524,10 @@ "https://deno.land/x/oak@v12.5.0/send.ts": "5ec49f106294593f468317a0c885da4f3274bf6d0fe9e16a7304391730b4f4fb", "https://deno.land/x/oak@v12.5.0/structured_clone.ts": "c3888b14d1eec558345bfbf13d0993d59bd45aaa8588444e35dd558c3a921cd8", "https://deno.land/x/oak@v12.5.0/testing.ts": "37d684d57bb8e5150fb5eb2677e66b04dcb422709cf2c5a74c1df94d52aa02e2", - "https://deno.land/x/oak@v12.5.0/types.d.ts": "bca5f38683ca2bb2b1ec841324a3c2e1c468e734151c9526af61c9257b016aca", "https://deno.land/x/oak@v12.5.0/util.ts": "0a3fdffb114859c2de84e1783efa3a544af4d2af8c6f08e0d25655de9d3e69bb", "https://deno.land/x/path_to_regexp@v6.2.1/index.ts": "894060567837bae8fc9c5cbd4d0a05e9024672083d5883b525c031eea940e556", "https://esm.sh/react@18.2.0/jsx-runtime": "914a55a07c388d345c5a0c11616ee5282242e8b8dfd0d505b83500ea04fd9870", "https://esm.sh/stable/react@18.2.0/denonext/jsx-runtime.js": "54d8a51c6ca025380abd2d5302e4a9b38ff835d9759c4657e52314f587eaf6bf", "https://esm.sh/stable/react@18.2.0/denonext/react.mjs": "3c4f23bcfc53b256fcfaf6f834fa9f584c3bb7be667b2682c6cb6ba8ef88f8e6" - }, - "npm": { - "specifiers": { - "date-fns@2.30.0": "date-fns@2.30.0", - "highlight.js@11.8.0": "highlight.js@11.8.0", - "markdown-it-attrs@4.1.6": "markdown-it-attrs@4.1.6_markdown-it@13.0.1", - "markdown-it-deflist@2.1.0": "markdown-it-deflist@2.1.0", - "markdown-it@13.0.1": "markdown-it@13.0.1", - "nunjucks@3.2.4": "nunjucks@3.2.4", - "react-dom@18.2.0": "react-dom@18.2.0_react@18.2.0", - "react@18.2.0": "react@18.2.0" - }, - "packages": { - "@babel/runtime@7.22.5": { - "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", - "dependencies": { - "regenerator-runtime": "regenerator-runtime@0.13.11" - } - }, - "a-sync-waterfall@1.0.1": { - "integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==", - "dependencies": {} - }, - "argparse@2.0.1": { - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dependencies": {} - }, - "asap@2.0.6": { - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dependencies": {} - }, - "commander@5.1.0": { - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "dependencies": {} - }, - "date-fns@2.30.0": { - "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==", - "dependencies": { - "@babel/runtime": "@babel/runtime@7.22.5" - } - }, - "entities@3.0.1": { - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dependencies": {} - }, - "highlight.js@11.8.0": { - "integrity": "sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg==", - "dependencies": {} - }, - "js-tokens@4.0.0": { - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dependencies": {} - }, - "linkify-it@4.0.1": { - "integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==", - "dependencies": { - "uc.micro": "uc.micro@1.0.6" - } - }, - "loose-envify@1.4.0": { - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "js-tokens@4.0.0" - } - }, - "markdown-it-attrs@4.1.6_markdown-it@13.0.1": { - "integrity": "sha512-O7PDKZlN8RFMyDX13JnctQompwrrILuz2y43pW2GagcwpIIElkAdfeek+erHfxUOlXWPsjFeWmZ8ch1xtRLWpA==", - "dependencies": { - "markdown-it": "markdown-it@13.0.1" - } - }, - "markdown-it-deflist@2.1.0": { - "integrity": "sha512-3OuqoRUlSxJiuQYu0cWTLHNhhq2xtoSFqsZK8plANg91+RJQU1ziQ6lA2LzmFAEes18uPBsHZpcX6We5l76Nzg==", - "dependencies": {} - }, - "markdown-it@13.0.1": { - "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==", - "dependencies": { - "argparse": "argparse@2.0.1", - "entities": "entities@3.0.1", - "linkify-it": "linkify-it@4.0.1", - "mdurl": "mdurl@1.0.1", - "uc.micro": "uc.micro@1.0.6" - } - }, - "mdurl@1.0.1": { - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dependencies": {} - }, - "nunjucks@3.2.4": { - "integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==", - "dependencies": { - "a-sync-waterfall": "a-sync-waterfall@1.0.1", - "asap": "asap@2.0.6", - "commander": "commander@5.1.0" - } - }, - "react-dom@18.2.0_react@18.2.0": { - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dependencies": { - "loose-envify": "loose-envify@1.4.0", - "react": "react@18.2.0", - "scheduler": "scheduler@0.23.0" - } - }, - "react@18.2.0": { - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dependencies": { - "loose-envify": "loose-envify@1.4.0" - } - }, - "regenerator-runtime@0.13.11": { - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dependencies": {} - }, - "scheduler@0.23.0": { - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "loose-envify@1.4.0" - } - }, - "uc.micro@1.0.6": { - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dependencies": {} - } - } } } diff --git a/src/controllers/pokemon.controller.ts b/src/controllers/pokemon.controller.ts index 081e777..7b70ff3 100644 --- a/src/controllers/pokemon.controller.ts +++ b/src/controllers/pokemon.controller.ts @@ -1,6 +1,6 @@ import { getQuery } from 'oak/helpers.ts'; import { RouterMiddleware } from 'oak/mod.ts'; -import { Pokemon, PokemonOfTheDay } from '../models/pokemon.ts'; +import { Pokemon } from '../models/pokemon.ts'; export const getPokemon: RouterMiddleware< '/', @@ -31,7 +31,7 @@ export const getPokemon: RouterMiddleware< }; export const getPokemonDetail: RouterMiddleware<'/:idOrName'> = async ( - context, + context ) => { const idOrName = Number.isNaN(Number(context.params.idOrName)) ? decodeURIComponent(context.params.idOrName!).toLowerCase() @@ -56,30 +56,13 @@ export const getPokemonDetail: RouterMiddleware<'/:idOrName'> = async ( }; export const getPokemonOfTheDay: RouterMiddleware<'/potd'> = async ( - context, + context ) => { - const pool = 905; - const todaysDate = new Date().toDateString(); - try { const kv = await Deno.openKv(); - const { value } = await kv.get(['potd']); - if (value && value.date === todaysDate) { - context.response.body = value.pokemon; - kv.close(); - } else { - const randomNumber = Math.ceil(Math.random() * pool); - const { value: pokemonData } = await kv.get([ - 'pokemon', - randomNumber, - ]); - await kv.set(['potd'], { - pokemon: pokemonData, - date: todaysDate, - }); - context.response.body = pokemonData; - kv.close(); - } + const { value } = await kv.get(['potd']); + context.response.body = value; + kv.close(); } catch (error) { console.log(error); context.throw(500, 'Internal server error'); @@ -87,13 +70,13 @@ export const getPokemonOfTheDay: RouterMiddleware<'/potd'> = async ( }; export const migratePokemonToKv: RouterMiddleware<'/migrate'> = async ( - context, + context ) => { const body = context.request.body({ type: 'json' }); const { id } = await body.value; const p: Pokemon = JSON.parse( - await Deno.readTextFile(`assets/data/${id}.json`), + await Deno.readTextFile(`assets/data/${id}.json`) ); const primaryKey = ['pokemon', p.id]; @@ -114,3 +97,16 @@ export const migratePokemonToKv: RouterMiddleware<'/migrate'> = async ( context.response.body = 'Success!'; }; + +export const setPokemonOfTheDay = async () => { + const pool = 905; + const kv = await Deno.openKv(); + + const randomNumber = Math.ceil(Math.random() * pool); + const { value: pokemonData } = await kv.get([ + 'pokemon', + randomNumber, + ]); + await kv.set(['potd'], pokemonData); + kv.close(); +}; diff --git a/src/index.ts b/src/index.ts index 6520d5d..f25a880 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ import { oakCors } from 'https://deno.land/x/cors@v1.2.2/mod.ts'; import { Application } from 'https://deno.land/x/oak@v12.5.0/mod.ts'; +import { setPokemonOfTheDay } from './controllers/pokemon.controller.ts'; import PokemonRouter from './routes/pokemon.route.ts'; const app = new Application(); @@ -20,3 +21,5 @@ app.use(async (context, next) => { app.use(PokemonRouter.routes(), PokemonRouter.allowedMethods()); app.listen({ port: 8000 }); + +Deno.cron('potd', '0 0 * * *', setPokemonOfTheDay); diff --git a/src/models/pokemon.ts b/src/models/pokemon.ts index c4e5c80..d729d77 100644 --- a/src/models/pokemon.ts +++ b/src/models/pokemon.ts @@ -17,8 +17,3 @@ export type Pokemon = { stats: Record; locations: string[]; }; - -export type PokemonOfTheDay = { - pokemon: Pokemon; - date: string; -};