├── .vscode ├── extensions.json └── settings.json ├── LICENSE ├── README.md ├── deno.json ├── deno.lock ├── dev.ts ├── fresh.gen.ts ├── islands └── TodoListView.tsx ├── main.ts ├── routes ├── [listId].tsx ├── _app.tsx └── index.tsx ├── services └── database.ts ├── shared └── api.ts ├── static ├── favicon.ico ├── logo.svg └── screenshot.png └── twind.config.ts /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "denoland.vscode-deno" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true, 3 | "deno.lint": true, 4 | "deno.unstable": true, 5 | "editor.defaultFormatter": "denoland.vscode-deno" 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Deno 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `showcase_todo` 2 | 3 | ![Screenshot](./static/screenshot.png) 4 | 5 | Collaborative todo-list app built with Deno and Fresh. 6 | 7 | ## Features 8 | 9 | - Global persistent data and real-time collaboration using Deno KV 10 | - Sends updates from server to clients using EventSource (server-sent events) 11 | 12 | This project is hosted on Deno Deploy: 13 | 14 | - Served from 35 edge locations around the world 15 | - Scales automatically 16 | - Data is a globally distributed Deno KV store with no setup required 17 | - Code is deployed automatically when pushed to GitHub 18 | - Automatic HTTPS (even for custom domains) 19 | - Free for most hobby use cases 20 | 21 | ## Running locally 22 | 23 | To run the app locally, you will need to install Deno. Then run from the root of 24 | this repository: 25 | 26 | ``` 27 | deno task start 28 | ``` 29 | -------------------------------------------------------------------------------- /deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": { 3 | "start": "deno run -A --unstable --watch=static/,routes/ dev.ts", 4 | "build": "deno run -A dev.ts build", 5 | "preview": "deno run -A main.ts" 6 | }, 7 | "compilerOptions": { "jsx": "react-jsx", "jsxImportSource": "preact" }, 8 | "imports": { 9 | "$fresh/": "https://deno.land/x/fresh@1.6.1/", 10 | "preact": "https://esm.sh/preact@10.19.2", 11 | "preact/": "https://esm.sh/preact@10.19.2/", 12 | "preact-render-to-string": "https://esm.sh/*preact-render-to-string@5.2.4", 13 | "@preact/signals": "https://esm.sh/*@preact/signals@1.2.1", 14 | "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.5.0", 15 | "twind": "https://esm.sh/twind@0.16.19", 16 | "twind/": "https://esm.sh/twind@0.16.19/", 17 | "$std/": "https://deno.land/std@0.177.0/", 18 | "zod": "https://esm.sh/zod@3.21.4", 19 | "axios-web": "https://esm.sh/axios@1.3.2?target=es2022" 20 | }, 21 | "lint": { "rules": { "tags": ["fresh", "recommended"] } }, 22 | "exclude": ["**/_fresh/*"] 23 | } 24 | -------------------------------------------------------------------------------- /deno.lock: -------------------------------------------------------------------------------- 1 | { 2 | "version": "3", 3 | "remote": { 4 | "https://deno.land/std@0.140.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74", 5 | "https://deno.land/std@0.140.0/_util/os.ts": "3b4c6e27febd119d36a416d7a97bd3b0251b77c88942c8f16ee5953ea13e2e49", 6 | "https://deno.land/std@0.140.0/bytes/bytes_list.ts": "67eb118e0b7891d2f389dad4add35856f4ad5faab46318ff99653456c23b025d", 7 | "https://deno.land/std@0.140.0/bytes/equals.ts": "fc16dff2090cced02497f16483de123dfa91e591029f985029193dfaa9d894c9", 8 | "https://deno.land/std@0.140.0/bytes/mod.ts": "763f97d33051cc3f28af1a688dfe2830841192a9fea0cbaa55f927b49d49d0bf", 9 | "https://deno.land/std@0.140.0/fmt/colors.ts": "30455035d6d728394781c10755351742dd731e3db6771b1843f9b9e490104d37", 10 | "https://deno.land/std@0.140.0/fs/_util.ts": "0fb24eb4bfebc2c194fb1afdb42b9c3dda12e368f43e8f2321f84fc77d42cb0f", 11 | "https://deno.land/std@0.140.0/fs/ensure_dir.ts": "9dc109c27df4098b9fc12d949612ae5c9c7169507660dcf9ad90631833209d9d", 12 | "https://deno.land/std@0.140.0/hash/sha256.ts": "803846c7a5a8a5a97f31defeb37d72f519086c880837129934f5d6f72102a8e8", 13 | "https://deno.land/std@0.140.0/io/buffer.ts": "bd0c4bf53db4b4be916ca5963e454bddfd3fcd45039041ea161dbf826817822b", 14 | "https://deno.land/std@0.140.0/path/_constants.ts": "df1db3ffa6dd6d1252cc9617e5d72165cd2483df90e93833e13580687b6083c3", 15 | "https://deno.land/std@0.140.0/path/_interface.ts": "ee3b431a336b80cf445441109d089b70d87d5e248f4f90ff906820889ecf8d09", 16 | "https://deno.land/std@0.140.0/path/_util.ts": "c1e9686d0164e29f7d880b2158971d805b6e0efc3110d0b3e24e4b8af2190d2b", 17 | "https://deno.land/std@0.140.0/path/common.ts": "bee563630abd2d97f99d83c96c2fa0cca7cee103e8cb4e7699ec4d5db7bd2633", 18 | "https://deno.land/std@0.140.0/path/glob.ts": "cb5255638de1048973c3e69e420c77dc04f75755524cb3b2e160fe9277d939ee", 19 | "https://deno.land/std@0.140.0/path/mod.ts": "d3e68d0abb393fb0bf94a6d07c46ec31dc755b544b13144dee931d8d5f06a52d", 20 | "https://deno.land/std@0.140.0/path/posix.ts": "293cdaec3ecccec0a9cc2b534302dfe308adb6f10861fa183275d6695faace44", 21 | "https://deno.land/std@0.140.0/path/separator.ts": "fe1816cb765a8068afb3e8f13ad272351c85cbc739af56dacfc7d93d710fe0f9", 22 | "https://deno.land/std@0.140.0/path/win32.ts": "31811536855e19ba37a999cd8d1b62078235548d67902ece4aa6b814596dd757", 23 | "https://deno.land/std@0.140.0/streams/conversion.ts": "712585bfa0172a97fb68dd46e784ae8ad59d11b88079d6a4ab098ff42e697d21", 24 | "https://deno.land/std@0.177.0/encoding/base58.ts": "c0316bee1275c5e44909506869e96bb61750fef714e3e6eb3b1d5e876b6efe47", 25 | "https://deno.land/std@0.181.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462", 26 | "https://deno.land/std@0.181.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3", 27 | "https://deno.land/std@0.181.0/fs/_util.ts": "65381f341af1ff7f40198cee15c20f59951ac26e51ddc651c5293e24f9ce6f32", 28 | "https://deno.land/std@0.181.0/fs/ensure_dir.ts": "dc64c4c75c64721d4e3fb681f1382f803ff3d2868f08563ff923fdd20d071c40", 29 | "https://deno.land/std@0.181.0/fs/expand_glob.ts": "e4f56259a0a70fe23f05215b00de3ac5e6ba46646ab2a06ebbe9b010f81c972a", 30 | "https://deno.land/std@0.181.0/fs/walk.ts": "ea95ffa6500c1eda6b365be488c056edc7c883a1db41ef46ec3bf057b1c0fe32", 31 | "https://deno.land/std@0.181.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", 32 | "https://deno.land/std@0.181.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b", 33 | "https://deno.land/std@0.181.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0", 34 | "https://deno.land/std@0.181.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000", 35 | "https://deno.land/std@0.181.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1", 36 | "https://deno.land/std@0.181.0/path/mod.ts": "bf718f19a4fdd545aee1b06409ca0805bd1b68ecf876605ce632e932fe54510c", 37 | "https://deno.land/std@0.181.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d", 38 | "https://deno.land/std@0.181.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1", 39 | "https://deno.land/std@0.181.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba", 40 | "https://deno.land/std@0.201.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", 41 | "https://deno.land/std@0.201.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", 42 | "https://deno.land/std@0.201.0/encoding/base32.ts": "c329447451560ec692b9eb4d1badb6437f1d419ddbb21c1f994b0fe0b6b66cc8", 43 | "https://deno.land/std@0.201.0/fs/_util.ts": "fbf57dcdc9f7bc8128d60301eece608246971a7836a3bb1e78da75314f08b978", 44 | "https://deno.land/std@0.201.0/fs/copy.ts": "23cc1c465babe5ca4d69778821e2f8addc44593e30a5ca0b902b3784eed75bb6", 45 | "https://deno.land/std@0.201.0/fs/empty_dir.ts": "2e52cd4674d18e2e007175c80449fc3d263786a1361e858d9dfa9360a6581b47", 46 | "https://deno.land/std@0.201.0/fs/ensure_dir.ts": "dc64c4c75c64721d4e3fb681f1382f803ff3d2868f08563ff923fdd20d071c40", 47 | "https://deno.land/std@0.201.0/fs/ensure_file.ts": "39ac83cc283a20ec2735e956adf5de3e8a3334e0b6820547b5772f71c49ae083", 48 | "https://deno.land/std@0.201.0/fs/ensure_link.ts": "c15e69c48556d78aae31b83e0c0ece04b7b8bc0951412f5b759aceb6fde7f0ac", 49 | "https://deno.land/std@0.201.0/fs/ensure_symlink.ts": "b389c8568f0656d145ac7ece472afe710815cccbb2ebfd19da7978379ae143fe", 50 | "https://deno.land/std@0.201.0/fs/eol.ts": "f1f2eb348a750c34500741987b21d65607f352cf7205f48f4319d417fff42842", 51 | "https://deno.land/std@0.201.0/fs/exists.ts": "cb59a853d84871d87acab0e7936a4dac11282957f8e195102c5a7acb42546bb8", 52 | "https://deno.land/std@0.201.0/fs/expand_glob.ts": "52b8b6f5b1fa585c348250da1c80ce5d820746cb4a75d874b3599646f677d3a7", 53 | "https://deno.land/std@0.201.0/fs/mod.ts": "bc3d0acd488cc7b42627044caf47d72019846d459279544e1934418955ba4898", 54 | "https://deno.land/std@0.201.0/fs/move.ts": "b4f8f46730b40c32ea3c0bc8eb0fd0e8139249a698883c7b3756424cf19785c9", 55 | "https://deno.land/std@0.201.0/fs/walk.ts": "a16146724a6aaf9efdb92023a74e9805195c3469900744ce5de4113b07b29779", 56 | "https://deno.land/std@0.201.0/jsonc/mod.ts": "b88dce28eb3645667caa856538ae2fe87af51410822544a0b45a4177ef3bd7dd", 57 | "https://deno.land/std@0.201.0/jsonc/parse.ts": "c1096e2b7ffb4996d7ed841dfdb29a4fccc78edcc55299beaa20d6fe5facf7b6", 58 | "https://deno.land/std@0.201.0/path/_basename.ts": "057d420c9049821f983f784fd87fa73ac471901fb628920b67972b0f44319343", 59 | "https://deno.land/std@0.201.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", 60 | "https://deno.land/std@0.201.0/path/_dirname.ts": "355e297236b2218600aee7a5301b937204c62e12da9db4b0b044993d9e658395", 61 | "https://deno.land/std@0.201.0/path/_extname.ts": "eaaa5aae1acf1f03254d681bd6a8ce42a9cb5b7ff2213a9d4740e8ab31283664", 62 | "https://deno.land/std@0.201.0/path/_format.ts": "4a99270d6810f082e614309164fad75d6f1a483b68eed97c830a506cc589f8b4", 63 | "https://deno.land/std@0.201.0/path/_from_file_url.ts": "6eadfae2e6f63ad9ee46b26db4a1b16583055c0392acedfb50ed2fc694b6f581", 64 | "https://deno.land/std@0.201.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b", 65 | "https://deno.land/std@0.201.0/path/_is_absolute.ts": "05dac10b5e93c63198b92e3687baa2be178df5321c527dc555266c0f4f51558c", 66 | "https://deno.land/std@0.201.0/path/_join.ts": "815f5e85b042285175b1492dd5781240ce126c23bd97bad6b8211fe7129c538e", 67 | "https://deno.land/std@0.201.0/path/_normalize.ts": "a19ec8706b2707f9dd974662a5cd89fad438e62ab1857e08b314a8eb49a34d81", 68 | "https://deno.land/std@0.201.0/path/_os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3", 69 | "https://deno.land/std@0.201.0/path/_parse.ts": "0f9b0ff43682dd9964eb1c4398610c4e165d8db9d3ac9d594220217adf480cfa", 70 | "https://deno.land/std@0.201.0/path/_relative.ts": "27bdeffb5311a47d85be26d37ad1969979359f7636c5cd9fcf05dcd0d5099dc5", 71 | "https://deno.land/std@0.201.0/path/_resolve.ts": "7a3616f1093735ed327e758313b79c3c04ea921808ca5f19ddf240cb68d0adf6", 72 | "https://deno.land/std@0.201.0/path/_to_file_url.ts": "a141e4a525303e1a3a0c0571fd024552b5f3553a2af7d75d1ff3a503dcbb66d8", 73 | "https://deno.land/std@0.201.0/path/_to_namespaced_path.ts": "0d5f4caa2ed98ef7a8786286df6af804b50e38859ae897b5b5b4c8c5930a75c8", 74 | "https://deno.land/std@0.201.0/path/_util.ts": "4e191b1bac6b3bf0c31aab42e5ca2e01a86ab5a0d2e08b75acf8585047a86221", 75 | "https://deno.land/std@0.201.0/path/basename.ts": "bdfa5a624c6a45564dc6758ef2077f2822978a6dbe77b0a3514f7d1f81362930", 76 | "https://deno.land/std@0.201.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000", 77 | "https://deno.land/std@0.201.0/path/dirname.ts": "b6533f4ee4174a526dec50c279534df5345836dfdc15318400b08c62a62a39dd", 78 | "https://deno.land/std@0.201.0/path/extname.ts": "62c4b376300795342fe1e4746c0de518b4dc9c4b0b4617bfee62a2973a9555cf", 79 | "https://deno.land/std@0.201.0/path/format.ts": "110270b238514dd68455a4c54956215a1aff7e37e22e4427b7771cefe1920aa5", 80 | "https://deno.land/std@0.201.0/path/from_file_url.ts": "9f5cb58d58be14c775ec2e57fc70029ac8b17ed3bd7fe93e475b07280adde0ac", 81 | "https://deno.land/std@0.201.0/path/glob.ts": "593e2c3573883225c25c5a21aaa8e9382a696b8e175ea20a3b6a1471ad17aaed", 82 | "https://deno.land/std@0.201.0/path/is_absolute.ts": "0b92eb35a0a8780e9f16f16bb23655b67dace6a8e0d92d42039e518ee38103c1", 83 | "https://deno.land/std@0.201.0/path/join.ts": "31c5419f23d91655b08ec7aec403f4e4cd1a63d39e28f6e42642ea207c2734f8", 84 | "https://deno.land/std@0.201.0/path/mod.ts": "6e1efb0b13121463aedb53ea51dabf5639a3172ab58c89900bbb72b486872532", 85 | "https://deno.land/std@0.201.0/path/normalize.ts": "6ea523e0040979dd7ae2f1be5bf2083941881a252554c0f32566a18b03021955", 86 | "https://deno.land/std@0.201.0/path/parse.ts": "be8de342bb9e1924d78dc4d93c45215c152db7bf738ec32475560424b119b394", 87 | "https://deno.land/std@0.201.0/path/posix.ts": "0a1c1952d132323a88736d03e92bd236f3ed5f9f079e5823fae07c8d978ee61b", 88 | "https://deno.land/std@0.201.0/path/relative.ts": "8bedac226afd360afc45d451a6c29fabceaf32978526bcb38e0c852661f66c61", 89 | "https://deno.land/std@0.201.0/path/resolve.ts": "133161e4949fc97f9ca67988d51376b0f5eef8968a6372325ab84d39d30b80dc", 90 | "https://deno.land/std@0.201.0/path/separator.ts": "40a3e9a4ad10bef23bc2cd6c610291b6c502a06237c2c4cd034a15ca78dedc1f", 91 | "https://deno.land/std@0.201.0/path/to_file_url.ts": "00e6322373dd51ad109956b775e4e72e5f9fa68ce2c6b04e4af2a6eed3825d31", 92 | "https://deno.land/std@0.201.0/path/to_namespaced_path.ts": "1b1db3055c343ab389901adfbda34e82b7386bcd1c744d54f9c1496ee0fd0c3d", 93 | "https://deno.land/std@0.201.0/path/win32.ts": "8b3f80ef7a462511d5e8020ff490edcaa0a0d118f1b1e9da50e2916bdd73f9dd", 94 | "https://deno.land/std@0.208.0/assert/_constants.ts": "8a9da298c26750b28b326b297316cdde860bc237533b07e1337c021379e6b2a9", 95 | "https://deno.land/std@0.208.0/assert/_diff.ts": "58e1461cc61d8eb1eacbf2a010932bf6a05b79344b02ca38095f9b805795dc48", 96 | "https://deno.land/std@0.208.0/assert/_format.ts": "a69126e8a469009adf4cf2a50af889aca364c349797e63174884a52ff75cf4c7", 97 | "https://deno.land/std@0.208.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", 98 | "https://deno.land/std@0.208.0/assert/assert_almost_equals.ts": "e15ca1f34d0d5e0afae63b3f5d975cbd18335a132e42b0c747d282f62ad2cd6c", 99 | "https://deno.land/std@0.208.0/assert/assert_array_includes.ts": "6856d7f2c3544bc6e62fb4646dfefa3d1df5ff14744d1bca19f0cbaf3b0d66c9", 100 | "https://deno.land/std@0.208.0/assert/assert_equals.ts": "d8ec8a22447fbaf2fc9d7c3ed2e66790fdb74beae3e482855d75782218d68227", 101 | "https://deno.land/std@0.208.0/assert/assert_exists.ts": "407cb6b9fb23a835cd8d5ad804e2e2edbbbf3870e322d53f79e1c7a512e2efd7", 102 | "https://deno.land/std@0.208.0/assert/assert_false.ts": "0ccbcaae910f52c857192ff16ea08bda40fdc79de80846c206bfc061e8c851c6", 103 | "https://deno.land/std@0.208.0/assert/assert_greater.ts": "ae2158a2d19313bf675bf7251d31c6dc52973edb12ac64ac8fc7064152af3e63", 104 | "https://deno.land/std@0.208.0/assert/assert_greater_or_equal.ts": "1439da5ebbe20855446cac50097ac78b9742abe8e9a43e7de1ce1426d556e89c", 105 | "https://deno.land/std@0.208.0/assert/assert_instance_of.ts": "3aedb3d8186e120812d2b3a5dea66a6e42bf8c57a8bd927645770bd21eea554c", 106 | "https://deno.land/std@0.208.0/assert/assert_is_error.ts": "c21113094a51a296ffaf036767d616a78a2ae5f9f7bbd464cd0197476498b94b", 107 | "https://deno.land/std@0.208.0/assert/assert_less.ts": "aec695db57db42ec3e2b62e97e1e93db0063f5a6ec133326cc290ff4b71b47e4", 108 | "https://deno.land/std@0.208.0/assert/assert_less_or_equal.ts": "5fa8b6a3ffa20fd0a05032fe7257bf985d207b85685fdbcd23651b70f928c848", 109 | "https://deno.land/std@0.208.0/assert/assert_match.ts": "c4083f80600bc190309903c95e397a7c9257ff8b5ae5c7ef91e834704e672e9b", 110 | "https://deno.land/std@0.208.0/assert/assert_not_equals.ts": "9f1acab95bd1f5fc9a1b17b8027d894509a745d91bac1718fdab51dc76831754", 111 | "https://deno.land/std@0.208.0/assert/assert_not_instance_of.ts": "0c14d3dfd9ab7a5276ed8ed0b18c703d79a3d106102077ec437bfe7ed912bd22", 112 | "https://deno.land/std@0.208.0/assert/assert_not_match.ts": "3796a5b0c57a1ce6c1c57883dd4286be13a26f715ea662318ab43a8491a13ab0", 113 | "https://deno.land/std@0.208.0/assert/assert_not_strict_equals.ts": "4cdef83df17488df555c8aac1f7f5ec2b84ad161b6d0645ccdbcc17654e80c99", 114 | "https://deno.land/std@0.208.0/assert/assert_object_match.ts": "d8fc2867cfd92eeacf9cea621e10336b666de1874a6767b5ec48988838370b54", 115 | "https://deno.land/std@0.208.0/assert/assert_rejects.ts": "45c59724de2701e3b1f67c391d6c71c392363635aad3f68a1b3408f9efca0057", 116 | "https://deno.land/std@0.208.0/assert/assert_strict_equals.ts": "b1f538a7ea5f8348aeca261d4f9ca603127c665e0f2bbfeb91fa272787c87265", 117 | "https://deno.land/std@0.208.0/assert/assert_string_includes.ts": "b821d39ebf5cb0200a348863c86d8c4c4b398e02012ce74ad15666fc4b631b0c", 118 | "https://deno.land/std@0.208.0/assert/assert_throws.ts": "63784e951475cb7bdfd59878cd25a0931e18f6dc32a6077c454b2cd94f4f4bcd", 119 | "https://deno.land/std@0.208.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", 120 | "https://deno.land/std@0.208.0/assert/equal.ts": "9f1a46d5993966d2596c44e5858eec821859b45f783a5ee2f7a695dfc12d8ece", 121 | "https://deno.land/std@0.208.0/assert/fail.ts": "c36353d7ae6e1f7933d45f8ea51e358c8c4b67d7e7502028598fe1fea062e278", 122 | "https://deno.land/std@0.208.0/assert/mod.ts": "37c49a26aae2b254bbe25723434dc28cd7532e444cf0b481a97c045d110ec085", 123 | "https://deno.land/std@0.208.0/assert/unimplemented.ts": "d56fbeecb1f108331a380f72e3e010a1f161baa6956fd0f7cf3e095ae1a4c75a", 124 | "https://deno.land/std@0.208.0/assert/unreachable.ts": "4600dc0baf7d9c15a7f7d234f00c23bca8f3eba8b140286aaca7aa998cf9a536", 125 | "https://deno.land/std@0.208.0/async/delay.ts": "a6142eb44cdd856b645086af2b811b1fcce08ec06bb7d50969e6a872ee9b8659", 126 | "https://deno.land/std@0.208.0/cli/parse_args.ts": "9bea02050b3f302e706871ff87ecfa3ad82cc34249adbe0dcddfaac75bdb48ff", 127 | "https://deno.land/std@0.208.0/crypto/to_hash_string.ts": "5a687ffee6b54c935a84394c8f2394c2e1bf62bbff0f855b8ab6f5669e47cc8a", 128 | "https://deno.land/std@0.208.0/datetime/constants.ts": "b63a6b702e06fa028fb2ffa25e0cf775e3b21cf7f38e53a6f219e9641894dfbb", 129 | "https://deno.land/std@0.208.0/encoding/_util.ts": "f368920189c4fe6592ab2e93bd7ded8f3065b84f95cd3e036a4a10a75649dcba", 130 | "https://deno.land/std@0.208.0/encoding/base64.ts": "81c0ecff5ccb402def58ca03d8bd245bd01da15a077d3362b568e991aa10f4d9", 131 | "https://deno.land/std@0.208.0/encoding/hex.ts": "a384101d02cd87036c708f540825feb5b073c8527a00d635e48b2e69c992a5f9", 132 | "https://deno.land/std@0.208.0/flags/mod.ts": "567a34800a33e701942cb1726dd7e627a76e4681c33ce7346ac85cf90f691a8e", 133 | "https://deno.land/std@0.208.0/fmt/colors.ts": "34b3f77432925eb72cf0bfb351616949746768620b8e5ead66da532f93d10ba2", 134 | "https://deno.land/std@0.208.0/fs/_util.ts": "fbf57dcdc9f7bc8128d60301eece608246971a7836a3bb1e78da75314f08b978", 135 | "https://deno.land/std@0.208.0/fs/copy.ts": "ca19e4837965914471df38fbd61e16f9e8adfe89f9cffb0c83615c83ea3fc2bf", 136 | "https://deno.land/std@0.208.0/fs/empty_dir.ts": "7fba29ef2d03f3503cd512616efc0535984cf1bbe7ca9d098e8b4d0d88910120", 137 | "https://deno.land/std@0.208.0/fs/ensure_dir.ts": "dc64c4c75c64721d4e3fb681f1382f803ff3d2868f08563ff923fdd20d071c40", 138 | "https://deno.land/std@0.208.0/fs/ensure_file.ts": "39ac83cc283a20ec2735e956adf5de3e8a3334e0b6820547b5772f71c49ae083", 139 | "https://deno.land/std@0.208.0/fs/ensure_link.ts": "c15e69c48556d78aae31b83e0c0ece04b7b8bc0951412f5b759aceb6fde7f0ac", 140 | "https://deno.land/std@0.208.0/fs/ensure_symlink.ts": "b389c8568f0656d145ac7ece472afe710815cccbb2ebfd19da7978379ae143fe", 141 | "https://deno.land/std@0.208.0/fs/eol.ts": "8565e1e076c5baced170236617150a7833668658e000205d896fc54084309ce1", 142 | "https://deno.land/std@0.208.0/fs/exists.ts": "cb59a853d84871d87acab0e7936a4dac11282957f8e195102c5a7acb42546bb8", 143 | "https://deno.land/std@0.208.0/fs/expand_glob.ts": "4f98c508fc9e40d6311d2f7fd88aaad05235cc506388c22dda315e095305811d", 144 | "https://deno.land/std@0.208.0/fs/mod.ts": "bc3d0acd488cc7b42627044caf47d72019846d459279544e1934418955ba4898", 145 | "https://deno.land/std@0.208.0/fs/move.ts": "b4f8f46730b40c32ea3c0bc8eb0fd0e8139249a698883c7b3756424cf19785c9", 146 | "https://deno.land/std@0.208.0/fs/walk.ts": "c1e6b43f72a46e89b630140308bd51a4795d416a416b4cfb7cd4bd1e25946723", 147 | "https://deno.land/std@0.208.0/http/server.ts": "f3cde6672e631d3e00785743cfa96bfed275618c0352c5ae84abbe5a2e0e4afc", 148 | "https://deno.land/std@0.208.0/http/status.ts": "dcbcc0f048ba8fad81228ac66e4a984c924a28c05701dddd20e0f005681d932f", 149 | "https://deno.land/std@0.208.0/jsonc/mod.ts": "b88dce28eb3645667caa856538ae2fe87af51410822544a0b45a4177ef3bd7dd", 150 | "https://deno.land/std@0.208.0/jsonc/parse.ts": "6048912a52d1ee3876a89f57ae6885f3b675bf2708700ef8d3d72acf6ef3342e", 151 | "https://deno.land/std@0.208.0/media_types/_db.ts": "7606d83e31f23ce1a7968cbaee852810c2cf477903a095696cdc62eaab7ce570", 152 | "https://deno.land/std@0.208.0/media_types/_util.ts": "0879b04cc810ff18d3dcd97d361e03c9dfb29f67d7fc4a9c6c9d387282ef5fe8", 153 | "https://deno.land/std@0.208.0/media_types/content_type.ts": "a7a3cb6a2b6e81101637afcaa9884d655b4568ded84fa7e6169bb690a87ee2aa", 154 | "https://deno.land/std@0.208.0/media_types/format_media_type.ts": "f5e1073c05526a6f5a516ac5c5587a1abd043bf1039c71cde1166aa4328c8baf", 155 | "https://deno.land/std@0.208.0/media_types/get_charset.ts": "18b88274796fda5d353806bf409eb1d2ddb3f004eb4bd311662c4cdd8ac173db", 156 | "https://deno.land/std@0.208.0/media_types/parse_media_type.ts": "31ccf2388ffab31b49500bb89fa0f5de189c8897e2ee6c9954f207637d488211", 157 | "https://deno.land/std@0.208.0/media_types/vendor/mime-db.v1.52.0.ts": "6925bbcae81ca37241e3f55908d0505724358cda3384eaea707773b2c7e99586", 158 | "https://deno.land/std@0.208.0/path/_common/assert_path.ts": "061e4d093d4ba5aebceb2c4da3318bfe3289e868570e9d3a8e327d91c2958946", 159 | "https://deno.land/std@0.208.0/path/_common/basename.ts": "0d978ff818f339cd3b1d09dc914881f4d15617432ae519c1b8fdc09ff8d3789a", 160 | "https://deno.land/std@0.208.0/path/_common/common.ts": "9e4233b2eeb50f8b2ae10ecc2108f58583aea6fd3e8907827020282dc2b76143", 161 | "https://deno.land/std@0.208.0/path/_common/constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", 162 | "https://deno.land/std@0.208.0/path/_common/dirname.ts": "2ba7fb4cc9fafb0f38028f434179579ce61d4d9e51296fad22b701c3d3cd7397", 163 | "https://deno.land/std@0.208.0/path/_common/format.ts": "11aa62e316dfbf22c126917f5e03ea5fe2ee707386555a8f513d27ad5756cf96", 164 | "https://deno.land/std@0.208.0/path/_common/from_file_url.ts": "ef1bf3197d2efbf0297a2bdbf3a61d804b18f2bcce45548ae112313ec5be3c22", 165 | "https://deno.land/std@0.208.0/path/_common/glob_to_reg_exp.ts": "5c3c2b79fc2294ec803d102bd9855c451c150021f452046312819fbb6d4dc156", 166 | "https://deno.land/std@0.208.0/path/_common/normalize.ts": "2ba7fb4cc9fafb0f38028f434179579ce61d4d9e51296fad22b701c3d3cd7397", 167 | "https://deno.land/std@0.208.0/path/_common/normalize_string.ts": "88c472f28ae49525f9fe82de8c8816d93442d46a30d6bb5063b07ff8a89ff589", 168 | "https://deno.land/std@0.208.0/path/_common/relative.ts": "1af19d787a2a84b8c534cc487424fe101f614982ae4851382c978ab2216186b4", 169 | "https://deno.land/std@0.208.0/path/_common/strip_trailing_separators.ts": "7ffc7c287e97bdeeee31b155828686967f222cd73f9e5780bfe7dfb1b58c6c65", 170 | "https://deno.land/std@0.208.0/path/_common/to_file_url.ts": "a8cdd1633bc9175b7eebd3613266d7c0b6ae0fb0cff24120b6092ac31662f9ae", 171 | "https://deno.land/std@0.208.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b", 172 | "https://deno.land/std@0.208.0/path/_os.ts": "30b0c2875f360c9296dbe6b7f2d528f0f9c741cecad2e97f803f5219e91b40a2", 173 | "https://deno.land/std@0.208.0/path/basename.ts": "04bb5ef3e86bba8a35603b8f3b69537112cdd19ce64b77f2522006da2977a5f3", 174 | "https://deno.land/std@0.208.0/path/common.ts": "f4d061c7d0b95a65c2a1a52439edec393e906b40f1caf4604c389fae7caa80f5", 175 | "https://deno.land/std@0.208.0/path/dirname.ts": "88a0a71c21debafc4da7a4cd44fd32e899462df458fbca152390887d41c40361", 176 | "https://deno.land/std@0.208.0/path/extname.ts": "2da4e2490f3b48b7121d19fb4c91681a5e11bd6bd99df4f6f47d7a71bb6ecdf2", 177 | "https://deno.land/std@0.208.0/path/format.ts": "3457530cc85d1b4bab175f9ae73998b34fd456c830d01883169af0681b8894fb", 178 | "https://deno.land/std@0.208.0/path/from_file_url.ts": "e7fa233ea1dff9641e8d566153a24d95010110185a6f418dd2e32320926043f8", 179 | "https://deno.land/std@0.208.0/path/glob.ts": "a00a81a55c02bbe074ab21a50b6495c6f7795f54cd718c824adaa92c6c9b7419", 180 | "https://deno.land/std@0.208.0/path/glob_to_regexp.ts": "74d7448c471e293d03f05ccb968df4365fed6aaa508506b6325a8efdc01d8271", 181 | "https://deno.land/std@0.208.0/path/is_absolute.ts": "67232b41b860571c5b7537f4954c88d86ae2ba45e883ee37d3dec27b74909d13", 182 | "https://deno.land/std@0.208.0/path/is_glob.ts": "567dce5c6656bdedfc6b3ee6c0833e1e4db2b8dff6e62148e94a917f289c06ad", 183 | "https://deno.land/std@0.208.0/path/join.ts": "98d3d76c819af4a11a81d5ba2dbb319f1ce9d63fc2b615597d4bcfddd4a89a09", 184 | "https://deno.land/std@0.208.0/path/join_globs.ts": "9b84d5103b63d3dbed4b2cf8b12477b2ad415c7d343f1488505162dc0e5f4db8", 185 | "https://deno.land/std@0.208.0/path/mod.ts": "3defabebc98279e62b392fee7a6937adc932a8f4dcd2471441e36c15b97b00e0", 186 | "https://deno.land/std@0.208.0/path/normalize.ts": "aa95be9a92c7bd4f9dc0ba51e942a1973e2b93d266cd74f5ca751c136d520b66", 187 | "https://deno.land/std@0.208.0/path/normalize_glob.ts": "674baa82e1c00b6cb153bbca36e06f8e0337cb8062db6d905ab5de16076ca46b", 188 | "https://deno.land/std@0.208.0/path/parse.ts": "d87ff0deef3fb495bc0d862278ff96da5a06acf0625ca27769fc52ac0d3d6ece", 189 | "https://deno.land/std@0.208.0/path/posix/_util.ts": "ecf49560fedd7dd376c6156cc5565cad97c1abe9824f4417adebc7acc36c93e5", 190 | "https://deno.land/std@0.208.0/path/posix/basename.ts": "a630aeb8fd8e27356b1823b9dedd505e30085015407caa3396332752f6b8406a", 191 | "https://deno.land/std@0.208.0/path/posix/common.ts": "e781d395dc76f6282e3f7dd8de13194abb8b04a82d109593141abc6e95755c8b", 192 | "https://deno.land/std@0.208.0/path/posix/dirname.ts": "f48c9c42cc670803b505478b7ef162c7cfa9d8e751b59d278b2ec59470531472", 193 | "https://deno.land/std@0.208.0/path/posix/extname.ts": "ee7f6571a9c0a37f9218fbf510c440d1685a7c13082c348d701396cc795e0be0", 194 | "https://deno.land/std@0.208.0/path/posix/format.ts": "b94876f77e61bfe1f147d5ccb46a920636cd3cef8be43df330f0052b03875968", 195 | "https://deno.land/std@0.208.0/path/posix/from_file_url.ts": "b97287a83e6407ac27bdf3ab621db3fccbf1c27df0a1b1f20e1e1b5acf38a379", 196 | "https://deno.land/std@0.208.0/path/posix/glob_to_regexp.ts": "6ed00c71fbfe0ccc35977c35444f94e82200b721905a60bd1278b1b768d68b1a", 197 | "https://deno.land/std@0.208.0/path/posix/is_absolute.ts": "159900a3422d11069d48395568217eb7fc105ceda2683d03d9b7c0f0769e01b8", 198 | "https://deno.land/std@0.208.0/path/posix/is_glob.ts": "ec4fbc604b9db8487f7b56ab0e759b24a971ab6a45f7b0b698bc39b8b9f9680f", 199 | "https://deno.land/std@0.208.0/path/posix/join.ts": "0c0d84bdc344876930126640011ec1b888e6facf74153ffad9ef26813aa2a076", 200 | "https://deno.land/std@0.208.0/path/posix/join_globs.ts": "f4838d54b1f60a34a40625a3293f6e583135348be1b2974341ac04743cb26121", 201 | "https://deno.land/std@0.208.0/path/posix/mod.ts": "f1b08a7f64294b7de87fc37190d63b6ce5b02889af9290c9703afe01951360ae", 202 | "https://deno.land/std@0.208.0/path/posix/normalize.ts": "11de90a94ab7148cc46e5a288f7d732aade1d616bc8c862f5560fa18ff987b4b", 203 | "https://deno.land/std@0.208.0/path/posix/normalize_glob.ts": "10a1840c628ebbab679254d5fa1c20e59106102354fb648a1765aed72eb9f3f9", 204 | "https://deno.land/std@0.208.0/path/posix/parse.ts": "199208f373dd93a792e9c585352bfc73a6293411bed6da6d3bc4f4ef90b04c8e", 205 | "https://deno.land/std@0.208.0/path/posix/relative.ts": "e2f230608b0f083e6deaa06e063943e5accb3320c28aef8d87528fbb7fe6504c", 206 | "https://deno.land/std@0.208.0/path/posix/resolve.ts": "51579d83159d5c719518c9ae50812a63959bbcb7561d79acbdb2c3682236e285", 207 | "https://deno.land/std@0.208.0/path/posix/separator.ts": "0b6573b5f3269a3164d8edc9cefc33a02dd51003731c561008c8bb60220ebac1", 208 | "https://deno.land/std@0.208.0/path/posix/to_file_url.ts": "08d43ea839ee75e9b8b1538376cfe95911070a655cd312bc9a00f88ef14967b6", 209 | "https://deno.land/std@0.208.0/path/posix/to_namespaced_path.ts": "c9228a0e74fd37e76622cd7b142b8416663a9b87db643302fa0926b5a5c83bdc", 210 | "https://deno.land/std@0.208.0/path/relative.ts": "23d45ede8b7ac464a8299663a43488aad6b561414e7cbbe4790775590db6349c", 211 | "https://deno.land/std@0.208.0/path/resolve.ts": "5b184efc87155a0af9fa305ff68a109e28de9aee81fc3e77cd01380f19daf867", 212 | "https://deno.land/std@0.208.0/path/separator.ts": "40a3e9a4ad10bef23bc2cd6c610291b6c502a06237c2c4cd034a15ca78dedc1f", 213 | "https://deno.land/std@0.208.0/path/to_file_url.ts": "edaafa089e0bce386e1b2d47afe7c72e379ff93b28a5829a5885e4b6c626d864", 214 | "https://deno.land/std@0.208.0/path/to_namespaced_path.ts": "cf8734848aac3c7527d1689d2adf82132b1618eff3cc523a775068847416b22a", 215 | "https://deno.land/std@0.208.0/path/windows/_util.ts": "f32b9444554c8863b9b4814025c700492a2b57ff2369d015360970a1b1099d54", 216 | "https://deno.land/std@0.208.0/path/windows/basename.ts": "8a9dbf7353d50afbc5b221af36c02a72c2d1b2b5b9f7c65bf6a5a2a0baf88ad3", 217 | "https://deno.land/std@0.208.0/path/windows/common.ts": "e781d395dc76f6282e3f7dd8de13194abb8b04a82d109593141abc6e95755c8b", 218 | "https://deno.land/std@0.208.0/path/windows/dirname.ts": "5c2aa541384bf0bd9aca821275d2a8690e8238fa846198ef5c7515ce31a01a94", 219 | "https://deno.land/std@0.208.0/path/windows/extname.ts": "07f4fa1b40d06a827446b3e3bcc8d619c5546b079b8ed0c77040bbef716c7614", 220 | "https://deno.land/std@0.208.0/path/windows/format.ts": "343019130d78f172a5c49fdc7e64686a7faf41553268961e7b6c92a6d6548edf", 221 | "https://deno.land/std@0.208.0/path/windows/from_file_url.ts": "d53335c12b0725893d768be3ac6bf0112cc5b639d2deb0171b35988493b46199", 222 | "https://deno.land/std@0.208.0/path/windows/glob_to_regexp.ts": "290755e18ec6c1a4f4d711c3390537358e8e3179581e66261a0cf348b1a13395", 223 | "https://deno.land/std@0.208.0/path/windows/is_absolute.ts": "245b56b5f355ede8664bd7f080c910a97e2169972d23075554ae14d73722c53c", 224 | "https://deno.land/std@0.208.0/path/windows/is_glob.ts": "ec4fbc604b9db8487f7b56ab0e759b24a971ab6a45f7b0b698bc39b8b9f9680f", 225 | "https://deno.land/std@0.208.0/path/windows/join.ts": "e6600bf88edeeef4e2276e155b8de1d5dec0435fd526ba2dc4d37986b2882f16", 226 | "https://deno.land/std@0.208.0/path/windows/join_globs.ts": "f4838d54b1f60a34a40625a3293f6e583135348be1b2974341ac04743cb26121", 227 | "https://deno.land/std@0.208.0/path/windows/mod.ts": "d7040f461465c2c21c1c68fc988ef0bdddd499912138cde3abf6ad60c7fb3814", 228 | "https://deno.land/std@0.208.0/path/windows/normalize.ts": "9deebbf40c81ef540b7b945d4ccd7a6a2c5a5992f791e6d3377043031e164e69", 229 | "https://deno.land/std@0.208.0/path/windows/normalize_glob.ts": "344ff5ed45430495b9a3d695567291e50e00b1b3b04ea56712a2acf07ab5c128", 230 | "https://deno.land/std@0.208.0/path/windows/parse.ts": "120faf778fe1f22056f33ded069b68e12447668fcfa19540c0129561428d3ae5", 231 | "https://deno.land/std@0.208.0/path/windows/relative.ts": "026855cd2c36c8f28f1df3c6fbd8f2449a2aa21f48797a74700c5d872b86d649", 232 | "https://deno.land/std@0.208.0/path/windows/resolve.ts": "5ff441ab18a2346abadf778121128ee71bda4d0898513d4639a6ca04edca366b", 233 | "https://deno.land/std@0.208.0/path/windows/separator.ts": "ae21f27015f10510ed1ac4a0ba9c4c9c967cbdd9d9e776a3e4967553c397bd5d", 234 | "https://deno.land/std@0.208.0/path/windows/to_file_url.ts": "8e9ea9e1ff364aa06fa72999204229952d0a279dbb876b7b838b2b2fea55cce3", 235 | "https://deno.land/std@0.208.0/path/windows/to_namespaced_path.ts": "e0f4d4a5e77f28a5708c1a33ff24360f35637ba6d8f103d19661255ef7bfd50d", 236 | "https://deno.land/std@0.208.0/regexp/escape.ts": "625c953f03ef0b9628c4d676fef222457b702050faf824f035f05f5f755fb362", 237 | "https://deno.land/std@0.208.0/semver/_shared.ts": "8547ccf91b36c30fb2a8a17d7081df13f4ae694c4aa44c39799eba69ad0dcb23", 238 | "https://deno.land/std@0.208.0/semver/cmp.ts": "12c30b5888afd9e414defef64f881a478ff9ab11bd329ed6c5844b74eea5c971", 239 | "https://deno.land/std@0.208.0/semver/comparator_format.ts": "329e05d914c064590ded4801fc601bf1c5d0f461c5524b1578e10f180551ef6f", 240 | "https://deno.land/std@0.208.0/semver/comparator_intersects.ts": "61920121a6c1600306dbcf8944c4cc55e45c3a1bdbefe41b79a0884bf02d9e1b", 241 | "https://deno.land/std@0.208.0/semver/comparator_max.ts": "f4cc5f528abd8aab68c66bbead732e3c59102b13a318cd8e4f8a47aa3debec76", 242 | "https://deno.land/std@0.208.0/semver/comparator_min.ts": "eea382428ebf0c50168f780898df8519c88da5a10d1f8babbfebdc89fb75942e", 243 | "https://deno.land/std@0.208.0/semver/compare.ts": "782e03b5107648bebaaebf0e33a9a7d6a0481eb88d2f7be8e857e4abbfdf42c0", 244 | "https://deno.land/std@0.208.0/semver/compare_build.ts": "5d6ebc0106f1ed46e391d6c234e071934ba30938fa818c9cc3da67c7c7494c02", 245 | "https://deno.land/std@0.208.0/semver/constants.ts": "bb0c7652c433c7ec1dad5bf18c7e7e1557efe9ddfd5e70aa6305153e76dc318c", 246 | "https://deno.land/std@0.208.0/semver/difference.ts": "966ef286f0bfde53ebfb74a727c607b05a7fdce623a678794d088166b9b9afdf", 247 | "https://deno.land/std@0.208.0/semver/eq.ts": "6ddb84ce8c95f18e9b7a46d8a63b1e6ca5f0c0f651f1f46f20db6543b390c3f3", 248 | "https://deno.land/std@0.208.0/semver/format.ts": "236cc8b5d2e8031258dcff3ca89e14ba926434d5b789730e2c781db172e76bd9", 249 | "https://deno.land/std@0.208.0/semver/gt.ts": "8529cf2ae1bca95c22801cf38f93620dc802c5dcbc02f863437571b970de3705", 250 | "https://deno.land/std@0.208.0/semver/gte.ts": "b54f7855ac37ff076d6df9a294e944356754171f94f5cb974af782480a9f1fd0", 251 | "https://deno.land/std@0.208.0/semver/gtr.ts": "d2ec1f02ce6a566b7df76a188af7315d802c6069892d460d631a3b0d9e2b1a45", 252 | "https://deno.land/std@0.208.0/semver/increment.ts": "a6e5ac018887244731a4b936743ae14476cc432ac874f1c9848711b4000c5991", 253 | "https://deno.land/std@0.208.0/semver/is_semver.ts": "666f4e1d8e41994150d4326d515046bc5fc72e59cbbd6e756a0b60548dcd00b5", 254 | "https://deno.land/std@0.208.0/semver/is_semver_comparator.ts": "035aa894415ad1c8f50a6b6f52ea49c62d6f3af62b5d6fca9c1f4cb84f1896fd", 255 | "https://deno.land/std@0.208.0/semver/is_semver_range.ts": "6f9b4f1c937a202750cae9444900d8abe4a68cc3bf5bb90f0d49c08cf85308cb", 256 | "https://deno.land/std@0.208.0/semver/lt.ts": "081614b5adbc5bc944649e09af946a90a4b4bdb3d65a67c005183994504f04c2", 257 | "https://deno.land/std@0.208.0/semver/lte.ts": "f8605c17d620bfb3aa57775643e3c560c04f7c20f2e431f64ca5b2ea39e36217", 258 | "https://deno.land/std@0.208.0/semver/ltr.ts": "975e672b5ca8aa67336660653f8c76e1db829c628fb08ea3e815a9a12fa7eb9c", 259 | "https://deno.land/std@0.208.0/semver/max_satisfying.ts": "75406901818cd1127a6332e007e96285474e833d0e40dbbfddc01b08ee6e51f2", 260 | "https://deno.land/std@0.208.0/semver/min_satisfying.ts": "58bd48033a00e63bea0709f78c33c66ea58bce2dbebda0d54d3fdc6db7d0d298", 261 | "https://deno.land/std@0.208.0/semver/mod.ts": "442702e8a57cbf02e68868c46ffe66ecf6efbde58d72cfdfbdaa51ad0c4af513", 262 | "https://deno.land/std@0.208.0/semver/neq.ts": "e91b699681c3b406fc3d661d4eac7aa36cd1cc8bf188f8e3c7b53cc340775b87", 263 | "https://deno.land/std@0.208.0/semver/outside.ts": "1d225fdb42172d946c382e144ce97c402812741741bbe299561aa164cc956ec4", 264 | "https://deno.land/std@0.208.0/semver/parse.ts": "5d24ec0c5f681db1742c31332f6007395c84696c88ff4b58287485ed3f6d8c84", 265 | "https://deno.land/std@0.208.0/semver/parse_comparator.ts": "f07f9be8322b1f61a36b94c3c65a0dc4124958ee54cf744c92ca4028bf156d5e", 266 | "https://deno.land/std@0.208.0/semver/parse_range.ts": "39a18608a8026004b218ef383e7ae624a9e663b82327948c1810f16d875113c2", 267 | "https://deno.land/std@0.208.0/semver/range_format.ts": "3de31fd0b74dd565e052840e73a8e9ee1d9d289ca60b85749167710b978cc078", 268 | "https://deno.land/std@0.208.0/semver/range_intersects.ts": "8672e603df1bb68a02452b634021c4913395f4d16d75c21b578d6f4175a2b2c1", 269 | "https://deno.land/std@0.208.0/semver/range_max.ts": "9c10c65bbc7796347ce6f765a77865cead88870d17481ac78259400a2378af2e", 270 | "https://deno.land/std@0.208.0/semver/range_min.ts": "b7849e70e0b0677b382eddaa822b6690521449a659c5b8ec84cbd438f6e6ca59", 271 | "https://deno.land/std@0.208.0/semver/rcompare.ts": "b8b9f5108d40c64cf50ffe455199aba7ad64995829a17110301ae3f8290374ee", 272 | "https://deno.land/std@0.208.0/semver/rsort.ts": "a9139a1fc37570f9d8b6517032d152cf69143cec89d4342f19174e48f06d8543", 273 | "https://deno.land/std@0.208.0/semver/sort.ts": "c058a5b2c8e866fa8e6ef25c9d228133357caf4c140f129bfc368334fcd0813b", 274 | "https://deno.land/std@0.208.0/semver/test_comparator.ts": "eff5394cb82d133ed18f96fe547de7e7264bf0d25d16cbc6126664aa06ef8f37", 275 | "https://deno.land/std@0.208.0/semver/test_range.ts": "b236c276268e92bbbc65e7c4b4b6b685ea6b4534a71b2525b53093d094f631c6", 276 | "https://deno.land/std@0.208.0/semver/types.ts": "d44f442c2f27dd89bd6695b369e310b80549746f03c38f241fe28a83b33dd429", 277 | "https://deno.land/std@0.208.0/testing/snapshot.ts": "d53cc4ad3250e3a826df9a1a90bc19c9a92c8faa8fd508d16b5e6ce8699310ca", 278 | "https://deno.land/x/code_block_writer@12.0.0/mod.ts": "2c3448060e47c9d08604c8f40dee34343f553f33edcdfebbf648442be33205e5", 279 | "https://deno.land/x/code_block_writer@12.0.0/utils/string_utils.ts": "60cb4ec8bd335bf241ef785ccec51e809d576ff8e8d29da43d2273b69ce2a6ff", 280 | "https://deno.land/x/deno_cache@0.4.1/auth_tokens.ts": "5fee7e9155e78cedf3f6ff3efacffdb76ac1a76c86978658d9066d4fb0f7326e", 281 | "https://deno.land/x/deno_cache@0.4.1/cache.ts": "51f72f4299411193d780faac8c09d4e8cbee951f541121ef75fcc0e94e64c195", 282 | "https://deno.land/x/deno_cache@0.4.1/deno_dir.ts": "f2a9044ce8c7fe1109004cda6be96bf98b08f478ce77e7a07f866eff1bdd933f", 283 | "https://deno.land/x/deno_cache@0.4.1/deps.ts": "8974097d6c17e65d9a82d39377ae8af7d94d74c25c0cbb5855d2920e063f2343", 284 | "https://deno.land/x/deno_cache@0.4.1/dirs.ts": "d2fa473ef490a74f2dcb5abb4b9ab92a48d2b5b6320875df2dee64851fa64aa9", 285 | "https://deno.land/x/deno_cache@0.4.1/disk_cache.ts": "1f3f5232cba4c56412d93bdb324c624e95d5dd179d0578d2121e3ccdf55539f9", 286 | "https://deno.land/x/deno_cache@0.4.1/file_fetcher.ts": "07a6c5f8fd94bf50a116278cc6012b4921c70d2251d98ce1c9f3c352135c39f7", 287 | "https://deno.land/x/deno_cache@0.4.1/http_cache.ts": "f632e0d6ec4a5d61ae3987737a72caf5fcdb93670d21032ddb78df41131360cd", 288 | "https://deno.land/x/deno_cache@0.4.1/mod.ts": "ef1cda9235a93b89cb175fe648372fc0f785add2a43aa29126567a05e3e36195", 289 | "https://deno.land/x/deno_cache@0.4.1/util.ts": "8cb686526f4be5205b92c819ca2ce82220aa0a8dd3613ef0913f6dc269dbbcfe", 290 | "https://deno.land/x/denoflate@1.2.1/mod.ts": "f5628e44b80b3d80ed525afa2ba0f12408e3849db817d47a883b801f9ce69dd6", 291 | "https://deno.land/x/denoflate@1.2.1/pkg/denoflate.js": "b9f9ad9457d3f12f28b1fb35c555f57443427f74decb403113d67364e4f2caf4", 292 | "https://deno.land/x/denoflate@1.2.1/pkg/denoflate_bg.wasm.js": "d581956245407a2115a3d7e8d85a9641c032940a8e810acbd59ca86afd34d44d", 293 | "https://deno.land/x/esbuild@v0.19.4/mod.js": "6277018cfbcad3912fd346409e0b2a9807cf10c9555a15e4aac299b3194fa4fb", 294 | "https://deno.land/x/esbuild@v0.19.4/wasm.js": "14e8be187eaed201e71dc04f20884403566d57150ca9723bb914651820a1f1c0", 295 | "https://deno.land/x/esbuild_deno_loader@0.8.2/deps.ts": "c1aa4747e43d3ae09da96e54aac798ed9bb967634cff72f21b7fab6e5435c293", 296 | "https://deno.land/x/esbuild_deno_loader@0.8.2/mod.ts": "28524460bef46d487221b01ade6ed913d2e127de7eeee025ab75b34b491283da", 297 | "https://deno.land/x/esbuild_deno_loader@0.8.2/src/deno.ts": "b0af3e430c068f18c6fa48c2083a1b4354b6c303e16fb37855e02fcafb95f36d", 298 | "https://deno.land/x/esbuild_deno_loader@0.8.2/src/loader_native.ts": "3ffab59d0ed26c9329b2b84e0a775be5a910b7fed403a46edf4d2c3c8feb8b5a", 299 | "https://deno.land/x/esbuild_deno_loader@0.8.2/src/loader_portable.ts": "d999f452ef3d8ec2dd3c8443f542adf57efc8a2cd59b29cc41f5b3d7dff512e5", 300 | "https://deno.land/x/esbuild_deno_loader@0.8.2/src/plugin_deno_loader.ts": "166356133ee63d80e5559a10c18e10b625da96e39a4518b8c7adfef718bb4e32", 301 | "https://deno.land/x/esbuild_deno_loader@0.8.2/src/plugin_deno_resolver.ts": "0449ed23ae93db1ec74d015a46934aefd7ba7a8f719f7a4980b616cb3f5bbee4", 302 | "https://deno.land/x/esbuild_deno_loader@0.8.2/src/shared.ts": "33052684aeb542ebd24da372816bbbf885cd090a7ab0fde7770801f7f5b49572", 303 | "https://deno.land/x/fresh@1.6.1/dev.ts": "720dd3a64b62b852db7b6ae471c246c5c605cf4a3091c4cbc802790f36d43e4c", 304 | "https://deno.land/x/fresh@1.6.1/plugins/twind.ts": "c92e6b839c015248c5a8fd4d7fa484e3b7a2ae9c58d0771cca6a57f83f4aeb28", 305 | "https://deno.land/x/fresh@1.6.1/plugins/twind/shared.ts": "ad8ccde3874b305be13a996e6f1c774bb9f611505f98a0995f5f7be368c5949c", 306 | "https://deno.land/x/fresh@1.6.1/runtime.ts": "49f4f70c24d14c5d5e112a671ef0314e438e5cd83eacb4f75c6db2fbdc22b540", 307 | "https://deno.land/x/fresh@1.6.1/server.ts": "d5817615a3ac822d422627f2cd6f850a31e11f7e73b328a79807f722e6519bac", 308 | "https://deno.land/x/fresh@1.6.1/src/build/aot_snapshot.ts": "4ac6330e5325dd9411fa2a46e97bb289f910fde4be82dc349d3e2b4bb1a7c07d", 309 | "https://deno.land/x/fresh@1.6.1/src/build/deps.ts": "b64aca721fb0756339e420e705432348fcaeb73d1bcce2694398279b1704e3df", 310 | "https://deno.land/x/fresh@1.6.1/src/build/esbuild.ts": "a668f5078c504577a905d01a88e68ffa3b16b385180b0d03d0bae59e0e89baf3", 311 | "https://deno.land/x/fresh@1.6.1/src/build/mod.ts": "b9d1695a86746ac3a1c52f0e07e723faa2310d1dfd109b9a2eebab6727c4702b", 312 | "https://deno.land/x/fresh@1.6.1/src/constants.ts": "4795d194b6c6b95f0e876c0a997fbaf57f94cfe253442c5819f95410870b79b3", 313 | "https://deno.land/x/fresh@1.6.1/src/dev/build.ts": "9aaf84a781ee4d11d73ec549425f273fe8339812fdd8f726e1ec1ba61bdf0e9d", 314 | "https://deno.land/x/fresh@1.6.1/src/dev/deps.ts": "9cf7cf1cb0759812f9106ab0eefbdff628aa1eea1dd3a9b6c91fd2a54d2b97e8", 315 | "https://deno.land/x/fresh@1.6.1/src/dev/dev_command.ts": "3e3dcc80180faf8868d44d892ddfa8c5ad06033e4d94c0934302e157db1de63d", 316 | "https://deno.land/x/fresh@1.6.1/src/dev/error.ts": "21a38d240c00279662e6adde41367f1da0ae7e2836d993f818ea94aabab53e7b", 317 | "https://deno.land/x/fresh@1.6.1/src/dev/manifest.ts": "156fb0ce3f77b9fdac18f8798eee36283c2fb440795c6024b6b6ab938e91f9cb", 318 | "https://deno.land/x/fresh@1.6.1/src/dev/mod.ts": "47489f35a9e462c7b91bac6c9102a619ce6fd2300098bf8ce3f8b77599aa8dea", 319 | "https://deno.land/x/fresh@1.6.1/src/dev/update_check.ts": "7dcf0066a8a5879c46f970113a5baa5356fb8deaaeadfc8827119a8be7bdb563", 320 | "https://deno.land/x/fresh@1.6.1/src/runtime/Partial.tsx": "92e16fa7edf37dc8e254024a5410ea2c8986804a6ddf911af4d30209dff80a22", 321 | "https://deno.land/x/fresh@1.6.1/src/runtime/active_url.ts": "c718797b11189c7e2c86569355d55056148907121e958e00f71c56593aecc329", 322 | "https://deno.land/x/fresh@1.6.1/src/runtime/build_id.ts": "8376e70e42ce456dfa6932c638409d2ef1bca4833b4ceba0bf74510080a7f976", 323 | "https://deno.land/x/fresh@1.6.1/src/runtime/csp.ts": "9ee900e9b0b786057b1009da5976298c202d1b86d1f1e4d2510bde5f06530ac9", 324 | "https://deno.land/x/fresh@1.6.1/src/runtime/deserializer.ts": "8f11e04f9671741442b9512cc0617bef3edf22a60620c78b05097143a83cfe6e", 325 | "https://deno.land/x/fresh@1.6.1/src/runtime/head.ts": "0f9932874497ab6e57ed1ba01d549e843523df4a5d36ef97460e7a43e3132fdc", 326 | "https://deno.land/x/fresh@1.6.1/src/runtime/utils.ts": "4f40630c308e8ea7d53860687905caf1a2f2a46ad8692f24e905a8e996b584c3", 327 | "https://deno.land/x/fresh@1.6.1/src/server/boot.ts": "af488946995049dcfc148ae0372252c6c871e0e9fbeea1a1149f92ce28031ede", 328 | "https://deno.land/x/fresh@1.6.1/src/server/build_id.ts": "3e88d03f9ab99282b36a2ef14be871d7fb453301b7c340217475b1905ec90465", 329 | "https://deno.land/x/fresh@1.6.1/src/server/code_frame.ts": "fac505f138fbd1bb260030122b87aeb2f5b5e54018e3066e105c669c686cc373", 330 | "https://deno.land/x/fresh@1.6.1/src/server/compose.ts": "895c28eddc618750768b26d703660ef9646ec0e3436ce0cd4bd1619446316b4d", 331 | "https://deno.land/x/fresh@1.6.1/src/server/config.ts": "925d14a41c81db7543b3ef632c7b3c369fbfbe5abbfdad924c25ccd4c33fe873", 332 | "https://deno.land/x/fresh@1.6.1/src/server/constants.ts": "e75a7f7b14185b6f85747613591348313200fe8e218cb473b1da9db941ee68d1", 333 | "https://deno.land/x/fresh@1.6.1/src/server/context.ts": "cfc4770f053bb41d12927cb84a4bbbf1054331ba71bd46369ae9ff13dd8faafc", 334 | "https://deno.land/x/fresh@1.6.1/src/server/default_error_page.tsx": "094ad8d52d31f99172a606d0a0d8236604a1f9bb6d1f928d0d466d55b36dae70", 335 | "https://deno.land/x/fresh@1.6.1/src/server/defines.ts": "f518ff10e499d4543bb9231f55026f26be2507eaccb072aafab93c8cc0bc3adc", 336 | "https://deno.land/x/fresh@1.6.1/src/server/deps.ts": "e500413cd9390f07603672baba0f2ef147934f7df29aead57e50795c56da2ed5", 337 | "https://deno.land/x/fresh@1.6.1/src/server/error_overlay.tsx": "e6ab4cef0ea812a1e1f32ee9116c61f64db8466d46e228acbb953215f4517d9c", 338 | "https://deno.land/x/fresh@1.6.1/src/server/fs_extract.ts": "10796d727dfad6c3e8789aea53db3c715fc4674f1ece8af2a8683c1f68a13e01", 339 | "https://deno.land/x/fresh@1.6.1/src/server/htmlescape.ts": "834ac7d0caa9fc38dffd9b8613fb47aeecd4f22d5d70c51d4b20a310c085835c", 340 | "https://deno.land/x/fresh@1.6.1/src/server/init_safe_deps.ts": "8c74d8708986d156126355b0935a1915069bfdc389ccabd3d2d72d1c9e04025c", 341 | "https://deno.land/x/fresh@1.6.1/src/server/mod.ts": "6cee56e234f6bc19f62f3b6c0d287dc7b9632fcbfb8f56dde1d81423532d65c4", 342 | "https://deno.land/x/fresh@1.6.1/src/server/render.ts": "eda7bb24440f91227ad4f4a6ea069ac83d7e262a982f38a89d8d5096424a3c64", 343 | "https://deno.land/x/fresh@1.6.1/src/server/rendering/fresh_tags.tsx": "0ce6076800b26e18ef83489d265dab7411b01db817e7e1662eabff89feee7525", 344 | "https://deno.land/x/fresh@1.6.1/src/server/rendering/preact_hooks.ts": "5c2904cfda3acdba0f18e8095428bb35546a20a2e5bf88a5adc53f04e7453b0d", 345 | "https://deno.land/x/fresh@1.6.1/src/server/rendering/state.ts": "d5839eb31bf3d6d1fb956ac542814c3c6793d4dae1dd5c464cfe609a85306924", 346 | "https://deno.land/x/fresh@1.6.1/src/server/rendering/template.tsx": "858ca33f239e3f26a932c4b0fd4d967df32d9f69dcbc5d6a5cecfe6cb7f195d1", 347 | "https://deno.land/x/fresh@1.6.1/src/server/router.ts": "257a293776ee682937b8abb6d803971a6863a2f161b1e079b57c013589d0ed0b", 348 | "https://deno.land/x/fresh@1.6.1/src/server/serializer.ts": "f0cffb863bbdbac6ed53fefe181e415d6aefc2101f2dc92a562b364088809e44", 349 | "https://deno.land/x/fresh@1.6.1/src/server/types.ts": "df1fc86702a847f509ebf17cf134fc9b7440a417ea59e9124a39ec5aa22255b6", 350 | "https://deno.land/x/fresh@1.6.1/src/types.ts": "05169e3389979d8283de0ec1db3a765324ffd730b6af29ffe02752f341ae7d35", 351 | "https://deno.land/x/fresh@1.6.1/versions.json": "dd1b4045501f911d5da07b9b2176a07109838d16413f25d10da4991212e0a503", 352 | "https://deno.land/x/importmap@0.2.1/_util.ts": "ada9a9618b537e6c0316c048a898352396c882b9f2de38aba18fd3f2950ede89", 353 | "https://deno.land/x/importmap@0.2.1/mod.ts": "ae3d1cd7eabd18c01a4960d57db471126b020f23b37ef14e1359bbb949227ade", 354 | "https://deno.land/x/ts_morph@20.0.0/common/DenoRuntime.ts": "6a7180f0c6e90dcf23ccffc86aa8271c20b1c4f34c570588d08a45880b7e172d", 355 | "https://deno.land/x/ts_morph@20.0.0/common/mod.ts": "01985d2ee7da8d1caee318a9d07664774fbee4e31602bc2bb6bb62c3489555ed", 356 | "https://deno.land/x/ts_morph@20.0.0/common/ts_morph_common.js": "2325f94f61dc5f3f98a1dab366dc93048d11b1433d718b10cfc6ee5a1cfebe8f", 357 | "https://deno.land/x/ts_morph@20.0.0/common/typescript.js": "b9edf0a451685d13e0467a7ed4351d112b74bd1e256b915a2b941054e31c1736", 358 | "https://deno.land/x/ts_morph@20.0.0/mod.ts": "adba9b82f24865d15d2c78ef6074b9a7457011719056c9928c800f130a617c93", 359 | "https://deno.land/x/ts_morph@20.0.0/ts_morph.js": "ea8c6d40a5a30ea2d720ef289b7cc817d3be3d0010587c197ea4419026943e0e", 360 | "https://esm.sh/*preact-render-to-string@6.3.1": "07807f027acf54b994b630bbb2a923f5a835f9544e01144f67ab292e90a431e4", 361 | "https://esm.sh/@babel/helper-validator-identifier@7.22.20": "daace34e028130297fddf97f3ef6deb4b05ec3eb46f5c5cacd6eaa43d6323b0a", 362 | "https://esm.sh/axios@1.3.2?target=es2022": "98b462d0db2b32732443838ac0da9222b40815132c8b71a0b73231ebb3dfa869", 363 | "https://esm.sh/preact@10.19.2": "41f31ba8eecf666f08289f2205f57c45f74baba5be815a55c15c4cc61086143c", 364 | "https://esm.sh/preact@10.19.2/debug": "e1434406abe1f663b8992a77100a3491142ef22032405ea96a4a8ee5f58795d1", 365 | "https://esm.sh/preact@10.19.2/hooks": "725034ea48c9ad8aa8d9919bc3c1afaf469cee10fb815ac372d318043a5688d6", 366 | "https://esm.sh/preact@10.19.2/jsx-runtime": "2a4111d9aa667a3e3776ffd9082d00d63f6960c038d01620d79f80645ecc049d", 367 | "https://esm.sh/stable/preact@10.19.2/denonext/debug.js": "e6deb8ee849f8de609ec41a4afd54ccb103d550f43baefb52d72d0ba35650239", 368 | "https://esm.sh/stable/preact@10.19.2/denonext/devtools.js": "cc15902874791f4bb4714f7444e6ae25cb98a5fbb938926fe19d7f2d72a2e60b", 369 | "https://esm.sh/stable/preact@10.19.2/denonext/hooks.js": "dfd710408bb1b988c7a33a33ce03b1d8076dd1d8140e0879ec78452a5f670726", 370 | "https://esm.sh/stable/preact@10.19.2/denonext/jsx-runtime.js": "f196c14042fc6019f3fed31eec7cfedea4669d0926858939380a5f54bd503798", 371 | "https://esm.sh/stable/preact@10.19.2/denonext/preact.mjs": "dc999b6432dc04d74ad7b692a8801f346294d815266dff915d0f222c120fd0b0", 372 | "https://esm.sh/twind@0.16.19": "3a538bbdab88576f75c392f47ba79c8ad5940b187fa473fa45e3fcfe60c16ee9", 373 | "https://esm.sh/twind@0.16.19/sheets": "c30df4c16990f26c52401656f9694d0c14f5df29a274bafd15257d291bc9504f", 374 | "https://esm.sh/v128/style-vendorizer@2.2.3/denonext/style-vendorizer.mjs": "121455e7b04b631ef6463ce63cdcd29febd74d88c37713c774ceca8a1561c83d", 375 | "https://esm.sh/v128/twind@0.16.19/denonext/sheets.js": "efd516ad31769dc75c995bfb984ab03d23c0e0a90240c83a5496ef150cfd4757", 376 | "https://esm.sh/v128/twind@0.16.19/denonext/twind.mjs": "aa796520471d0b829cdde8176ef2ec50b12193b89cd66ab006f0f882eaac59ae", 377 | "https://esm.sh/v135/@babel/helper-validator-identifier@7.22.20/denonext/helper-validator-identifier.mjs": "1ad312a9040d1f3b096e90a3e6a9da7ecfc99662140852fe3862a316c2591c93", 378 | "https://esm.sh/v135/axios@1.3.2/es2022/axios.mjs": "1fd171978adc5788f0c9926b9743d221049a8b200fe17d637d144a21e6110a7c", 379 | "https://esm.sh/v135/base64-js@1.5.1/es2022/base64-js.mjs": "56594379eed23d8e1b5a5312cd48e179ec97ec7a5b55e24c75c58decca1f49e3", 380 | "https://esm.sh/v135/buffer@6.0.3/es2022/buffer.mjs": "8035f954f4483b847e34b46c0947a55b2af4db29d91718bf766212b3b2fabd7f", 381 | "https://esm.sh/v135/ieee754@1.2.1/es2022/ieee754.mjs": "6e9f43f2599ed8bbcc9cdb19bf9d1b8caea9882fe4717c97edc397d363a5d1c7", 382 | "https://esm.sh/v135/preact-render-to-string@6.3.1/X-ZS8q/denonext/preact-render-to-string.mjs": "bcaceb8c3938310aee3dd4f7b6f2136cf0b2b890988c2e6679485e052e76e920", 383 | "https://esm.sh/v135/zod@3.21.4/denonext/zod.mjs": "3e104633fb5d127189f1a38f52f5620a21ec8988d639b5adcf5a65be1cbbcc62", 384 | "https://esm.sh/zod@3.21.4": "dc4f42ed520b2e45b3463eaf7952c26b20cb315921c826c67eb55d9ec1898a08" 385 | } 386 | } 387 | -------------------------------------------------------------------------------- /dev.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env -S deno run -A --watch=static/,routes/ 2 | 3 | import dev from "$fresh/dev.ts"; 4 | 5 | await dev(import.meta.url, "./main.ts"); 6 | -------------------------------------------------------------------------------- /fresh.gen.ts: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This file is generated by Fresh. 2 | // This file SHOULD be checked into source version control. 3 | // This file is automatically updated during development when running `dev.ts`. 4 | 5 | import * as $_listId_ from "./routes/[listId].tsx"; 6 | import * as $_app from "./routes/_app.tsx"; 7 | import * as $index from "./routes/index.tsx"; 8 | import * as $TodoListView from "./islands/TodoListView.tsx"; 9 | import { type Manifest } from "$fresh/server.ts"; 10 | 11 | const manifest = { 12 | routes: { 13 | "./routes/[listId].tsx": $_listId_, 14 | "./routes/_app.tsx": $_app, 15 | "./routes/index.tsx": $index, 16 | }, 17 | islands: { 18 | "./islands/TodoListView.tsx": $TodoListView, 19 | }, 20 | baseUrl: import.meta.url, 21 | } satisfies Manifest; 22 | 23 | export default manifest; 24 | -------------------------------------------------------------------------------- /islands/TodoListView.tsx: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useRef, useState } from "preact/hooks"; 2 | import type { TodoList, TodoListItem } from "../shared/api.ts"; 3 | import axios from "axios-web"; 4 | 5 | interface LocalMutation { 6 | text: string | null; 7 | completed: boolean; 8 | } 9 | 10 | export default function TodoListView( 11 | props: { initialData: TodoList; latency: number }, 12 | ) { 13 | const [data, setData] = useState(props.initialData); 14 | const [dirty, setDirty] = useState(false); 15 | const localMutations = useRef(new Map()); 16 | const [hasLocalMutations, setHasLocalMutations] = useState(false); 17 | const busy = hasLocalMutations || dirty; 18 | const [adding, setAdding] = useState(false); 19 | 20 | useEffect(() => { 21 | let es = new EventSource(window.location.href); 22 | 23 | es.addEventListener("message", (e) => { 24 | const newData: TodoList = JSON.parse(e.data); 25 | setData(newData); 26 | setDirty(false); 27 | setAdding(false); 28 | }); 29 | 30 | es.addEventListener("error", async () => { 31 | es.close(); 32 | const backoff = 10000 + Math.random() * 5000; 33 | await new Promise((resolve) => setTimeout(resolve, backoff)); 34 | es = new EventSource(window.location.href); 35 | }); 36 | }, []); 37 | 38 | useEffect(() => { 39 | (async () => { 40 | while (1) { 41 | const mutations = Array.from(localMutations.current); 42 | localMutations.current = new Map(); 43 | setHasLocalMutations(false); 44 | 45 | if (mutations.length) { 46 | setDirty(true); 47 | const chunkSize = 10; 48 | for (let i = 0; i < mutations.length; i += chunkSize) { 49 | const chunk = mutations.slice(i, i + chunkSize).map(( 50 | [id, mut], 51 | ) => ({ 52 | id, 53 | text: mut.text, 54 | completed: mut.completed, 55 | })); 56 | while (true) { 57 | try { 58 | await axios.post(window.location.href, chunk); 59 | break; 60 | } catch { 61 | await new Promise((resolve) => setTimeout(resolve, 1000)); 62 | } 63 | } 64 | } 65 | } 66 | 67 | await new Promise((resolve) => 68 | setTimeout( 69 | () => requestAnimationFrame(resolve), // pause when the page is hidden 70 | 1000, 71 | ) 72 | ); 73 | } 74 | })(); 75 | }, []); 76 | 77 | const addTodoInput = useRef(null); 78 | const addTodo = useCallback(() => { 79 | const value = addTodoInput.current!.value; 80 | if (!value) return; 81 | addTodoInput.current!.value = ""; 82 | 83 | const id = generateItemId(); 84 | localMutations.current.set(id, { 85 | text: value, 86 | completed: false, 87 | }); 88 | setHasLocalMutations(true); 89 | setAdding(true); 90 | }, []); 91 | 92 | const saveTodo = useCallback( 93 | (item: TodoListItem, text: string | null, completed: boolean) => { 94 | localMutations.current.set(item.id!, { 95 | text, 96 | completed, 97 | }); 98 | setHasLocalMutations(true); 99 | }, 100 | [], 101 | ); 102 | 103 | return ( 104 |
105 |
106 |
107 |
108 |

Todo List

109 |
115 |
116 |
117 |
118 |

119 | Share this page to collaborate with others. 120 |

121 |
122 |
123 | 128 | 135 |
136 |
137 |
138 | {data.items.map((item) => ( 139 | 144 | ))} 145 |
146 |
147 |

148 | Initial data fetched in {props.latency}ms 149 |

150 |

151 | 155 | Source code 156 | 157 |

158 |
159 |
160 |
161 | ); 162 | } 163 | 164 | function TodoItem( 165 | { item, save }: { 166 | item: TodoListItem; 167 | save: (item: TodoListItem, text: string | null, completed: boolean) => void; 168 | }, 169 | ) { 170 | const input = useRef(null); 171 | const [editing, setEditing] = useState(false); 172 | const [busy, setBusy] = useState(false); 173 | const doSave = useCallback(() => { 174 | if (!input.current) return; 175 | setBusy(true); 176 | save(item, input.current.value, item.completed); 177 | }, [item]); 178 | const cancelEdit = useCallback(() => { 179 | if (!input.current) return; 180 | setEditing(false); 181 | input.current.value = item.text; 182 | }, []); 183 | const doDelete = useCallback(() => { 184 | const yes = confirm("Are you sure you want to delete this item?"); 185 | if (!yes) return; 186 | setBusy(true); 187 | save(item, null, item.completed); 188 | }, [item]); 189 | const doSaveCompleted = useCallback((completed: boolean) => { 190 | setBusy(true); 191 | save(item, item.text, completed); 192 | }, [item]); 193 | 194 | return ( 195 |
199 | {editing && ( 200 | <> 201 | 206 | 214 | 222 | 223 | )} 224 | {!editing && ( 225 | <> 226 | doSaveCompleted(e.currentTarget.checked)} 231 | class="mr-2" 232 | /> 233 |
234 |

235 | {item.text} 236 |

237 |

238 | {new Date(item.createdAt).toISOString()} 239 |

240 |
241 | 249 | 257 | 258 | )} 259 |
260 | ); 261 | } 262 | 263 | function generateItemId(): string { 264 | return `${Date.now()}-${crypto.randomUUID()}`; 265 | } 266 | -------------------------------------------------------------------------------- /main.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | /// 7 | 8 | import { start } from "$fresh/server.ts"; 9 | import manifest from "./fresh.gen.ts"; 10 | 11 | import twindPlugin from "$fresh/plugins/twind.ts"; 12 | import twindConfig from "./twind.config.ts"; 13 | 14 | await start(manifest, { plugins: [twindPlugin(twindConfig)] }); 15 | -------------------------------------------------------------------------------- /routes/[listId].tsx: -------------------------------------------------------------------------------- 1 | import { Head } from "$fresh/runtime.ts"; 2 | import { Handlers } from "$fresh/server.ts"; 3 | import TodoListView from "../islands/TodoListView.tsx"; 4 | import { db, inputSchema, loadList, writeItems } from "../services/database.ts"; 5 | import { TodoList } from "../shared/api.ts"; 6 | 7 | export const handler: Handlers = { 8 | GET: async (req, ctx) => { 9 | const listId = ctx.params.listId; 10 | const accept = req.headers.get("accept"); 11 | const url = new URL(req.url); 12 | 13 | if (accept === "text/event-stream") { 14 | const stream = db.watch([["list_updated", listId]]).getReader(); 15 | const body = new ReadableStream({ 16 | async start(controller) { 17 | console.log( 18 | `Opened stream for list ${listId} remote ${ 19 | JSON.stringify(ctx.remoteAddr) 20 | }`, 21 | ); 22 | while (true) { 23 | try { 24 | if ((await stream.read()).done) { 25 | return; 26 | } 27 | 28 | const data = await loadList(listId, "strong"); 29 | const chunk = `data: ${JSON.stringify(data)}\n\n`; 30 | controller.enqueue(new TextEncoder().encode(chunk)); 31 | } catch (e) { 32 | console.error(`Error refreshing list ${listId}`, e); 33 | } 34 | } 35 | }, 36 | cancel() { 37 | stream.cancel(); 38 | console.log( 39 | `Closed stream for list ${listId} remote ${ 40 | JSON.stringify(ctx.remoteAddr) 41 | }`, 42 | ); 43 | }, 44 | }); 45 | return new Response(body, { 46 | headers: { 47 | "content-type": "text/event-stream", 48 | }, 49 | }); 50 | } 51 | 52 | const startTime = Date.now(); 53 | const data = await loadList( 54 | listId, 55 | url.searchParams.get("consistency") === "strong" ? "strong" : "eventual", 56 | ); 57 | const endTime = Date.now(); 58 | const res = await ctx.render({ data, latency: endTime - startTime }); 59 | res.headers.set("x-list-load-time", "" + (endTime - startTime)); 60 | return res; 61 | }, 62 | POST: async (req, ctx) => { 63 | const listId = ctx.params.listId; 64 | const body = inputSchema.parse(await req.json()); 65 | await writeItems(listId, body); 66 | return Response.json({ ok: true }); 67 | }, 68 | }; 69 | 70 | export default function Home( 71 | { data: { data, latency } }: { data: { data: TodoList; latency: number } }, 72 | ) { 73 | return ( 74 | <> 75 | 76 | Todo List 77 | 78 |
79 | 80 |
81 | 82 | ); 83 | } 84 | -------------------------------------------------------------------------------- /routes/_app.tsx: -------------------------------------------------------------------------------- 1 | import { PageProps } from "$fresh/server.ts"; 2 | 3 | export default function App({ Component }: PageProps) { 4 | return ( 5 | 6 | 7 | 8 | 9 | showcase_todo 10 | 11 | 12 | 13 | 14 | 15 | ); 16 | } -------------------------------------------------------------------------------- /routes/index.tsx: -------------------------------------------------------------------------------- 1 | import { HandlerContext } from "$fresh/server.ts"; 2 | import * as base58 from "$std/encoding/base58.ts"; 3 | 4 | export const handler = (req: Request, _ctx: HandlerContext): Response => { 5 | const listId = base58.encode(crypto.getRandomValues(new Uint8Array(8))); 6 | const url = new URL(req.url); 7 | return Response.redirect(`${url.origin}/${listId}`, 302); 8 | }; 9 | -------------------------------------------------------------------------------- /services/database.ts: -------------------------------------------------------------------------------- 1 | import { TodoList, TodoListItem } from "../shared/api.ts"; 2 | import { z } from "zod"; 3 | 4 | export const db = await Deno.openKv(); 5 | export const inputSchema = z.array(z.object({ 6 | id: z.string(), 7 | text: z.string().nullable(), 8 | completed: z.boolean(), 9 | })); 10 | export type InputSchema = z.infer; 11 | 12 | export async function loadList( 13 | id: string, 14 | consistency: "strong" | "eventual", 15 | ): Promise { 16 | const out: TodoList = { 17 | items: [], 18 | }; 19 | 20 | const it = db.list({ prefix: ["list", id] }, { 21 | reverse: true, 22 | consistency, 23 | }); 24 | for await (const entry of it) { 25 | const item = entry.value as TodoListItem; 26 | item.id = entry.key[entry.key.length - 1] as string; 27 | item.versionstamp = entry.versionstamp!; 28 | out.items.push(item); 29 | } 30 | 31 | return out; 32 | } 33 | 34 | export async function writeItems( 35 | listId: string, 36 | inputs: InputSchema, 37 | ): Promise { 38 | const currentEntries = await db.getMany( 39 | inputs.map((input) => ["list", listId, input.id]), 40 | ); 41 | 42 | const op = db.atomic(); 43 | 44 | inputs.forEach((input, i) => { 45 | if (input.text === null) { 46 | op.delete(["list", listId, input.id]); 47 | } else { 48 | const current = currentEntries[i].value as TodoListItem | null; 49 | const now = Date.now(); 50 | const createdAt = current?.createdAt ?? now; 51 | 52 | const item: TodoListItem = { 53 | text: input.text, 54 | completed: input.completed, 55 | createdAt, 56 | updatedAt: now, 57 | }; 58 | op.set(["list", listId, input.id], item); 59 | } 60 | }); 61 | op.set(["list_updated", listId], true); 62 | await op.commit(); 63 | } 64 | -------------------------------------------------------------------------------- /shared/api.ts: -------------------------------------------------------------------------------- 1 | export interface TodoList { 2 | items: TodoListItem[]; 3 | } 4 | 5 | export interface TodoListItem { 6 | // Non-empty in API request and response 7 | id?: string; 8 | 9 | // Non-empty in API response 10 | versionstamp?: string; 11 | 12 | text: string; 13 | completed: boolean; 14 | createdAt: number; 15 | updatedAt: number; 16 | } 17 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/denoland/showcase_todo/d7633183965f06e25c61bb625b8db773986391ea/static/favicon.ico -------------------------------------------------------------------------------- /static/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /static/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/denoland/showcase_todo/d7633183965f06e25c61bb625b8db773986391ea/static/screenshot.png -------------------------------------------------------------------------------- /twind.config.ts: -------------------------------------------------------------------------------- 1 | import { Options } from "$fresh/plugins/twind.ts"; 2 | 3 | export default { 4 | selfURL: import.meta.url, 5 | } as Options; 6 | --------------------------------------------------------------------------------